最长不下降子序列

package dp;

import java.util.Arrays;

/***
 * [3,4,7,1,9] 的最长不减序列是[3,4,7,9]。返回4。
 * 
 * @author MiXian
 *
 */
public class LongestNoDecreaseSubArray {

	/**
	 * O(n^2)
	 */
	public static int length(int[] nums) {
		if (nums == null || nums.length == 0) {
			return 0;
		}

		int l = nums.length;
		int[] dp = new int[l];
		int max = 1;
		Arrays.fill(dp, 1);
		for (int i = 1; i < l; ++i) {
			int n = nums[i];
			for (int j = i - 1; j >= 0; --j) {
				if (nums[j] <= n && dp[j] >= dp[i]) {
					dp[i] = dp[j] + 1;
					if (dp[i] > max) {
						max = dp[i];
					}
				}
			}
		}
		return max;
	}

	/**
	 * O(nlogn)的算法关键是它建立了一个数组b[],b[i]表示长度为i的不下降序列中结尾元素的最小值
	 * K表示数组目前的长度,算法完成后K的值即为最长不下降子序列的长度。
	 * 
	 * 具体点来讲:
	 * 
	 * 设当前的以求出的长度为K,则判断a[i]和b[k]:
	 * 
	 * 1.如果a[i]>=b[k],即a[i]大于长度为K的序列中的最后一个元素,这样就可以使序列的长度增加1,即K=K+1,
	 * 然后现在的b[k]=a[i]
	 * 
	 * 2.如果a[i]<b[k],那么就在b[1]...b[k]中找到最大的j,使得b[j]<a[i],然后因为b[j]<a[i],
	 * 所以a[i]大于长度为j的序列的最后一个元素,那么就可以更新长度为j+1的序列的最后一个元素,即b[j+1]=a[i]。
	 * 
	 * 算法复杂度的分析:
	 * 
	 * 因为共有n个元素要进行计算;每次计算又要查找n次,所以复杂度是O(n^2),但是,注意到b[]数组里的元素的单调递增的,所以我们可以用二分法,
	 * 查找变成了logn次.
	 * 这样算法的复杂度就变成了O(nlogn)。
	 */
	public static int len(int[] nums) {
		if (nums == null || nums.length == 0) {
			return 0;
		}

		int l = nums.length;
		int[] lastOfLen = new int[l];
		int curLen = 0;
		lastOfLen[0] = nums[0];// 长度为1寸在lastOfLen[0]中
		for (int i = 1; i < l; ++i) {
			if (nums[i] >= lastOfLen[curLen]) {
				lastOfLen[++curLen] = nums[i];
			} else {
				if (nums[i] < lastOfLen[0]) {
					lastOfLen[0] = nums[i];
				} else {
					lastOfLen[findLen(lastOfLen, 0, curLen, nums[i])] = nums[i];
				}
			}
		}
		return 1 + curLen;
	}

	// 将n应该更新的下面返回   n属于[lens[0], lens[r])
	private static int findLen(int[] lens, int l, int r, int n) {
		while (l < r) {
			int m = (l + r) >> 1;
			if (n >= lens[m] && n < lens[m + 1]) {
				return m + 1;
			} else if (n < lens[m]) {
				r = m;
			} else {
				l = m + 1;
			}
		}
		return l;
	}

	public static void main(String[] args) {
		System.out.println(length(new int[] { 3, 4, 7, 9 }));
		System.out.println(length(new int[] { 3, 4, 1, 7, 9 }));
		System.out.println(length(new int[] { 3, 4, 8, 7, 9 }));
		System.out.println(length(new int[] { 3, 1, 7, 9 }));
		System.out.println(length(new int[] { 3 }));
		System.out.println(length(new int[] { 3, 2, 2, 1 }));
		System.out.println(length(new int[] { 1, 1, 2 }));

		System.out.println(len(new int[] { 3, 4, 7, 9 }));
		System.out.println(len(new int[] { 3, 4, 1, 7, 9 }));
		System.out.println(len(new int[] { 3, 4, 8, 7, 9 }));
		System.out.println(len(new int[] { 3, 1, 7, 9 }));
		System.out.println(len(new int[] { 3 }));
		System.out.println(len(new int[] { 3, 2, 2, 1 }));
		System.out.println(len(new int[] { 1, 1, 2 }));
		boolean isTest = true;
		if (isTest) {
			int[] lens1 = { 3, 4, 9 };
			test(lens1, 3);
			test(lens1, 4);
			test(lens1, 5);

			int[] lens3 = { 1, 5 };
			test(lens3, 4);
			test(lens3, 1);
		}
	}

	// /// tests
	private static void test(int[] lens, int n) {
		for (int i = 0; i < lens.length; ++i) {
			System.out.print(lens[i] + " ");
		}
		System.out.println(" : " + n);
		System.out.println(findLen(lens, 0, lens.length - 1, n));
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值