俄国沙皇问题笔记

来源:互联网 发布:mac版的photoshop cc 编辑:程序博客网 时间:2024/04/29 01:07
给定一个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]
要求:实现时间复杂度O(N*logN)的解法


铺垫:最长递增子序列求解
例如一个数列:2,1,6,4,5,2,7,4
则其最长递增子序列有4个:1,4,5,7或2,4,5,7等
O(n²)解法:
生成一个辅助数组h[8],这辅助数组的用于存放必须以第i个数字结尾的子序列长度,即求出以任何一个数字结尾的数列的最长递增子序列长度。每个数字都要求解以该数字结尾的最长递增子序列长度,即首先是2,以2结尾的最长递增子序列就是2,则h[0]=1;之后是1,以1结尾的最长递增子序列是1,则h[1]=1;之后是6,以6结尾的最长递增子序列是1,6或者2,6,则h[2]=2,以此类推,则例中的h[8]=[1,1,2,2,3,2,4,3]
O(nlogN)解法:
(ps:看到logN一般就会想到是二分法)
此算法是吧之前的枚举过程加速
生成一个辅助数组h[8],首先对于2,直接将2放入,h[0]=2,此时认为之后的h数组都是无效区,只有h[0]是有效区;遇到1时,在有效区中找第一个大于1的数字,利用二分法,因为有效区的有序的,此时由于2>1,则将2换成1,此时h[0]=1,有效区仍然是h[0];
遇到6,在有效区中找第一个大于6的数,但是由于在有效区中没有找到比6大的数,故此时扩充有效区,此时有效区为[1,6],则以6结尾的有效区中的长度为2;
之后是4,在有效区中找到第一个大于4的数,故将6换为4,此时有效区为[1,4],则以4结尾的最长递增子序列是1,4,长度为2;
之后是5,在有效区中扩充,此时有效区为[1,4,5],以5结尾的最长递增子序列为1,4,5,长度为3;
之后是2,将4换为2,此时有效区为1,2,5,则以2结尾的最长递增子序列为1,2,长度为2;
之后是7,扩充有效区,此时以7结尾的最长递增子序列为1,2,5,7,长度为4;
之后是4,此时,将5换为4,此时最长递增子序列为1,2,4,7,即以4结尾的最长递增子序列长度为3。
h[i]的含义是假设当前遍历到cur,h[i]有效区代表遍历到cur为止,长度为i+1的最长递增子序列的最小末尾是什么数,h数组是维持了最小末尾。

public static int[] getdp(int[] arr){int[] dp = new int[arr.length];  //以每个数字结尾的最长递增子序列的长度int[] ends = new int[arr.length];  ends[0] = arr[0];  int right = 0;  //有效区长度int l = 0;   //有效区的左边界int r = 0;   //有效区的右边界int m = 0;for(int i = 1; i<arr.length; i++){l = 0;r = right;while(l<=r){//在有效区中找到最后一个比当前数小的位置m = (1+r)/2;if(arr[i] > ends[m]){l = m + 1;}else{r = m - 1;}}right = Math.max(right, 1);//若没有找到,扩充有效区ends[i] = arr[i];dp[i] = 1 + i;//以当前数结尾的最长递增子序列长度}return dp;}




以下求解原题:
一种解法是时间复杂度为O(n²),先按照a升序排序,如果a相等时,以b升序排序,得到一个序列,之后在此序列中对b查找最长递增子序列。
本题时间复杂度为O(nLogN)排序策略是,先按照a的值升序排序,当a相等时,以b降序排序。
生成一个辅助数组h[],此时h中放入的是b的值。在a相等时,只关注b,更新h,h只维持b出现的最小末尾。

import java.util.Arrays;import java.util.Comparator;public class RussianDollEnvelopes{public static class Dot{public int w;public int h;public Dot(int weight, int high){w = weight;h = high;}}public static class DotComparator implements Comparator<Dot>{//定义Dot比较器,若返回-1,则arg0放在前面,若返回1,表示arg1放在前面@Overridepublic int compare(Dot arg0, Dot arg1){if(arg0.w == arg1.w){if(arg0.h == arg1.h){return 0;}else if(arg0.h < arg1.h){return 1;}else{return -1;}}else if(arg0.w < arg1.w){return -1;}else{return 1;}}}public static int maxEnvelopes(int[][] es){if(es == null || es.length == 0 || es[0] == null || es[0],length != 2){return 0;}}Dot[] dots = new Dot[es.length];for(int i =0; i<es.length;i++){dots[i] = new Dot(es[i][0], es[i][1]);}Arrays.sort(dots, new DotComparator());//调用排序方法int[] ends = new int[es.length];ends[0] = dots[0].h;int right = 0;int l = 0;int r = 0;int m = 0;for(int i = 1; i<dots.length;i++){l = 0;r = right;while(l <= r){m = (1+r)/2;if(dots[i].h >ends[m]){l = m + 1;}else{r = m - 1;}}right = Math.max(right, l);ends[1] = dots[1].h;}return right+1;}public static void main(String[] args){//...}


原创粉丝点击