0354. Russian Doll Envelopes (H)

Russian Doll Envelopes (H)

题目

You are given a 2D array of integers envelopes where envelopes[i] = [wi, hi] represents the width and the height of an envelope.

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.

Return the maximum number of envelopes can you Russian doll (i.e., put one inside the other).

Note: You cannot rotate an envelope.

Example 1:

Input: envelopes = [[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]).

Example 2:

Input: envelopes = [[1,1],[1,1],[1,1]]
Output: 1

Constraints:

  • 1 <= envelopes.length <= 5000
  • envelopes[i].length == 2
  • 1 <= wi, hi <= 10^4

题意

给定n个信封,每个信封有高度和宽度,如果一个信封a的高度宽度都小于另一个信封b的高度宽度,则可以进行套娃操作,将a塞入b,问最多可以进行几次套娃操作。

思路

本质上就是LIS问题。对数组按照宽从小到大排序,如果相同则按照高从大到小排序(关键!),保证数组中后一个信封的宽都比前一个大,且当相邻信封的宽相等时,前一个信封的高一定比后一个信封的大(用于排除等宽信封不能套娃的特殊情况),这样就可以对每个信封的高组成的序列做一次最长递增子序列问题求解来得到答案。


代码实现

Java

动态规划

class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        int ans = 1;
        int[] dp = new int[envelopes.length];

        Arrays.sort(envelopes, (a, b) -> a[0] != b[0] ? a[0] - b[0] : b[1] - a[1]);
        dp[0] = 1;
        for (int i = 1; i < dp.length; i++) {
            for (int j = 0; j < i; j++) {
                dp[i] = Math.max(dp[i], envelopes[i][1] > envelopes[j][1] ? dp[j] + 1 : 1);
            }
            ans = Math.max(ans, dp[i]);
        }

        return ans;
    }
}

动态规划二分优化

class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        List<Integer> list = new ArrayList<>();

        // 关键:当宽度相同时,按照高度递减排序
        Arrays.sort(envelopes, (a, b) -> a[0] != b[0] ? a[0] - b[0] : b[1] - a[1]);
      
        for (int i = 0; i < envelopes.length; i++) {
            int pos = findPos(list, envelopes[i][1]);
            if (pos == list.size()) {
                list.add(envelopes[i][1]);
            } else {
                list.set(pos, envelopes[i][1]);
            }
        }

        return list.size();
    }

    private int findPos(List<Integer> list, int target) {
        int left = 0, right = list.size() - 1;
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            if (list.get(mid) < target) {
                left = mid + 1;
            } else if (list.get(mid) > target) {
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return left;
    }
}
posted @ 2021-03-30 19:31  墨云黑  阅读(46)  评论(0编辑  收藏  举报