LeetCode354. 俄罗斯套娃信封问题

题目连接

https://leetcode-cn.com/problems/russian-doll-envelopes/

解题思路

前言
根据题目的要求,如果我们选择了 kk 个信封,它们的的宽度依次为 w0 ,w1 ,⋯,wk−1 ,高度依次为 h0 ,h1 ,⋯,hk−1 ,那么需要满足:

	w0 < w1 << wk−1 
	h0 < h1 << hk−1

同时控制 w 和 h 两个维度并不是那么容易,因此我们考虑固定一个维度,再在另一个维度上进行选择。例如,我们固定 w 维度,那么我们将数组envelopes 中的所有信封按照 w 升序排序。这样一来,我们只要按照信封在数组中的出现顺序依次进行选取,就一定保证满足:w0 < w1 < ⋯ < wk−1 了。然而小于等于 ≤ 和小于 < 还是有区别的,但我们不妨首先考虑一个简化版本的问题:

	如果我们保证所有信封的 w 值互不相同,那么我们可以设计出一种得到答案的方法吗?

在 w 值互不相同的前提下,小于等于 ≤ 和小于 < 是等价的,那么我们在排序后,就可以完全忽略 w 维度,只需要考虑 h 维度了。此时,我们需要解决的问题即为:

	给定一个序列,我们需要找到一个最长的子序列,使得这个子序列中的元素严格单调递增,即上面要求的:
	h0 < h1 << hk−1

那么这个问题就是经典的「最长严格递增子序列」问题了,读者可以参考 LeetCode300题解 。最长严格递增子序列的详细解决方法属于解决本题的前置知识点,不是本文分析的重点,因此这里不再赘述。

当我们解决了简化版本的问题之后,我们来想一想使用上面的方法解决原问题,会产生什么错误。当 w 值相同时,如果我们不规定 h 值的排序顺序,那么可能会有如下的情况:

排完序的结果为 [(w, h)] = [(1, 1), (1, 2), (1, 3), (1, 4)],由于这些信封的 w 值都相同,不存在一个信封可以装下另一个信封,那么我们只能在其中选择 1 个信封。然而如果我们完全忽略 w 维度,剩下的 h 维度为 [1, 2, 3, 4],这是一个严格递增的序列,那么我们就可以选择所有的 4 个信封了,这就产生了错误。

因此,我们必须要保证对于每一种 w 值,我们最多只能选择 1 个信封。

我们可以将 h 值作为排序的第二关键字进行降序排序,这样一来,对于每一种 w 值,其对应的信封在排序后的数组中是按照 h 值递减的顺序出现的,那么这些 h 值不可能组成长度超过 1 的严格递增的序列,这就从根本上杜绝了错误的出现。

因此我们就可以得到解决本题需要的方法:

  • 首先我们将所有的信封按照 w 值第一关键字升序、h 值第二关键字降序进行排序
  • 随后我们就可以忽略 w 维度,求出 h 维度的最长严格递增子序列,其长度即为答案。
class Solution {
public:
    int maxEnvelopes(vector<vector<int>>& envelopes) {
        if(envelopes.empty()) return 0;
        // 排序,C++11的方式重载sort(暂时不会)
        sort(envelopes.begin(), envelopes.end(), [](const auto& e1, const auto& e2) {
            return e1[0] < e2[0] || (e1[0] == e2[0] && e1[1] > e2[1]);
        });

		// 直接将最长严格递增子序列的代码copy上
        const int N = 2505;
    	int len = 1, d[N];
    	d[len] = envelopes[0][1]; // 初始化d[1]为nums[0],因为若数组长度不为0,则len至少为1 
    	for(int i = 1;i < envelopes.size(); i++) {
    		if(d[len] < envelopes[i][1]) d[++len] = envelopes[i][1];
    		else {
    			int l = 1, r = len, m, pos = 0; // pos是为了保证当全部数都比nums[i]大时,将d[pos+1]赋值为nums[i] 
    			while(l <= r) {
    				m = l + r >> 1;
    				if(d[m] < envelopes[i][1]) {
    					pos = m;
    					l = m + 1;
					}
					else {
						r = m - 1;
					}
				}
				d[pos + 1] = envelopes[i][1];
			}
		}
        return len;

    }
};

总结

可以获取的技巧为:
通过将第二关键字降序排列,再通过“最长严格递增子序列”算法求长度的时候,可以避免第一关键字不严格单调的情况。从而求出两个关键字都严格单调的最长长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不牌不改

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值