lintcode(602)Russian Doll Envelopes

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;
    }  
} 












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值