354、俄罗斯套娃信封问题

  1. 354、俄罗斯套娃信封问题
    1. 示例:
  • 题解——最长递增子序列的二维问题。
    1. 1、动态规划求最长递增子序列
  • 354、俄罗斯套娃信封问题

    给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

    请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。

    • 说明:
      不允许旋转信封。

    示例:

    输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
    输出: 3 
    解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
    

    题解——最长递增子序列的二维问题。

    1、动态规划求最长递增子序列

    • 预处理
      • 先对宽度 w 进行升序排序,如果遇到 w 相同的情况,则按照高度 h 降序排序。之后把所有的 h 作为一个数组,在这个数组上计算 LIS 的长度就是答案。
    • 代码
    // java
    class Solution {
        public int maxEnvelopes(int[][] envelopes) {
            // 首先按照第一个纬度递增,其次第二个纬度递减,排序
            Arrays.sort(envelopes, new Comparator<int[]>() {
                public int compare(int[] a,int[] b) {
                    if (a[0] == b[0]) {
                        return b[1] - a[1];
                    } else {
                        return a[0] - b[0];
                    }
                }
            });
            // 提取第二纬度的数字,求最长的递增子序列
            int[] secondDim = new int[envelopes.length];
            for (int i = 0;i < envelopes.length;i++) {
                secondDim[i] = envelopes[i][1];
            }
            return lengthOfLIS(secondDim);
        }
    
        private int lengthOfLIS(int[] nums) {
            int[] dp = new int[nums.length];
            int len = 0;
            for (int num : nums) {
                // 查找位置,已存在的值的位置,或者需要插入的位置
                int i = Arrays.binarySearch(dp,0,len,num);
                // 插入位置为负数,需要计算成正数
                if (i < 0) {
                    // x = (-(insertpoint) - 1) => insertpoint = -(x+1)
                    i = - (i + 1);
                }
                dp[i] = num;// 将值插入,替换掉原来的值????
                // 只有插入位置为最后一个位置时,计数+1
                if (i == len) {
                    len++;
                }
            }
            // 返回递增序列
            return len;
        }
    }
    // LIS的自己实现
    /* 返回 nums 中 LIS 的长度 */
    public int lengthOfLIS(int[] nums) {
        int piles = 0, n = nums.length;
        int[] top = new int[n];
        for (int i = 0; i < n; i++) {
            // 要处理的扑克牌
            int poker = nums[i];
            int left = 0, right = piles;
            // 二分查找插入位置
            while (left < right) {
                int mid = (left + right) / 2;
                if (top[mid] >= poker)
                    right = mid;
                else
                    left = mid + 1;
            }
            if (left == piles) piles++;
            // 把这张牌放到牌堆顶
            top[left] = poker;
        }
        // 牌堆数就是 LIS 长度
        return piles;
    }
    
    // 作者:labuladong
    // 链接:https://leetcode-cn.com/problems/russian-doll-envelopes/solution/zui-chang-di-zeng-zi-xu-lie-kuo-zhan-dao-er-wei-er/
    
    • 10ms
    public class Solution {
    
        public int maxEnvelopes(int[][] envelopes) {
    
            int len = envelopes.length;
            if (len < 2) {
                return len;
            }
    
            Arrays.sort(envelopes, new Comparator<int[]>() {
                @Override
                public int compare(int[] envelope1, int[] envelope2) {
                    if (envelope1[0] != envelope2[0]) {
                        return envelope1[0] - envelope2[0];
                    }
                    return envelope2[1] - envelope1[1];
                }
            });
    
    
            int[] tail = new int[len];
            tail[0] = envelopes[0][1];
    
            // end 表示有序数组 tail 的最后一个已经赋值元素的索引
            int end = 0;
    
            for (int i = 1; i < len; i++) {
                int target = envelopes[i][1];
                // 先判断是否大雨最后一个元素,是则直接赋值,减少二分搜索的次数
                if (target > tail[end]) {
                    end++;
                    tail[end] = target;
                } else {
                    int left = 0;
                    int right = end;
    
                    while (left < right) {
                        int mid = (left + right) >>> 1;
                        if (tail[mid] < target) {
                            left = mid + 1;
                        } else {
                            right = mid;
                        }
                    }
                    tail[left] = target;
                }
            }
            // 长度为最后一个元素下标+1
            return end + 1;
        }
    }
    

    转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

    💰

    Title:354、俄罗斯套娃信封问题

    Count:856

    Author:攀登

    Created At:2020-07-26, 00:19:44

    Updated At:2024-06-15, 15:52:32

    Url:http://jiafeimao-gjf.github.io/2020/07/26/354%E3%80%81%E4%BF%84%E7%BD%97%E6%96%AF%E5%A5%97%E5%A8%83%E4%BF%A1%E5%B0%81%E9%97%AE%E9%A2%98/

    Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

    ×

    Help us with donation