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;
}
}