求非连续最长单调递增子序列

简述:

设计一个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;
	}

}

输出:




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值