PrevNext
Rare
 0/6

(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 be the array we want to find the LIS for.

Resources
CPHslow solution

Let be the length of the longest increasing subsequence that ends on . We can then naively compute (and thus the LIS) in time:

C++

1int find_lis(vector<int> a) {
2 int n = a.size(), lis = 0;
3 vector<int> dp(n, 1);
4 for (int i = 0; i < n; i++) {
5 for (int j = 0; j < i; j++)
6 if (a[j] < a[i])
7 dp[i] = max(dp[i], dp[j] + 1);
8 lis = max(lis, dp[i]);
9 }
10 return lis;

Java

1public static int find_lis(int[] a) {
2 int n = a.length, lis = 0;
3 int[] dp = new int[n]; Arrays.fill(dp, 1);
4 for (int i = 0; i < n; i++) {
5 for (int j = 0; j < i; j++)
6 if (a[j] < a[i])
7 dp[i] = Math.max(dp[i], dp[j] + 1);
8 lis = Math.max(lis, dp[i]);
9 }
10 return lis;

We can do much better than this though!

Let be an array where is the smallest element from the first elements of with an increasing sequence of length ending on it (or if there is no such element).

Lemma 1: forms a non-decreasing sequence.

Proof: Assume for a contradiction that for some , we have . However, this is impossible because an increasing sequence of length ending on some element implies that there is also an increasing sequence of length ending on that same sequence.

Lemma 2: The length of the LIS ending on is equal to the least index such that .

Proof: Firstly, since , there is an increasing sequence of length ending on . By Lemma 1, is non-decreasing, so for all . This means that the length of the LIS is .

Lemma 3: Exactly 1 element differs between and .

Proof: Obviously, we need to set to be since . We don't update anything else though, since for all and there are no increasing sequences ending on of length greater than .

To find and update the described in time, we can use a std::vector and std::lower_bound. Alternatively, we can use a std::set (demonstrated in the solution for PCB).

C++

1int find_lis(vector<int> a) {
2 vector<int> dp;
3 for (int i : a) {
4 int pos = lower_bound(dp.begin(), dp.end(), i) - dp.begin();
5 if (pos == dp.size()) dp.push_back(i);
6 else dp[pos] = i;
7 }
8 return dp.size();
9}

Java

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

Example - PCB

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

Application 1 - Non-intersecting Segments

First, what can we say about two segments and if they intersect (assuming )?

Since these segments are straight, notice how .

This means that a set of non-intersecting segments satisfies for all pairs !

Let be an array where means that the segment with its right endpoint at position has its left endpoint at position .

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

Application 2 - Minimum Number of Increasing Sequences

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

Luckily for us, there's a simple (though not so obvious) solution to this.

Lemma (Easy): The minimum number of increasing subsequences required to cover is at least the size of longest non-increasing subsequence of .

Proof: No two elements of any non-increasing subsequence can be part of the same increasing subsequence.

Claim: The minimum number of increasing subsequences required to cover is equal to the size of longest non-increasing subsequence of !

Wrong Proof 1: See cp-algo (note that this link describes partitioning into non-increasing subsequences rather than increasing subsequences). However, it's not correct because the process of unhooking and reattaching might never terminate. For example, consider partitioning into the non-increasing subsequences and . Then will be moved from the front of to the front of on the first step, back to on the second step, and so on.

Wrong Proof 2: This is essentially the same as the above.

Motivation: Consider the obvious greedy strategy to construct the collection of increasing subsequences (essentially patience sorting). For each element of from left to right, add it to the increasing subsequence with last element less than such that the value of this last element is maximized. If no such increasing subsequence currently exists, then start a new increasing subsequence with .

This algorithm performs exactly the same steps as the algorithm to compute the length of the longest non-increasing subsequence, so it follows that they return the same result.

Proof: Let denote the length of longest non-increasing subsequence ending at . Then the 's satisfying for a fixed are an increasing subsequence for each . So we have covered with (size of longest non-increasing subsequence) increasing subsequences, done.

Do you see why this is equivalent to the sketch?

Alternative Proof: This is just a special case of Dilworth's Theorem. See the inductive proof.

Code

C++

1#include <bits/stdc++.h>
2using namespace std;
3
4int lis = 0;
5pair<int, int> a[100000];
6set<int> s;
7
8int main() {
9 iostream::sync_with_stdio(false);
10 cin.tie(0);

Java

1import java.io.*;
2import java.util.*;
3
4class PCB{
5 public static void main(String[] args) throws IOException
6 {
7 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
8 int n = Integer.parseInt(br.readLine());
9 TreeMap<Integer, Integer> a = new TreeMap<Integer, Integer>(Collections.reverseOrder());
10 for(int i = 0; i < n; i++){

Problems

StatusSourceProblem NameDifficultyTagsSolutionURL
CSESEasy
Show Tags

DP

Old GoldNormal
Show Tags

DP

External Sol
LMiONormal
Show Tags

DP

Baltic OIHard
Show Tags

DP, Geometry

External Sol
CEOIHard
Show Tags

DP

Module Progress:

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!

Give Us Feedback on (Optional) Longest Increasing Subsequence!

PrevNext