PrevNext
Rare
 0/8

(Optional) Longest Increasing Subsequence

Authors: Michael Cao, Benjamin Qi, Andi Qu, Andrew Wang

Finding and using the LIS of an array

Resources
cp-algoA comprehensive guide (covers almost everything here)

Focus Problem – read through this problem before continuing!

Tutorial

In this tutorial, let AA be the array we want to find the LIS for.

O(N2)O(N^2)

Resources
CPHslow solution

Let dp[i]dp[i] be the length of the longest increasing subsequence that ends on A[i]A[i]. We can then naively compute dpdp (and thus the LIS) in O(N2)O(N^2) time:

C++

int find_lis(vector<int> a) {
int n = a.size(), lis = 0;
vector<int> dp(n, 1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++)
if (a[j] < a[i])
dp[i] = max(dp[i], dp[j] + 1);
lis = max(lis, dp[i]);
}
return lis;

Java

public static int find_lis(int[] a) {
int n = a.length, lis = 0;
int[] dp = new int[n]; Arrays.fill(dp, 1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++)
if (a[j] < a[i])
dp[i] = Math.max(dp[i], dp[j] + 1);
lis = Math.max(lis, dp[i]);
}
return lis;

We can do much better than this though!

O(NlogN)O(N \log N)

Let LiL_i be an array where Li[j]L_i[j] is the smallest element from the first ii elements of AA with an increasing sequence of length jj ending on it (or \infty if there is no such element).

Lemma 1: LiL_i forms a non-decreasing sequence.

Proof: Assume for a contradiction that for some jj, we have Li[j]>Li[j+1]L_i[j] > L_i[j + 1]. However, this is impossible because an increasing sequence of length j+1j + 1 ending on some element implies that there is also an increasing sequence of length jj ending on that same sequence.

Lemma 2: The length of the LIS ending on A[i+1]A[i + 1] is equal to the least index jj such that Li[j]A[i+1]L_i[j] \geq A[i + 1].

Proof: Firstly, since A[i+1]>Li[j1]A[i + 1] > L_i[j - 1], there is an increasing sequence of length jj ending on A[i+1]A[i + 1]. By Lemma 1, LiL_i is non-decreasing, so Li[k]A[i+1]L_i[k] \geq A[i + 1] for all kjk \geq j. This means that the length of the LIS is jj.

Lemma 3: Exactly 1 element differs between LiL_i and Li+1L_{i + 1}.

Proof: Obviously, we need to set Li+1[j]L_{i + 1}[j] to be A[i+1]A[i + 1] since Li[j]A[i+1]L_i[j] \geq A[i + 1]. We don't update anything else though, since A[i+1]>Li[k]A[i + 1] > L_i[k] for all k<jk < j and there are no increasing sequences ending on A[i+1]A[i + 1] of length greater than jj.

To find and update the described jj in O(logN)O(\log N) time, we can use a std::vector and std::lower_bound (or just a std::set).

C++

int find_lis(vector<int> a) {
vector<int> dp;
for (int i : a) {
int pos = lower_bound(dp.begin(), dp.end(), i) - dp.begin();
if (pos == dp.size()) dp.push_back(i);
else dp[pos] = i;
}
return dp.size();
}

Java

public static int find_lis(int[] a) {
ArrayList<Integer> dp = new ArrayList<Integer>();
for (int i : a) {
int pos = Collections.binarySearch(dp, i);
if(pos < 0) pos = Math.abs(pos + 1);
if (pos == dp.size()) dp.add(i);
else dp.set(pos, i);
}
return dp.size();
}

Application 1 - Non-intersecting Segments

Focus Problem – read through this problem before continuing!

This problem asks us to find the minimum number of disjoint sets of non-intersecting segments.

This seems quite intimidating, so let's break it up into two parts:

  • Finding a set of non-intersecting segments
  • Minimizing the number of these sets

First, what can we say about two segments (l1,r1)(l_1, r_1) and (l2,r2)(l_2, r_2) if they intersect (assuming l1<l2l_1 < l_2)?

Since these segments are straight, notice how l1<l2    r1>r2l_1 < l_2 \implies r_1 > r_2.

This means that a set of non-intersecting segments satisfies li<lj    ri<rjl_i < l_j \implies r_i < r_j for all pairs (i,j)(i, j)!

Let AA be an array where A[i]=xA[i] = x means that the segment with its right endpoint at position ii has its left endpoint at position xx.

If we were asked to find the maximum size of a set of non-intersecting segments, the answer would be the LIS of AA!

Application 2 - Minimum Number of Increasing Sequences

Continuing from application 1, we now want to find the minimum number of increasing subsequences of AA.

Luckily for us, there's a simple solution to this - the minimum number of increasing subsequences of AA is simply the size of the LDS (longest decreasing subsequence) of AA!

(Try to prove this fact yourself - as a hint, assume the contrary for a contradiction.)

Code for PCB

C++

#include <bits/stdc++.h>
using namespace std;
int lis = 0;
pair<int, int> a[100000];
set<int> s;
int main() {
iostream::sync_with_stdio(false);
cin.tie(0);

Java

import java.io.*;
import java.util.*;
class PCB{
public static int find_lis(int[] a) {
ArrayList<Integer> dp = new ArrayList<Integer>();
for (int i : a) {
int pos = Math.abs(Collections.binarySearch(dp, i));
if (pos > dp.size()) dp.add(i);
else dp.set(pos-1, i);

Application 3 - Number of LISes

Focus Problem – read through this problem before continuing!

This section is not complete.

Feel free to file a request to complete this using the "Contact Us" button.
#include <bits/stdc++.h>
using namespace std;
const int MOD = 30013;
struct Trapezoid {
int x1, x2, y1, y2;
} traps[100001];
int n, top[200001], bottom[200001];

Problems

StatusSourceProblem NameDifficultyTagsSolution
Old GoldEasy
Show Tags

DP

External Sol
LMiOEasy
Show Tags

DP

View Solution
Baltic OINormal
Show Tags

DP, Geometry

Show Sketch
CEOINormal
Show Tags

DP

COCIHard
Show Tags

DP, BIT

View Solution
JOIVery Hard
Show Tags

DP

View Solution
PlatInsane
Show Tags

DP

External Sol

Give Us Feedback on (Optional) Longest Increasing Subsequence!

Module Progress:

PrevNext