沙皇算法(及最长自增子序列)
俄国沙皇问题
给定一个N*2的二维数组,看作是一个个二元组,[a1,b1],[a2,b2],[a3,b3],规定:如果想把一个二元组甲放到二元组乙上,甲中的a值必须大于乙中的a值,甲中的b值必须大于乙中的b值,如果二维数组中随意选择二元组,请问二元组中最多可以往上放多少个?
例如:[[7,8],[5,9],[1,2],[6,4],[8,6]],则最多可以放三个:[1,2]->[6,4]->[7,8]或[1,2]->[6,4]->[8,6]
注:只计算了个数,不需要显示出来具体是什么...
最长递增子序列
求给定一个数组中,最长递增子序列的长度
(子序列,可以不连续 子数组,需要连续)
Eg: arr={2,1,6,4,5,2,7,4} 最长递增子序列为 {2,4,5,7} 长度为4
解法一 O(n2)
思路:
- 生成辅助数组temp,temp[i]代表以arr[i]结尾的情况下的最大子序列长度
- 设置temp[i]时,比较arr[i],遍历前方所有比arr[i]小的数,在其集合的最大temp值上加一

缺点:
在思路(2)中需要遍历arr数组的前方所有比arr[i]小的数,为O(n),整体为O(n2)
解法二 O(nlogn)
是对解法一的思路(2)中的改进,使用二分法将复杂度降低
思路:
- Temp存在有效区的概念,即只在一定区间内数据可以存放
- Temp[i]指的是在有效区中,长为i+1的最长子序列的最小末尾值

Temp数组的概念与解法一中有所不同(这里比较难理解)
举个例子: temp[1]=6代表的是长度为1+1=2的最长子序列的最小末尾值为6 ,此时若是继续遍历arr,发现存在子序列长度为2但是末尾值小于6的则会替换(2,1,6,2 1,6->1,2),这样做的意义是在于永远保持temp数组的值的最小,以便后续增加
Arr : 2 1 5 7 3 2->1->1,5->1,5,7->1,3,7
1,5,7->1,3,7 意味着遍历到目前为止,长度为2的子序列可以以5结尾,也可以以3结尾,但是为了统计后续的最大值,替换为3结尾的子序列,在此基础上增加
注意:此时不会影响到前面已经统计的, 1,5,7->1,3,7, 7结尾的最长子序列长度依然是3(子序列为1,5,7),
后面数字为2 1,3,7->1,2,7 长度为2的子序列最小末尾为2 1,2
后面数字为9 1,2,7->1,2,7,9 长度为4的子序列最小末尾为9 1,5,7,9(这个想清楚就理解了)
代码:
public class LongestSeq {
public int[] funcNN(int[] arr){ int[] temp = new int[arr.length]; temp[0] = 1; int max; //后者temp值为前者比其小的arr元素组中最大temp值+1 for(int i=1;i<arr.length;i++){ max=0; for(int j=0;j<i;j++){ if(arr[j]<arr[i] && max<temp[j]){ max = temp[j]; } } temp[i] = max+1; //这里要+1 } return temp; } public int funcNLogn(int[] arr){ int[] temp = new int[arr.length]; int[] maxSize = new int[arr.length]; //记录每个数最大子序列长度 temp[0] = arr[0]; maxSize[0] = 1; int left,right,mid,border=0; for(int i=1;i<arr.length;i++){ left = 0; right = border; while(left<=right){ mid = (left+right)/2; if(temp[mid]<arr[i]){ left = mid+1; }else{ right = mid-1; } } //left递增,会出现大于边界的情况,因此需要比较 //只看left,因为退出循环的情况为left=right+1,所以改变的一定是temp[left] border = Math.max(left,border); temp[left] = arr[i]; maxSize[i] = left+1; } return border+1; } }
比较器
定义比较器
import java.util.Comparator;; public class TypeCompare implements Comparator<Type>{ //按照a从小到大,a相等情况下从大到小 //对于比较器与Arrays.Sort 返回-1,则顺序为d1,d2;返回1,顺序为d2,d1;0随机分配 public int compare(Type t1,Type t2){ if(t1.a == t2.a){ if(t1.b < t2.b){ return 1; }else{ return -1; } }else if(t1.a < t2.a){ return -1; }else{ return 1; } } }
使用比较器排序
import java.util.Arrays; Arrays.sort(type,new TypeCompare());
定义数据类型
public class Type { int a,b; public Type(int a,int b){ this.a = a; this.b = b; } }
算法具体实现
import java.util.Arrays; public class RusEmp { public int getTheEmp(int[][] arr){ Type[] type = new Type[arr.length]; int[] temp = new int[arr.length]; //1.放入Type容器 for(int i=0;i<arr.length;i++){ type[i] = new Type(arr[i][0],arr[i][1]); } //2.使用比较器排序 Arrays.sort(type,new TypeCompare()); //sort调用比较器的compare()函数,又TypeCompare重写了该函数 //3.将所有的temp.b作为一个数组,进行最长子序列遍历,寻找最大长度 for(int i=0;i<temp.length;i++){ temp[i] = type[i].b; } LongestSeq longSeq = new LongestSeq();return longSeq.funcNLogn(temp); } }
返回个数

浙公网安备 33010602011771号