import java.util.*;
/**
* NC153 信封嵌套问题
* @author d3y1
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 相同题目 => NC91 最长上升子序列(三)
* @param letters int整型二维数组
* @return int整型
*/
public int maxLetters (int[][] letters) {
// return solution1(letters);
return solution2(letters);
}
/**
* 动态规划: 等价于最长上升子序列(Longest Increasing Subsequence)LIS问题
*
* dp[i]表示从前面到以第i个信封结尾的最多嵌套层数(letters[i][1]必须被选取)
*
* dp[i] = Math.max(dp[i], dp[j]+1) , letters[j][1] < letters[i][1]
*
* @param letters
* @return
*/
private int solution1(int[][] letters){
// 预处理 信封排序(长度升序 宽度降序)
// Arrays.sort(letters, (o1, o2)->(o1[0]==o2[0]?o2[1]-o1[1]:o1[0]-o2[0]));
// Arrays.sort(letters, (o1, o2) -> {
// if(o1[0] == o2[0]){
// return o2[1]-o1[1];
// }else{
// return o1[0]-o2[0];
// }
// });
// 最快
Arrays.sort(letters, new Comparator<int[]>(){
@Override
public int compare(int[] o1, int[] o2){
if(o1[0] == o2[0]){
return o2[1]-o1[1];
}else{
return o1[0]-o2[0];
}
}
});
int len = letters.length;
int[] dp = new int[len];
// 初始值
dp[0] = 1;
// 最长上升子序列的长度
int max = 1;
for(int i=1; i<len; i++){
dp[i] = 1;
for(int j=0; j<i; j++){
if(letters[j][1] < letters[i][1]){
dp[i] = Math.max(dp[i], dp[j]+1);
}
}
max = Math.max(max, dp[i]);
}
return max;
}
/**
* 贪心 + 二分
* @param letters
* @return
*/
private int solution2(int[][] letters){
// 预处理 信封排序(长度升序 宽度降序)
// Arrays.sort(letters, (o1, o2)->(o1[0]==o2[0]?o2[1]-o1[1]:o1[0]-o2[0]));
Arrays.sort(letters, new Comparator<int[]>(){
@Override
public int compare(int[] o1, int[] o2){
if(o1[0] == o2[0]){
return o2[1]-o1[1];
}else{
return o1[0]-o2[0];
}
}
});
int len = letters.length;
// dp[i]表示从前面到以第i个信封结尾的最多嵌套层数(letters[i][1]必须被选取)
int[] dp = new int[len];
// 最长上升子序列 单调增
int[] seq = new int[len+1];
seq[1] = letters[0][1];
dp[0] = 1;
// 最长上升子序列的长度
int max = 1;
for(int i=1; i<len; i++){
if(seq[max] < letters[i][1]){
seq[++max] = letters[i][1];
dp[i] = max;
}else{
int left=0,right=max;
// 上升子序列seq中二分查找最大的小于letters[i][1]的位置pos
int pos = 0;
while(left <= right){
int mid = (left + right) >> 1;
if(seq[mid] < letters[i][1]){
pos = mid;
left = mid + 1;
}else{
right = mid - 1;
}
}
// 替换
seq[pos+1] = letters[i][1];
dp[i] = pos + 1;
}
}
return max;
}
}