先升后降

7先升后降

Descripton

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

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 1

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

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

代码如下

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
//		int[] arr= {1,3,5,4,7,6,4,5,3};
		
//		int[] arr1= {1,2,10,6,12,2,1};
		
//		int[] arr1= {1,2,3};
		int[] arr2= {8,9,19,21};
//		int[] arr2= {3,2,1};
//		handle(arr1);
		handle(arr2);
		
//		Scanner sc=new Scanner(System.in);
//		int times=Integer.parseInt(sc.nextLine());
//		while(times>0) {
//			String[] line=sc.nextLine().split(" ");
//			int[] arr=new int[line.length];
//			for(int i=0;i<line.length;i++) {
//				arr[i]=Integer.parseInt(line[i]);
//			}
//		
//			handle(arr);
//			
//			times--;
//		}
//		
		
 	}
	
	//翻转字符串
	//注意不是镜面反转
	//比如    str=“1 5 10 8”
	//希望结果时“8 10 5 1”
	//   而不是“5 01 5 1”
	//所以没有使用StringBuilder的reverse()函数
	public static String reverseStr(String str) {
		String[] arr=str.split(" ");
		String res="";
		for(int i=0;i<arr.length;i++) {
			res=res+" "+arr[arr.length-1-i];
		}
		return res;
	  }
	
	
	//结合dp[]值和园数组arr找出 从开始到目标index的路径
	public static void findWay(int[] arr,int[] dp,int index,List ways,int k) {
		//通过递归找到下一个点满足要求的点
		if(k==0) {return;}
		else {
			int[] candi= new int[index];
			int idx=0;
			List newWaysSet=new ArrayList();
			for(int i=index;i>=0;i--) {
				if(dp[i]==k&&arr[i]<arr[index]) {
					List singleWays=new ArrayList();
					for(int j=0;j<ways.size();j++) {
						String temp = (String) ways.get(j);
						temp=arr[i]+" "+temp;
						singleWays.add(temp);
					}
					findWay(arr, dp, i, singleWays, k-1);
					newWaysSet.addAll(singleWays);			
				}
			}
			ways.clear();
			ways.addAll(newWaysSet);
			
		
		}
		
		
	}
	
	//作为主函数
	public static void handle(int[] arr) {
		
			//这边主要时用于 全1之类的输入
			boolean flag=true;
			for(int i=0;i<arr.length-1;i++) {
				for(int j=i+1;j<arr.length;j++) {
					if(arr[i]!=arr[j]) {
						flag=false;
						break;
					}
				}
			}
			if(flag) {
				System.out.println(arr[0]);
				return;
			}

			//采用LIS 
			//采取两头找,每个位置就会有两个次序的LIS值
			//加在一起 找到最大值,注意一下,最大值可能不止一个点
			// 例如   1 2 10 6 12 2 1
			 // 左    1 2 3  3  4 2 1
			//  右    1 2 4  3  3 2 1
			// 10 和12位置都是最大值
			int[] dp1=LIS(arr);
			int[] arr_rev=new int[arr.length];
			for(int i=0;i<arr_rev.length;i++) {
				arr_rev[i]=arr[arr.length-1-i];
			}
			int[] dp2=LIS(arr_rev);
			
			int max=dp1[0]+dp2[arr.length-1]-1;
			
			int[] indexList=new int[arr.length];
			int idxl=0;
			
			for(int i=0;i<dp1.length;i++) {
				if(dp1[i]+dp2[dp1.length-1-i]-1>max) {
					max=dp1[i]+dp2[dp1.length-1-i]-1;
				}
			}
			for(int i=0;i<dp1.length;i++) {
				if(dp1[i]+dp2[dp1.length-1-i]-1==max) {
					indexList[idxl]=i;
					idxl++;
				}
			}
			
			
			//将最大值点进行处理
			//将每个点作为处理的开始赋予一个list,再将所返回的所有list 进行结果打印
			List Result=new ArrayList();
			for(int i=0;i<idxl;i++) {
				List res = handleHelp(indexList[i], arr, arr_rev, dp1, dp2);
				Result.addAll(res);
			}
			print(Result);
			

			
		}
	//找出路径
	public static List handleHelp(int index,int[] arr,int[] arr_rev,int[] dp1,int[] dp2) {
		
		//分别找出左边路径和右边路径,两者合并
		
		String str=arr[index]+"";
		List leftways=new ArrayList();
		leftways.add(str);
		findWay(arr, dp1, index, leftways, dp1[index]-1);
		
		
		String str2=arr_rev[dp2.length-1-index]+"";
		List rightways=new ArrayList();
		rightways.add(str2);
		findWay(arr_rev, dp2, dp2.length-1-index, rightways, dp2[dp2.length-1-index]-1);
	
		List result = linkleftAndRight(leftways,rightways);
		return result;
	}
	
	//用于把左右两边的数组 作为字符串链接起来
	public static List linkleftAndRight(List left,List right) {
		List<String> result=new ArrayList();
		for(int i=0;i<left.size();i++) {
			for(int j=0;j<right.size();j++) {
				String Leftstr=(String) left.get(i);
				String rightstr=(String) right.get(j);
				String[] lArr=Leftstr.split(" ");
				String[] rArr=rightstr.split(" ");
				String lres="";
				String rres="";
				if(rArr.length!=1) {
					for(int t=0;t<rArr.length-1;t++) {
						rres+=rArr[t]+" ";
					}
					rres.substring(0,rres.length()-1);
				}
				if(lres.length()!=1) {
					lres=Leftstr;
				}
				result.add(lres+rres);
				
			}
		}
		return result;
		
	}
	
	public static void print(List result) {
		//去除重复的数组
		for (int i = 0; i < result.size() - 1; i++) {
			for (int j = result.size() - 1; j > i; j--) {
				if (result.get(j).equals(result.get(i))) {
					result.remove(j);
				}
			}
		}
		//排序 
		//但没有真正意义上的排序
		//比如   str1:"2 3 6 13"
		//   和str2:"2 3 10 13"
		//collection 会将str2排在str1之前 因为 取字符串 6比10中的1靠前
		//而事实上我们想要str1排在str2之前
		Collections.sort(result);
		
		//打印
		for (int i = 0; i < result.size(); i++) {
			System.out.println(result.get(i));
		}
	}
	
	//Longest Increasing Subsequence
	public static int[] LIS(int[] arr) {
		//采用动态规划
		//例如数组{1,3,5,4,7,6,4,5,3}
		//       1 2 3 3 4 4 3 4 2
		//每个开始LIS[i]=1 然后从前找到所在的那个数
		//如果这个数比前面的数大 前面的数的LIS值+1 和 自身比较 取最大值
		
		int[] LIS=new int[arr.length];
		for(int i=0;i<arr.length;i++) {
			LIS[i]=1;
			for(int j=0;j<i;j++) {
				if(arr[i]>arr[j]&&LIS[j]+1>LIS[i]) {
					LIS[i]=LIS[j]+1;
				}
			}
		}
//		int max=0;
//		for(int i = 0;i < arr.length;++i)
//	    {
//	        if(LIS[i] > max)
//	            max = LIS[i];
//	    }
		return LIS;
		
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值