Longest Increasing Subsequence
Problem
Read an array. Print the length of the longest strictly increasing subsequence (the elements keep their order, but they do not have to be next to each other).
Constraints
- 1 <= n <= 2000
Examples
Input
8 10 9 2 5 3 7 101 18
Output
4
Solutions
The array tails stays sorted, so we can use binary search. A smaller tail is always better, because it is easier to extend. The length of tails is the answer. This takes O(n log n) instead of O(n^2).
/*
* Problem : Find the LIS length.
* Input : n, then n integers.
* Output : The length.
* Approach: Keep the smallest tails.
* Time : O(n log n)
* Space : O(n)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// This method solves the task. It receives the input and returns the answer.
static int solve(int[] a) {
// Step 1: tails[i] = the smallest last value of an increasing subsequence with length i + 1.
int[] tails = new int[a.length];
int length = 0;
for (int value : a) {
// Step 2: Binary search for the first tail that is greater than or equal to the value.
int low = 0;
int high = length;
while (low < high) {
int mid = low + (high - low) / 2;
if (tails[mid] < value) {
low = mid + 1;
} else {
high = mid;
}
}
// Step 3: Replace that tail with the value. If the value is bigger than all tails, the subsequence grows.
tails[low] = value;
if (low == length) {
length++;
}
}
return length;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
int[] a = new int[size];
for (int i = 0; i < size; i++) {
a[i] = scanner.nextInt();
}
System.out.println(solve(a));
}
}
Hints (2)
- Why is a smaller tail better?
- Why can we use binary search on tails?