最长不下降子序列

package cn.edu.hit;

import java.util.Scanner;

/**
 * 求最长单调序列
 * @author admin
 *
 */
public class LongestMonotone {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();//数组的长度
		int[] array = new int[n];
		for (int i = 0; i < n; i++) {
			array[i] = in.nextInt();
		}
		int[] count = new int[n];//用于记录到达每个位置的最长子序列
		int[] record =  new int[n];//记录达到某个位置的最大序列的前一个位置
		for (int i = 0; i < record.length; i++) {
			record[i] = -1;
		}
		
		//n^2实现
//		for (int i = 0; i < array.length-1; i++) {
//			for (int j = i; j > -1; j--) {
//				if(array[i+1]>array[j]){//加个等号就是最长不下降序列
//					//count[i+1] = Math.max(count[i+1], count[j]+1);
//					if(count[i+1] < count[j]+1){
//						count[i+1] = count[j]+1;
//						record[i+1] = j;//记录前一个位置
//					}
//				}
//			}
//		}
//		int max = count[0],index = 0;
//		for (int i = 0; i < count.length; i++) {//求出最长的序列长度
//			if(max < count[i]){
//				max = count[i];
//				index = i;
//			}
//		}
//		System.out.println(max+1);
//		//输出最长子序列
//		int[] record1 = new int[n];//正序记录最长子序列
//		int num = 0;
//		record1[num] = array[index];//记录最后一个
//		while(record[index]!=-1){
//			num++;
//			record1[num] = array[record[index]];
//			index = record[index];
//		}
//		for (int i = num; i > -1; i--) {
//			System.out.print(record1[i] + " ");
//		}
		
		//nlogn实现:关键是第二个循环要和所有的小于i的j去比较,倘若一开始就保存了各个最长子序列位置的最大值,再将新出现的值进行二分查找,确定位置即可
		int[] len = new int[n];
		for (int i = 0; i < len.length; i++) {//初始化要将其初始化为无穷大
			len[i] = Integer.MAX_VALUE;
		}
		int max1 = 0;
		for (int i = 0; i < array.length; i++) {
			int pos = bfind(0, i, array[i], len);
			len[pos] = Math.min(len[pos], array[i]);//选取一个小的元素
			count[i] = pos;//记录每个位置最长子序列的长度
			max1 = Math.max(max1, count[i]);
		}
		System.out.println(max1+1);
	}
	
	//二分查找位置
	public static int bfind(int first,int last,int value,int[] len){
		int mid;
		while(first<=last){
			mid = (first+last)/2;
			if(len[mid]<value){
				first = mid + 1;
			}else if(len[mid]>value){
				last = mid-1;
			}else{
				return mid;
			}
		}
		return first;
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值