Description:
You have a number of envelopes with widths and heights given as a pair of integers (w, h)
. One envelope can fit into another if and only if both the width and height of one envelope is greater than the width and height of the other envelope.
What is the maximum number of envelopes can you Russian doll? (put one inside other)
Explanation:
Given envelopes = [[5,4],[6,4],[6,7],[2,3]]
,
the maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).
Solution:
首先对信封按照宽度的升序进行排列。如果宽度相等,那么按照高度的降序进行排列。
然后我们开始查找最长的上升子序列。
解释一下for循环:
因为宽度是升序,高度是降序,所以[[5,4],[6,4],[6,7],[2,3]] ——> [[2,3],[5,4],[6,7],[6,4]]
这样可以保证每个宽度最多只有一个会被计数, 不会出现[6,7] [6,4]都被计数的情况。所以就转变成寻找(高度的)最长上升子序列的问题。
遍历每一个元素,用二分法查找是否能够插入到最长子序列中。如果可以计数,不可以则下一个。判断标准就是left==count这时代表当前元素可以插入到子序列的最右端。
每次while循环后交换位置,表示找到当前元素可以插入的位置,但是以Explanation为例,发现[6,4] 换掉了[5,4],这个没有影响,因为是按照高度的找子序列,宽度已经不影响结果了,而且4<7,所以[6,4] 不会换掉[6,7],计数也不会增加。
为了方便理解可以依据[[5,4],[6,4],[6,7],[2,3],[6,5]]执行一遍。
public class Solution {
/**
* @param envelopes a number of envelopes with widths and heights
* @return the maximum number of envelopes
*/
public int maxEnvelopes(int[][] envelopes) {
if(envelopes.length <= 1) return envelopes.length;
Arrays.sort(envelopes , new Comparator<int[]>() {
@Override
public int compare(int[] nums1 , int[]nums2){
int res = nums1[0] - nums2[0];
if(res != 0) return res;
return nums2[1] - nums1[1];
}
});
int count = 1;
for(int i = 0;i<envelopes.length;i++){
int left = 0;
int right = count - 1;
while(left <= right){
int mid = left + (right - left)/2;
if(envelopes[i][1] > envelopes[mid][1]){
left = mid + 1;
}else{
right = mid - 1;
}
}
envelopes[left] = envelopes[i];
if(left == count) count++;
}
return count;
}
}