Go 力扣题解《354.俄罗斯套娃信封问题》(上)笔记 05 | 青训营

119 阅读1分钟

本篇笔记是笔者在第六届字节跳动青训营期间使用 Go 语言解决了力扣《354.俄罗斯套娃信封问题》【困难】后,对官方题解解法二的理解

1. 题干

给你一个二维整数数组 envelopes ,其中 envelopes[i] = [wi, hi] ,表示第 i 个信封的宽度和高度。

当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。

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

注意:不允许旋转信封。

2.案例官方题解方法二

· 代码如下:

func maxEnvelopes(envelopes [][]int) int {
    sort.Slice(envelopes, func(i, j int) bool {
        a, b := envelopes[i], envelopes[j]
        return a[0] < b[0] || a[0] == b[0] && a[1] > b[1]
    })
​
    f := []int{}
    for _, e := range envelopes {
        h := e[1]
        if i := sort.SearchInts(f, h); i < len(f) {
            f[i] = h
        } else {
            f = append(f, h)
        }
    }
    return len(f)
}
​
作者:力扣官方题解
链接:https://leetcode.cn/problems/russian-doll-envelopes/solutions/633231/e-luo-si-tao-wa-xin-feng-wen-ti-by-leetc-wj68/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
​
3.题解分析

· 首先此题明显需要使用动态规划进行求解,因此我们首先需要找出子问题是什么?

  • 较大的信封才能将宽和高比它小的信封套下,即使得套进的信封数目更新(+1)
  • 子问题涉及到的属性有:宽、高和当前长度,子问题的规模参数(即何为较小问题由信封的宽和高共同决定)

· 接下来,我们解决问题的顺序应该是从小往大,推出:

  • 将信封按照大小排序,如何排序?

    • 由于信封大小有两个维度的参数————宽和高,因此我们其实没有办法实现一种排序,使其保证让后面的信封一定比前面的信封大(可能存在无法判定谁大的情况,比如信封[1, 3]和信封[2, 2])

    • 但我们可以退一步:即使我们可以让任意两个信封都可以判断大小,那也仍然会出现某两个信封相同的情况,它们虽然在排序后排列在一起,但彼此不可以嵌套,也不会影响答案

    • 受到启发,我们没有必要真正地花心思在比较信封大小上面,只需要保证:A信封序号为i(i > 0)

      • 若B信封序号为j,且B信封比A信封小(以B信封为最外层的问题是以A信封为最外层的子问题)

      故降低维度,比如仅仅使用宽进行排序,从前往后进行遍历,在更新时仅需要比较高的大小即可,即高大了,即信封大,就可以满足上面的要求,但注意,当宽相等的时候,比如[1, 2], [1, 3]信封,我们通过这种方式可能会误判[1,3]可以装下[1,2]信封,故为了完全避免这种可能,我们需要在排序的时候,若宽相等,则按照高降序排列,这样就可以完整解决排序的问题了,进而开始研究子问题的更新了