最长递增子序列
第一种是纯用动态规划的O(n2)的方法
dp[i] 表示0~i的最长递增序列的长度
思路:对于每个i,都向前面寻找dp[j]以及num[j]最大且num[j] < num[i]的j, 然后进行状态转移,从长度为2 到 n,依次遍历即可
个人认为该方式不太像动态规划 hhh
然后附上代码:
static int[] num = new int[100000];
static int[] dp = new int[100000];
static void longestDp() {
int res = 0;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
int len = 0;
for(int j = 1; j < i; j++) {
if(num[j] < num[i] && len < dp[j])
len = dp[j];
}
dp[i] = len + 1;
res = dp[i] > res?dp[i]:res;
}
System.out.println(res);
}
第二种是可以达到O(nlogn)的复杂度的算法
多用了O(n)的空间复杂度
新建了个辅助数组help, help[i]表示, i 长度的递增子序列,末尾最小值为help[i]
思路:如果大于help[helpLen]的话,直接插入后面并令helpLen++,否则给num[i]找到它所在的位置,然后最后结果helpLen就是为最长递增子序列的答案。。
然后因为每次都要为i找到它的容身之所的话,那么最好的方法就是二分了
ps:如果是求子序列而不是求长度的话这种方法得进行适当的修改
然后附上代码:
static int[] num = new int[100000];
static int[] dp1 =new int[100000];
static int[] help = new int[10000]; //help数组来解决最后一种nlogn的方法
static int helpLen = 0; //help数组的长度
static int dichotomy(int l, int r, int i) { //辅助的二分函数
if(l == r)
return l;
int mid = (r-l)/2+l;
if(help[mid] > num[i])
return dichotomy(l, mid, i);
else if(help[mid] < num[i])
return dichotomy(mid+1, r, i);
else
return mid;
}
static void longestDp1() { //二分+dp
for(int i = 1; i <= n; i++) {
if(num[i] > help[helpLen]) {
help[++helpLen] = num[i];
}else {
int index = dichotomy(1, helpLen, i);
help[index] = num[i];
}
}
System.out.println(helpLen);
}
思路有参考别人的,但代码纯自己重新写,不喜勿喷