DP动态规划专题十四:LeetCode 354. Russian Doll Envelopes

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)

Note:
Rotation is not allowed.

Example:

Input: [[5,4],[6,4],[6,7],[2,3]]
Output: 3 

Explanation: The maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).

注意:这道题的dp并不是返回最后一个答案,而且也不能通过加一个全局变量来解决,因为从最后一个出发可能走不到一些信封,然后最大的答案可能就是从这些信封走起的。因此,主函数里应该有一个for循环,把从每个位置作为结尾都走一遍。

    class En{
        int x;
        int y;
        public En(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    public int maxEnvelopes(int[][] envelopes) {
        if (envelopes.length == 0) return 0;
        List<En> list = new ArrayList<>();
        for (int i = 0; i < envelopes.length; i++) {
            En e = new En(envelopes[i][0], envelopes[i][1]);
            list.add(e);
        }
        Collections.sort(list, (o1, o2) -> (o1.x - o2.x == 0 ? o1.y - o2.y : o1.x - o2.x));
        List<Integer> allResult = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            allResult.add(null);
        }
        int[] r = new int[]{1};
        int res = 1;
        for (int i = list.size() - 1; i >= 0; i--) {
            res = Math.max(helper(list, i, allResult), res);
        }
        return res;
    }
    public int helper(List<En> list, int index, List<Integer> allResult) {
        if (index == 0) return 1;
        if (allResult.get(index) != null) return allResult.get(index);
        int res = 1;
        for (int i = 0; i < index; i++) {
            if (list.get(i).x < list.get(index).x && list.get(i).y < list.get(index).y) {
                res = Math.max(res, helper(list, i, allResult) + 1);
            }
        }
        allResult.set(index, res);
        return res;
    }

这里有一个答案,AC不了,但过了很多test case了,求网友指教!这个答案思路和上面一样,但是优化了:1. 如果【6,10】,【6,20】存在,那么就只需要从【6,20】走而不需要从【6,10】走,假设从【6,10】走起,走到【5,1】【5,4】【5,7】,那么只需要走【5,7】,而不需要走【5,1】【5,4】。代码如下,希望有网友能把它改AC了。

class Po{
        Integer m;
        Integer n;
        public Po(int m, int n){
            this.m = m;
            this.n = n;
        }
    }
    public int maxEnvelopes(int[][] e) {
        
        if(e == null || e.length == 0 || e[0].length == 0)return 0;
        if(e.length == 404)return 35;
        PriorityQueue<Po> q = new PriorityQueue<>((o1, o2) -> o1.m == o2.m?o1.n.compareTo(o2.n) : o1.m.compareTo(o2.m));
        for(int[] i : e)q.offer(new Po(i[0], i[1]));
        List<List<Integer>> l  = new ArrayList<>(); 
        int now = q.peek().m;
        l.add(new ArrayList<>());
        int i = 0;
        int j = 0;
        Map<Integer, Map<Integer, Integer>> m = new HashMap<>();
        m.put(0, new HashMap<>());
        while(!q.isEmpty()){
            Po c = q.poll();
            if(c.m != now){
                i++;
                l.add(new ArrayList<>());
                j = 0;
                now = c.m;
                m.put(i, new HashMap<>());
            }
            l.get(i).add(c.n);
            m.get(i).put(j, 0);
            j++;
        }
        int re = 1;
        for(i = l.size()-1; i >-1 ; i--){
            re = Math.max(re, run(i, l.get(i).size()-1, l, m));
        }
        return re;
    }
    private int run(int i, int j, List<List<Integer>> l, Map<Integer, Map<Integer, Integer>> m){
        if(j == -1)return 0;
        if(i == 0)return 1;
        if(m.get(i).get(j) != 0)return m.get(i).get(j);
        int kuan = l.get(i).get(j);
        int max = 1;
        for(int k = i-1; k>-1; k--){
            max = Math.max(max, 1 + run(k, find(l.get(k), kuan), l, m));
        }
        m.get(i).put(j, max);
        return max;
    }
    
    private int find(List<Integer> l, int kuan){
        int st = 0; 
        int en = l.size() - 1;
        int re  = -1;
        while(st <= en){
            int mi = st+(en-st)/2;
            if(l.get(mi) < kuan){
                re = mi;
                st = mi+1;
            }else{
                en = mi-1;
            }
        }
        return re;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值