本文的一些图片, 资料 截取自编程之美
对于这种求优问题, 最基本的思路, 无疑便是穷举了
解法一 : 使用一个incSeq数组存放包含第i个数之前的最长的递增子序列的长度, 将每一个位置的最长递增子序列长度初始化为1, 然后遍历一次数组[循环变量为n], 在遍历的过程中再一次遍历incSeq (0, curN)[循环变量为i], 如果当前数大于arr[i], 并且incSeq[i]+1 > incSeq[n], 则更新incSeq[n]
解法二 : 使用一个incSeq数组存放包含第i个数之前的最长的递增子序列的长度, 将每一个位置的最长递增子序列长度初始化为1, 使用一个maxValue数组存放”递增序列长度为i的子序列中最大值”中的最小的一个, 遍历一次数组[循环变量为i], 找出arr[i]能够满足的最大的maxValue[curMaxLen]
然后判断curMaxLen, 是否大于maxLen,
如果大于 则更新maxLen, 更新maxValue[curMaxLen],
否则 则判断arr[i] 是否小于maxValue[curMaxLen],
如果是 则更新maxValue[curMaxLen]
解法三 : 根据max[i] 的单调递增关系, 初始化上面的找出arr[i]能够满足的最大的maxValue的上界为incSeq[i-1], 但是, 根据上面解法二的代码分析, max[i], 应该不是单调递增的呀,
假设是incSeq现在将其定义改变为第i个数之前的最长的递增子序列的长度, 那么将上界定为[incSeq[i-1] ]的意义貌似也大呀, 应为incSeq[i-1] = maxLen
算了 先将这个问题放在这里, 希望有网友能够帮我解答一下这个解法的思路
/**
* file name : Test23FindMaxIncSeq.java
* created at : 4:58:07 PM May 24, 2015
* created by 970655147
*/
package com.hx.test03;
public class Test23FindMaxIncSeq {
// 找到最大的递增序列
public static void main(String []args) {
int[] intArr = {-50, 0, -14, -15, 32, -34, 19, 32, -25, -50, 41, -6, 45, 26, -38, 36, -4, -13, -8, -36 };
findMaxIncSeq01(intArr);
findMaxIncSeq02(intArr);
findMaxIncSeq03(intArr);
}
// 穷举 incSeq[i]表示包含第i个元素 之前的递增的元素的最大长度
public static void findMaxIncSeq01(int[] intArr) {
int[] incSeq = new int[intArr.length];
for(int i=0; ilength; i++) {
incSeq[i] = 1;
// 遍历前面的元素
// 如果该元素小于intArr[i], 并且该元素的递增最大长度+1 大于intArr[i]的当前递增长度 则更新intArr[i]的递增长度
for(int j=0; jif(intArr[i] > intArr[j] && incSeq[j] + 1 > incSeq[i]) {
incSeq[i] = incSeq[j] + 1;
}
}
}
int max = Tools.getMaxInArr(incSeq);
Log.log(max);
}
// incSeq[i]表示包含第i个元素 之前的递增的元素的最大长度
// maxV[i]表示长度为i 的递增子序列[可能存在多个长度为i的序列]的最大元素 的最小值
// 遍历intArr 找出intArr[i]满足的最长子序列, 更新incSeq[i] [之所以找出intArr[i] 满足的最长的子序列[maxSeqIdx], 是因为, 如果后面存在一个数字其大于[maxSeqIdx], 那么其一定会大于[maxSeqIdx-1], 二者同步增长, [maxSeqIdx-1]的序列永远不可能超过[maxSeqIdx]对应的序列, 所以不用更新[maxSeqIdx]之前的序列]
// 如果incSeq[i]大于maxLen 更新maxLen, maxV[j+1]
// 否则 如果存在intArr[i]满足的序列 并且maxV[j+1]大于intArr[i] 更新maxV[j+1]为intArr[i]
public static void findMaxIncSeq02(int[] intArr) {
int[] maxV = new int[intArr.length + 1];
maxV[1] = intArr[0];
maxV[0] = Tools.getMinInArr(intArr) - 1;
int[] incSeq = new int[intArr.length];
int maxLen = 1;
// 遍历intArr
for(int i=1; ilength; i++) {
incSeq[i] = 1;
int j;
// 找到intArr[i]能满足的最长子序列 更新incSeq[i], 之后的代码中j表示 该子序列的长度
for(j = maxLen; j>=0; j--) {
if(intArr[i] > maxV[j]) {
incSeq[i] = j + 1;
break;
}
}
// 如果第i个元素的递增子序列 超过了maxLen 则更新maxLen, 更新maxV[最大序列的长度]为intArr[i]
// 否则 如果intArr[i] 大于maxV[j][说明更新了incSeq[i]], 并且小于maxV[j+1] 更新maxV[j+1] = intArr[i]
if(incSeq[i] > maxLen) {
maxLen = incSeq[i];
maxV[incSeq[i]] = intArr[i];
} else if(maxV[j] < intArr[i] && intArr[i] < maxV[j+1]) {
maxV[j+1] = intArr[i];
}
}
Log.log(maxLen);
}
// incSeq[i]表示包含第i个元素 之前的递增的元素的最大长度
// maxV[i]表示长度为i 的递增子序列[可能存在多个长度为i的序列]的最大元素 的最小值
public static void findMaxIncSeq03(int[] intArr) {
int[] maxV = new int[intArr.length + 1];
maxV[0] = Tools.getMinInArr(intArr) - 1;
maxV[1] = intArr[0];
int[] incSeq = new int[intArr.length];
for(int i=0; ilength; i++) {
incSeq[i] = 1;
}
int maxLen = 1;
// 遍历intArr
for(int i=1; ilength; i++) {
int j;
// 这个算法 相对于上面的算法 仅仅是在j的初始化上做了一个修改 以及结束条件
// ... 但是 修改之后 好像还错了
// 找到intArr[i]能满足的最长子序列 更新incSeq[i], 之后的代码中j表示 该子序列的长度
for(j = incSeq[i-1]; j>=1; j--) {
if(intArr[i] > maxV[j]) {
incSeq[i] = j + 1;
break;
}
}
// 如果第i个元素的递增子序列 超过了maxLen 则更新maxLen, 更新maxV[最大序列的长度]为intArr[i]
// 否则 如果intArr[i] 大于maxV[j][说明更新了incSeq[i]], 并且小于maxV[j+1] 更新maxV[j+1] = intArr[i]
if(incSeq[i] > maxLen) {
maxLen = incSeq[i];
maxV[incSeq[i]] = intArr[i];
} else if(maxV[j] < intArr[i] && intArr[i] < maxV[j+1]) {
maxV[j+1] = intArr[i];
}
}
Log.log(maxLen);
}
}
这个题目是挺难的, 第二种解法知识比第一种解法优化了一些, 但是时间复杂度仍然为O(n^2)
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!