俄罗斯套娃信封问题

567 篇文章

已下架不支持订阅

题目来源

354. 俄罗斯套娃信封问题 - 力扣(LeetCode)

本题要求信封套信封,且外部的信封的宽、高必须都大于内部的信封的宽、高,问最多能套几个。

首先,我们很容易想到,将所有信封按照宽度升序,这样就可以保证只看宽度的话,排序靠前的信封可以被排序靠后的信封套进去。

真的是这样吗?

如果有两个宽度相同的信封,那么它们就无法嵌套。

因此,我们需要排除掉宽度相同的情况。

一种方案是dfs,比如宽度有 [1,2,3,3,4,5,5,5]

则宽度上一共有:2*3=6种嵌套方案,即不看宽度唯一的,那么只剩下[3,3,5,5,5],而重复的宽度的高度可能不同,因此这里需要求包含重复情况组合。

但是这种方案非常麻烦,也浪费性能。

有一种更好的方案,那就是宽度重复的情况不用管,我们只需要将宽度相同的信封的高度从大到小排序即可。

原因是,信封嵌套,不经要求宽度内小外大,高度也要求内小外大,因此如果两个信封宽度相同,而它们的高度降序的话,则排序靠后的信封也无法套进前面的信封。

因此,我们首先需要将,信封按照宽度升序,对于宽度相同的信封,则按照高度降序。

那么宽度一维就搞定,接下来就是求高度一维的最长递增子序列了,而关于最长递增子序列的求解请看这个博客

已下架不支持订阅

### 俄罗斯套娃信封问题的C语言实现与解决方案 俄罗斯套娃信封问题是一个经典的动态规划问题,目标是找到最多可以嵌套信封数量。每个信封由宽度和高度组成,只有当一个信封的宽度和高度都严格小于另一个信封时,它才能被嵌套。 以下是该问题的一个C语言实现方案: #### 算法思路 1. 首先对信封按照宽度升序排序,如果宽度相同,则按照高度降序排序[^1]。 2. 排序后的问题转化为寻找最长递增子序列(LIS)问题,可以通过动态规划或二分查找结合贪心算法来解决。 3. 动态规划的时间复杂度为 \(O(n^2)\),而使用二分查找优化后的时间复杂度为 \(O(n \log n)\)。 #### C语言代码实现 以下是一个基于二分查找优化的C语言实现: ```c #include <stdio.h> #include <stdlib.h> // 定义信封结构体 typedef struct { int width; int height; } Envelope; // 比较函数,用于qsort排序 int compare(const void *a, const void *b) { Envelope *envelopeA = (Envelope *)a; Envelope *envelopeB = (Envelope *)b; if (envelopeA->width == envelopeB->width) { return envelopeB->height - envelopeA->height; // 如果宽度相同,按高度降序排列 } return envelopeA->width - envelopeB->width; // 按宽度升序排列 } // 二分查找函数 int binarySearch(int *arr, int left, int right, int target) { while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] < target) { left = mid + 1; } else { right = mid - 1; } } return left; } // 主函数 int maxEnvelopes(Envelope *envelopes, int envelopesSize) { if (envelopesSize == 0) return 0; // 对信封进行排序 qsort(envelopes, envelopesSize, sizeof(Envelope), compare); // 使用二分查找求解最长递增子序列 int *dp = (int *)malloc(sizeof(int) * envelopesSize); int length = 0; for (int i = 0; i < envelopesSize; ++i) { int pos = binarySearch(dp, 0, length - 1, envelopes[i].height); if (pos >= length) { dp[length++] = envelopes[i].height; } else { dp[pos] = envelopes[i].height; } } free(dp); return length; } int main() { // 示例输入 Envelope envelopes[] = {{5, 4}, {6, 4}, {6, 7}, {2, 3}}; int envelopesSize = sizeof(envelopes) / sizeof(envelopes[0]); // 调用函数并输出结果 int result = maxEnvelopes(envelopes, envelopesSize); printf("最多可以嵌套信封数量: %d\n", result); return 0; } ``` #### 代码说明 1. **排序规则**:信封按照宽度升序排列,若宽度相同则按照高度降序排列。这样可以确保在处理高度时不会出现宽度相等的情况[^1]。 2. **二分查找**:通过二分查找优化动态规划中的状态转移,将时间复杂度从 \(O(n^2)\) 降低到 \(O(n \log n)\)。 3. **动态数组 `dp`**:存储当前最长递增子序列的最小可能尾部值。 #### 时间与空间复杂度分析 - 时间复杂度:排序的时间复杂度为 \(O(n \log n)\),二分查找的时间复杂度也为 \(O(n \log n)\),因此总时间复杂度为 \(O(n \log n)\)。 - 空间复杂度:需要额外的空间存储排序后的信封和动态数组 `dp`,空间复杂度为 \(O(n)\)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员阿甘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值