简述:
设计一个O(n2)以及O(nlogn)时间的算法,找出n个数组成的序列的最长单调递增子序列
例如,
4, 5, 8, 8, 4, 0, 8, 3, 6, 9, 这十个数字
其中最长递增子序列为 4,5,8,9
O(n2)的算法(找子问题)
这个算法的角度是,遍历一遍原始数组,如果假设当前遍历的元素是第i个
那么只要考虑i号元素之前的最大递增子序列,如果该子序列最后一个元素result[curLongestLength - 1] < array[i] 那么自动把array[i] 加入到变更后的最长递增子序列
由于每一次判断都要遍历i号元素之前所有的j < i ,从而获取i之前的最长递增子序列所以时间复杂度为O(n2)
O(nlogn)的算法(在二分查找替换上的优化)
演示一下这个算法,
原始数组:
100, 102, 1, 101 , 2, 3, 4
用resultArray[7]保留结果
1) resultArray[0] = 100; int curLongestLength = 1;
2) 之后遍历到102元素,发现102大于resultArray最大的元素100, 自动在有序结果集中增加resultArray[++curLongestLength - 1] = 102;
3) 之后遍历到1,发现1小于等于resultArray[0]即结果集中最小的元素, 自动将resultArray[0] = 1;
4) 之后遍历到101, 发现这个数处于结果集最小值1 与 最大值102之间,于是用二分查找得到索引【1】, 于是替换resultArray[1] = 101;
此时结果集resultArray为: resultArray[0] = 1, resultArray[1] = 101
5) 之后遍历到2,同4)得到索引为【1】, 于是resultArray[1] = 2;
6) 之后遍历到3, 由于3 大于结果集中最大的元素2, 于是自动执行resultArray[++curLongestLength - 1] = 3;此时结果集总长度为3
7)之后遍历到4, 由于4 大于结果集中最大的元素3, 于是自动执行resultArray[++curLongestLength - 1] = 4;此时结果集总长度为4
于是得到最终的最长递增子序列长度为 4 , 其中元素为 1,2,3,4
两种算法代码实现:
package dynamic_programming;
import java.util.Random;
public class LongestIncrementalSubSequence {
public static void main(String[] args) {
int array[] = new int[10];
System.out.print("Raw Input: ");
for(int i = 0;i < 10;i++){
Random random = new Random();
array[i] = random.nextInt(10);
System.out.print(array[i] + ", " );
}
System.out.println("\nLongest Distance of O(n2): "
+ GetLongestIncrementalSubSequence__O_N2_(array));
System.out.println("Longest Distance of O(nlogn): "
+ GetLongestIncrementalSubSequence__O_NLogN_(array));
}
public static int GetLongestIncrementalSubSequence__O_N2_(int array[]){
int recordLengthArray[] = new int[array.length];
recordLengthArray[0] = 1;
for(int i = 1;i < array.length;i++){
//use curLongestSubSequenceLength to record the length of
//the longest sub incremental sequence before i
int curLongestSubSequenceLength = 0;
for(int j = 0;j < i;j++){
if(array[j] < array[i]
&& curLongestSubSequenceLength < recordLengthArray[j]){
curLongestSubSequenceLength = recordLengthArray[j];
}
}
recordLengthArray[i] = ++curLongestSubSequenceLength;
}
int longestIncermentalSubSequenceLength = 0;
for(int i = 0;i < recordLengthArray.length;i++){
if(recordLengthArray[i] > longestIncermentalSubSequenceLength){
longestIncermentalSubSequenceLength = recordLengthArray[i];
}
}
return longestIncermentalSubSequenceLength;
}
public static int GetLongestIncrementalSubSequence__O_NLogN_(int array[]){
//use the result array to get the longest length
int resultArray[] = new int[array.length];
if(array.length == 0)
return 0;
resultArray[0] = array[0];
int curLongestLength = 1;
for(int i = 1;i < array.length;i++){
if(array[i] > resultArray[curLongestLength - 1]){
resultArray[++curLongestLength - 1] = array[i];
}
else{
if(array[i] <= resultArray[0]){
resultArray[0] = array[i];
continue;
}
//use binary search to fill the correct position
int start = 0; //point to b[0]
int end = curLongestLength - 1; //point to b[curLongestLength - 1]
for(;start != end - 1;){
if(array[i] > resultArray[(start + end) / 2])
start = (start + end) / 2;
else
end = (start + end) / 2;
}
resultArray[end] = array[i];
}
}
return curLongestLength;
}
}
输出: