最长非上升子序列

问题描述:

给定一个序列:X1 X2 X3 X4 X5 X6......Xn,试图找到一个最长的子序列,Xi1 Xi2 Xin,使得i1 < i2 < i3 ...而且Xi1 < Xi2 < Xi3......。

举个例子:48 65 34 29 64 38 89

有一种非常简单的做法,能够非常简单的计算出所要序列的长度,但是无法给出序列。过程如下

48

65

65 34

65 34 29

65 64 29

65 64 38

89 64 38

因此最长非上升子序列长度为3,代码如下:

Java

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class SubSeqDesc {

	public static void main(String[] args) {

		Scanner sin = new Scanner(System.in);
		List<Integer> maxList = new ArrayList<Integer>(32);

		int ele = 0;
		if ((ele = sin.nextInt()) != -1) {
			maxList.add(ele);
			while ((ele = sin.nextInt()) != -1) {
				if (maxList.get(maxList.size() - 1) >= ele) {
					maxList.add(ele);
				} else {
					int i = 0;
					while (maxList.get(i) >= ele)
						i++;
					maxList.set(i, ele);
				}
			}
			System.out.println("the longest subsequence' length is " + maxList.size());
		} else {
			System.out.println("no sequence...");
		}
	}

}

另外有一种动态规划的方法。记opt[i](i = 0...len)表示以array[i]为尾的满足条件的序列,那么最终所要求的序列必定在opt[i]中的最大值,也就是序列最大长度。代码如下:

Java

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class SubSeqDesc2 {

	public static void main(String[] args) {

		Scanner sin = new Scanner(System.in);
		List<Integer> maxList = new ArrayList<Integer>(32);

		int ele = 0;
		while ((ele = sin.nextInt()) != -1) {
			maxList.add(ele);
		}
		int len = maxList.size();
		if (len == 0) {
			System.out.println("no sequence...");
		} else {
			Integer[] seq = new Integer[len];
			maxList.toArray(seq);
			int[] opt = new int[len];
			opt[0] = 1;
			for(int i = 1; i < len; i++){
				opt[i] = 1;
				for(int j = 0; j < i; j++){
					if(seq[j] >= seq[i] && opt[j] + 1 > opt[i]){
						opt[i] = opt[j] + 1;
					}
				}
			}
			int result = opt[0];
			for(int i = 1; i < len; i++){
				if(result < opt[i]){
					result = opt[i];
				}
			}
			System.out.println("the longest subseq is " + result);
		}
	}
}

根据第二个做法,可以通过加入新的前向数组来输出一个最长的子序列:

Java

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class SubSeqDesc3 {

	public static void main(String[] args) {

		Scanner sin = new Scanner(System.in);
		List<Integer> maxList = new ArrayList<Integer>(32);

		int ele = 0;
		while ((ele = sin.nextInt()) != -1) {
			maxList.add(ele);
		}
		int len = maxList.size();
		if (len == 0) {
			System.out.println("no sequence...");
		} else {
			Integer[] seq = new Integer[len];
			int[] previous = new int[len];
			
			maxList.toArray(seq);
			int[] opt = new int[len];
			opt[0] = 1;
			previous[0] = -1;
			
			for(int i = 1; i < len; i++){
				opt[i] = 1;
				previous[i] = -1;
				for(int j = 0; j < i; j++){
					if(seq[j] >= seq[i] && opt[j] + 1 > opt[i]){
						opt[i] = opt[j] + 1;
						previous[i] = j;
					}
				}
			}
			int result = 0;
			for(int i = 1; i < len; i++){
				if(result < opt[i]){
					result = i;
				}
			}
			System.out.println("length:" + opt[result]);
			System.out.print("subsequence:");
			
			LinkedList<Integer> stack = new LinkedList<Integer>();
			do{
				stack.push(result);
				result = previous[result];
			}while(result != -1);
			
			while(!stack.isEmpty()){
				System.out.print(seq[stack.pop()] + " ");
			}
			System.out.println();
		}
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值