Question 6 Longest Increasing Subsequence母体
Method 1暴力解(从后往前,但是不会用在面试中,只是为了训练)
public int longest(int[] array) {
// assume array valid
int[] longest = new int[]{1};
int currentLength = 0;
dfs(longest, currentLength, array, array.length - 1, null);
return longest[0];
}
private void DFS(int[] longest, int currentLength, int[] array, int index, Integer lastAddedValue) {
// 哪里都是解
longest[0] = Math.max(longest[0], currentLength);
// branch 所有在index之前比加过的第一个元素还要小的元素,我要知道上次加了谁?
for (int i = index; i >= 0; i++) {
if (lastAddedValue == null || array[i] < lastAddedValue) {
dfs(longest, currentLength + 1, array, array.length - 1, array[i]);
}
}
}
从所有解的角度来衡量:dfs走的每一条路都是不一样,没有任何了一步计算的path
只说剪枝(我这啊哦这条路最终的答案肯定是不hi我要的,那我就压根不去)
去重:我这条路以前已经走过了,答案我知道了,现在不想再走一遍了
Method 2 从backtracking 到pure recursion
public int pureRecursion(int[] array, int index) {
if (index == array.length) {
return 0;
}
int subproblemResult = 0;
for (int i = index + 1; i < array.length; i++) {
if (array[i] > array[index]) {
subproblemResult = Math.max(subproblemResult, PureRecursion[i]);
}
}
return subproblemResult + 1;
}
看到重复的input size recursion call
在1,2,3都调用了pureRecursion(array,4)input size一样,都是4
答案一定都是一样的==》产生了重复&没有必要的运算
pure recursion里的input一样,结果一样,就是完全一样的问题
Method 3 从pure recursion to recursion memo
既然以某个index为开始的LIS一定永远都不会改变==》 那么我们以每一个starting index为开始的LIS只需要计算一次
class Solution{
public int lengthOfLIS(int[] array) {
if (array == null || array.length == 0) {
return 0;
}
int result = 0;
int[] LISStartingAtMemo = new int[array.length];
for (int i = 0; i < array.length; i++) {
result = Math.max(result, PureRecursionMemo(array, i, LISStartingAtMemo));
}
return result;
}
private int PureRecursionMemo(int[] array, int index, int[] LISStartingAtMemo) {
if (index == array.length) {
return 0;
}
// 如果我已经计算过了,那就别计算了,直接返回上次的结果
if (LISStartingAtMemo[index] != 0) {
return LISStartingAtMemo[index];
}
int subProblemResult = 0;
for (int i = index + 1; i < array.length; i++) {
if (array[i] > array[index]) {
subProblemResult = Math.max(subProblemResult, PureRecursionMemo(array, i , LISStartAtMemo));
}
}
//这次计算完 千万记下来
LISStartingAtMemo[index] = subProblemResult + 1;
return LISStartingAtMemo[index];
}
}
Longest Increating Subsequence时间复杂度是多少?O(N!)==> O(N^2)
Method 4真的确定有优化, pure recursion memo to dynamic programming
顺序又回到了ending index上:linear scan回头看
Step1 DP definition
LIS[i] represent longest increasing subsequence ending at i must including i
Step 2 Base Case
LIS[0] = 1
Step 3 Induction Rule
LIS[i] = Max(LIS[j] + 1) iff j < i && array[j] < array[i]
Step 4 Fill in order
left to right
Step 5 Return what
globalMax of all LIS[i]
public int longestOfLIS(int[] array){
int[] LIS = new int[array.length];
LIS[0] = 1;
int globalLongest - 1;
// left to right
for (int i = 0; i < array.length; i++) {
LIS[i] = 1;
for (int j = 0; j < i; j ++) {
if (array[j] < array[i]) {
LIS[i] = Math.max(LIS[i], LIS[j] + 1);
}
globalLongest = Math.max(globalLongest, LIS[i]);
}
}
return globalLongest;
}
TC & SC: O(n^2), O(n)
Last updated