題目:
分析:
這是一道解法很騷的題目,是最長遞增子序列的應用
直接說解法,先進行排序,長度升序,高度降序排序
然後把高度全去下來找最長遞增子序列
這麼做的正確性:
首先套信封是嚴格長和高都要小於才能套進去的,不能等於
找到最長遞增子序列的正確性在於,那麼長度必定不相等,因爲如果長度相等,那麼按高度降序排序,不可能出現遞增,那麼只要出現遞增,那麼前一個的長度必定小於後一個,能套進信封
代碼:
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;
}
}