catalogue
Problem Description:
Given a sequence, such as arr=[10, 9, 2, 5, 3, 7, 101, 18], find the longest increasing subsequence of the sequence.
The longest increasing subsequence (LIS) can be solved by dynamic programming with n^2 complexity or greedy plus dichotomy with nlongn complexity.
Dynamic programming: (n^2)
Let dp[i] be the maximum length at the end of arr[i], then at the beginning, the element values in dp array are all 1 (self length). Take the above array as an example:
dp[0] = 1(10)
dp[1] = 1(9)
dp[2] = 1(2)
dp[3] = dp[2] + 1 = 2(2,5)
dp[4] = dp[2] + 1 = 2(2,3)
dp[5] = dp[2] + 1 = 2 or dp[5] = dp[3] + 1 = 3 or dp[5] = dp[4] + 1 = 3 (2,7) (2,5,7) (2,3,7)
dp[6] = dp[0... 5] + 1, DP [i] < DP [6], whichever is the largest
The maximum value stored in dp is the final maximum length.
java code:
public class Main { public static void main(String[] args) { int []arr = new int[] {10, 9, 2, 5, 3, 7, 101, 18}; int []dp = new int[arr.length]; for(int i = 0; i < arr.length; i++) {//Traversing elements in arr dp[i] = 1;//The dp array is initialized to 1, that is, its length is 1 for(int j = 0; j < i; j++) {//Element before traversing dp[i] if(arr[j] < arr[i]) {//Less than current element dp[i] = Math.max(dp[i], dp[j] + 1);//compare } } } int max = Integer.MIN_VALUE;//Find the maximum value stored in dp for(int i = 0; i < arr.length; i++) { max = Math.max(max, dp[i]); } System.out.println(max); } }
Greed + dichotomy: (nlongn)
For a rising subsequence, the smaller the element of the end value, the more conducive it is to add new elements after it, making the length the longest.
Taking arr=[10, 9, 2, 5, 3, 7, 101, 18] as an example, let the element values in the dp array be the longest sequence. The following is the dynamic change process of dp:
① dp[0] = 10. If there is no element, add 10 directly
② dp[0] = 9, because 9 is smaller than 10, and the length is still 1 after changing to 9, and it is more likely to butt the following elements
③ dp[0] = 2, because 2 is smaller than 9, and the length is still 1 after changing to 2, and it is more likely to connect with the following elements. For example, when 5 comes later, 2 can be directly followed by 5, while 9 cannot (greedy thinking, local optimization)
④ dp[1] = 5, adding 5 can make the length longer
⑤ dp[1] = 3, you should find the element that is just less than 3, and then overwrite the following element with 3 (you can use two points when searching)
⑥ dp[2] = 7 (ditto below)
⑦dp[3] = 101
⑧dp[3] = 18
java code:
import java.util.Arrays; public class Main { public static void main(String[] args) { int []arr = new int[] {10, 9, 2, 5, 3, 7, 101, 18}; int []dp = new int[arr.length]; int len = 0;//The rightmost end of binary search (card range), the number of "meaningful" elements in dp for(int i = 0; i < arr.length; i++) { int index = Arrays.binarySearch(dp, 0, len, arr[i]); if(index < 0) { index = -(index + 1);//Change index to expected position } dp[index] = arr[i];//Update or append if(index == len) { len++; } } System.out.println(len); } }
Use of binarysearch():
binnarySearch() of the tool class Arrays is called during binary search. When using this method to find the element to be found, the found index is returned; If it cannot be found, a negative number is returned. Assuming that the non-existent elements should be located at index r when sorting, then - (r + 1) is the returned negative value.
For example:
public class BinarySeach { public static void main(String[] args) { int[] src = { 1, 2, 4, 5, 7, 8, 12 }; System.out.print(Arrays.binarySearch(src, 10)); //-7 } }
If 10 does not exist in the src array, a negative number is returned. When 10 is placed in the ordered array src, it should be at index 6, so the negative value returned is - (6 + 1), that is, - 7.