双向最长上升子序列

问题:

从一列不重复的数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的。

Input :

输入第一行为用例个数, 每个测试用例输入是一个数组,数值通过空格隔开。

Output:

输出筛选之后的数组,用空格隔开。如果有多种结果,则一行一种结果, 单个输入的所有结果按从小到大排序,排序的key的优先级随index递增而递减 例如 3 4 7 6; 1 3 7 5; 1 2 7 6; 1 3 7 6 排序成 1 2 7 6;1 3 7 5;1 3 7 6; 3 4 7 6; 

Sample Input :

4
1 2 4 7 11 10 9 15 3 5 8 6
1 3 5 4 7 6 4 5 3
1 2 3
3 2 1

 Sample Output:

1 2 4 7 11 10 9 8 6
1 3 4 7 6 4 3
1 3 4 7 6 5 3
1 3 5 7 6 4 3
1 3 5 7 6 5 3
1 2 3
3 2 1

解题思路:

最长序列长度:

首先求数组从左到右,以 i 结尾的最长递增子序列 LIS,再求数组从右到左,以 i 结尾的最长递增子序列 LDS,对每个位置的 i ,序列的最长长度为 LIS[i] + LDS[i] - 1 ,求出最长序列长度。

输出每个序列结果:

对每个位置的序列长度进行遍历,将每个最大序列长度 i 的位置 记录到 maxIndex中。再对maxIndex中每个位置进行遍历,分别求出列表中该元素的前缀和后缀,组成一组答案,最终遍历完成,对答案进行去重,排序,输出。

求前缀与后缀过程:

假设列表为arr,当前maxIndex = i , 则前缀最长上升子序列长度为front = 1、2、3、...、LIS[i] - 1,对这些长度倒序遍历,找出列表中 i 之前满足LIS[j] = front的位置 j,将同一 front 下的所有满足条件的位置 j 放入列表中,后对当前结果序列进行遍历,如最初结果序列中只有 11 一个元素,取得结果序列中首部的元素,如"7 11"的结果序列中,首部元素first_num = 7,若arr[j] < first 并且 j < arr.indexof(7),即当前位置的元素比结果序列中首部元素要小,并且该元素的索引,在首部元素索引的前面,则,string = arr[j] + " " + string,即将当前位置的元素加入到结果序列中。不断循环,直至求出所有前缀。

求后缀的过程与求前缀的过程基本类似。

参考代码(JAVA):

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;


public class Main5 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int cases = Integer.parseInt(sc.nextLine());
		for(int i = 0; i < cases ; i++) {
			String str1 = sc.nextLine();
			String[] str3 = str1.split(" ");
			int n = str3.length;
			ArrayList<Integer> arr = new ArrayList<Integer>();
			for(int j = 0; j < str3.length; j++){
				arr.add(Integer.parseInt(str3[j]));
			}
			int[] LIS = getLIS(arr,n);
			int[] LDS = getLDS(arr,n);
			
			ArrayList<Integer> maxIndex = new ArrayList<Integer>();
			int[] lengthArr = getLengthAndMaxLength(LIS,LDS,n);
			int maxLength = lengthArr[lengthArr.length-1];
			for (int j = 0; j < n; j++) {
				if(lengthArr[j] == maxLength) {
					maxIndex.add(j);
				}
			}
//			System.out.println(maxLength);
			ArrayList<String> output = getOutPut(arr,lengthArr,n,maxIndex,LIS,LDS);
			output = getUniqueOutput(output);
			for (String string : output) {
				System.out.println(string);
			}
			
		}
	}
	
	
	
	private static ArrayList<String> getUniqueOutput(List<String> output) {
		// TODO Auto-generated method stub
		Set<String> s = new HashSet<>();
		s.addAll(output);
		ArrayList<String> unique = new ArrayList<String>();
		unique.addAll(s);
		Collections.sort(unique);
		return unique;
	}



	private static ArrayList<String> getOutPut(ArrayList<Integer> arr, int[] lengthArr, int n,
			ArrayList<Integer> maxIndex, int[] LIS, int[] LDS) {
		
		ArrayList<String> output = new ArrayList<String>();
		for (Integer i : maxIndex) {
			int front = LIS[i] - 1;
			ArrayList<String> sFront = new ArrayList<String>();
			sFront.add(arr.get(i)+"");
			while(front > 0) {
				ArrayList<Integer> index = new ArrayList<Integer>();
				for (int j = 0; j < i; j++) {
					if(LIS[j] == front) {
						index.add(j);
					}
				}
				if(!index.isEmpty()) {
					sFront = addFirst(sFront,arr,index);
				}
				front--;
			}
			int after = LDS[i] - 1;
			while(after > 0) {
				ArrayList<Integer> index = new ArrayList<Integer>();
				for (int j = i + 1; j < n; j++) {
					if(LDS[j] == after) {
						index.add(j);
					}
				}
				if(!index.isEmpty()) {
					sFront = addAfter(sFront,arr,index);
				}
				after--;
			}
			output.addAll(sFront);
		}
		return output;
	}

	private static ArrayList<String> addAfter(ArrayList<String> str,
			ArrayList<Integer> arr, ArrayList<Integer> pos) {
		ArrayList<String> s = new ArrayList<String>();
		for (Integer index : pos) {
			if(!str.isEmpty()) {
				for (String string : str) {
					int last_num = Integer.parseInt(string.split(" ")[string.split(" ").length - 1]);
					if(arr.get(index) < last_num && index > arr.lastIndexOf(last_num)) {
						string = string + " " + arr.get(index);
						s.add(string);
					}	
				}
			}else {
				s.add(arr.get(index)+"");
			}
		}
		return s;	
	}



	private static ArrayList<String> addFirst(ArrayList<String> str, ArrayList<Integer> arr, ArrayList<Integer> pos) {
		
		ArrayList<String> s = new ArrayList<String>();
		for (Integer index : pos) {
			if(!str.isEmpty()) {
				for (String string : str) {
					int first_num = Integer.parseInt(string.split(" ")[0]);
//					System.out.println(first_num +"  "+ arr.indexOf(first_num));
					if(arr.get(index) < first_num && index < arr.indexOf(first_num)) {
						string = arr.get(index) + " " + string;
						s.add(string);
					}	
				}
			}else {
				s.add(arr.get(index) + "");
			}
		}
		return s;	
	}



	private static int[] getLengthAndMaxLength(int[] LIS,int[] LDS,int n) {
		int maxLength = 0;
		int[] lengthArr = new int[n + 10];
		for (int j = 0; j < n; j++) {
			int length = LIS[j] + LDS[j] - 1;
			lengthArr[j] = length;
			if(length > maxLength) {
				maxLength = length;
			}
		}
		lengthArr[lengthArr.length - 1] = maxLength;
		return lengthArr;
	}
	//获取以0为起点,以i为终点的最长递增子序列
	public static int[] getLIS(ArrayList<Integer> arr, int n) {
		int[] LIS = new int[n+10];
		Arrays.fill(LIS, 1);
		for (int i = 1; i < arr.size(); i++) {
			for (int j = 0; j < i; j++) {
				if(arr.get(j) < arr.get(i)) {
					LIS[i] = Math.max(LIS[i], LIS[j] + 1);
				}
			}
		}
		return LIS;
	}
	//获取以i为起点,以n为终点的最长递减子序列
	public static int[] getLDS(ArrayList<Integer> arr, int n) {
		int[] LDS = new int[n+10];
		Arrays.fill(LDS, 1);
		for (int i = n - 2; i >= 0; i--) {
			for (int j = i + 1; j < n; j++) {
				if(arr.get(j) < arr.get(i)) {
					LDS[i] = Math.max(LDS[i], LDS[j] + 1);
				}
			}
		}
		return LDS;
	}
}

如有错误,请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值