题目:
分析:
这是一道解法很骚的题目,是最长递增子序列的应用
直接说解法,先进行排序,长度升序,高度降序排序
然后把高度全去下来找最长递增子序列
这么做的正确性:
首先套信封是严格长和高都要小于才能套进去的,不能等于
找到最长递增子序列的正确性在于,那么长度必定不相等,因为如果长度相等,那么按高度降序排序,不可能出现递增,那么只要出现递增,那么前一个的长度必定小于后一个,能套进信封
代码:
class Solution {
public int maxEnvelopes(int[][] envelopes) {
if(envelopes == null){
return 0;
}
Arrays.sort(envelopes, (int[] a, int[] b)->{
if(a[0] == b[0]){
return b[1] - a[1];
}else{
return a[0] - b[0];
}
});
int len = envelopes.length;
int[] heights = new int[len];
//把排序后的高度加入数组
for(int i = 0; i < len; i++){
heights[i] = envelopes[i][1];
}
//求最大递增序列
return bestResolutionOfLIS(heights);
}
//最长递增子序列最优解,用二分
static int bestResolutionOfLIS(int[] nums){
if (nums == null || nums.length == 0){
return 0;
}
int maxLen = 0;
int len = nums.length;
int[] ends = new int[len];
//此时ends没有有效区,为-1
int validIndex = -1;
int[] dp = new int[len];
for (int i = 0; i < len; i++) {
int res = firstBigger(ends, validIndex, nums[i]);
if (res == -1){
//没有找到
validIndex++;
ends[validIndex] = nums[i];
dp[i] = validIndex + 1;
}else {
//找到,更新值
ends[res] = nums[i];
dp[i] = res + 1;
}
maxLen = Math.max(maxLen, dp[i]);
}
return maxLen;
}
static int firstBigger(int[] arr, int end, int target){
int l = 0;
int r = end;
int result = -1;
while (l <= r){
int m = (l + r) / 2;
if (arr[m] > target){
result = m;
r = m - 1;
}else if (arr[m] < target){
l = m + 1;
}else {
return m;
}
}
return result;
}
}