Article / 文章
LeetCode 第330题:按要求补齐数组
给定一个已排序的正整数数组 nums,和一个正整数 n。从 [1, n] 区间内选取任意个数字补充到 nums 中,使得 [1, n] 区间内的任何数字都可以用 nums 中某几个数字的和来表示。 请输出满足上述要求的最少需要补充的数字个数。
📖 文章摘要
本文详细解析LeetCode第330题“按要求补齐数组”,这是一道困难级别的贪心算法问题。文章提供了贪心算法的解法,包含C#、Python、C++三种语言实现,配有详细的算法分析和性能对比。适合想要提升贪心算法应用能力的程序员。
核心知识点: 贪心算法、区间合并、数学
难度等级: 困难
推荐人群: 具有扎实算法基础,想要提升贪心算法应用能力的程序员
题目描述
给定一个已排序的正整数数组 nums,和一个正整数 n。从 [1, n] 区间内选取任意个数字补充到 nums 中,使得 [1, n] 区间内的任何数字都可以用 nums 中某几个数字的和来表示。
请输出满足上述要求的最少需要补充的数字个数。
示例
示例 1:
输入: nums = [1,3], n = 6
输出: 1
解释:
根据 nums 里现有的组合 [1], [3], [1,3],可以得出 1, 3, 4。
现在如果我们将 2 添加到 nums 中, 组合变为: [1], [2], [3], [1,3], [2,3], [1,2,3]。
其和可以表示数字 1, 2, 3, 4, 5, 6,能够覆盖 [1, 6] 区间里所有的数。
所以我们最少需要添加一个数字。
示例 2:
输入: nums = [1,5,10], n = 20
输出: 2
解释: 我们需要添加 [2, 4]。
示例 3:
输入: nums = [1,2,2], n = 5
输出: 0
提示
- 1 <= nums.length <= 1000
- 1 <= nums[i] <= 10^4
- nums 按升序排列
- 1 <= n <= 2^31 - 1
解题思路
方法:贪心算法
使用贪心策略,维护当前可以表示的数字范围。
关键点:
- 维护当前可以表示的数字范围[1, miss)
- 贪心选择下一个需要添加的数字
- 处理数组中的现有数字
- 处理溢出问题
具体步骤:
- 初始化miss为1,表示需要覆盖的最小数字
- 遍历数组,更新可以表示的范围
- 当无法表示miss时,需要添加一个新数字
- 返回添加数字的个数
时间复杂度:O(n) 空间复杂度:O(1)
图解思路
贪心过程分析表
| 当前数组 | miss值 | 可表示范围 | 需要添加的数 |
|---|---|---|---|
| [1,3] | 1 | [1,2) | - |
| [1,3] | 2 | [1,4) | 2 |
| [1,2,3] | 4 | [1,7) | - |
区间合并示意图
初始:[1,2)
添加2:[1,4)
添加3:[1,7)
最终覆盖:[1,7)包含了[1,6]
代码实现
C# 实现
public class Solution {
public int MinPatches(int[] nums, int n) {
int patches = 0;
long miss = 1; // 使用long避免溢出
int i = 0;
while (miss <= n) {
if (i < nums.Length && nums[i] <= miss) {
miss += nums[i];
i++;
} else {
miss += miss;
patches++;
}
}
return patches;
}
}
Python 实现
class Solution:
def minPatches(self, nums: List[int], n: int) -> int:
patches = 0
miss = 1
i = 0
while miss <= n:
if i < len(nums) and nums[i] <= miss:
miss += nums[i]
i += 1
else:
miss += miss
patches += 1
return patches
C++ 实现
class Solution {
public:
int minPatches(vector<int>& nums, int n) {
int patches = 0;
long miss = 1; // 使用long避免溢出
int i = 0;
while (miss <= n) {
if (i < nums.size() && nums[i] <= miss) {
miss += nums[i];
i++;
} else {
miss += miss;
patches++;
}
}
return patches;
}
};
执行结果
C# 实现
- 执行用时:84 ms
- 内存消耗:38.4 MB
Python 实现
- 执行用时:36 ms
- 内存消耗:15.7 MB
C++ 实现
- 执行用时:4 ms
- 内存消耗:11.3 MB
性能对比
| 语言 | 执行用时 | 内存消耗 | 特点 |
|---|---|---|---|
| C# | 84 ms | 38.4 MB | 实现简洁,性能适中 |
| Python | 36 ms | 15.7 MB | 代码最简洁 |
| C++ | 4 ms | 11.3 MB | 性能最优 |
代码亮点
- 🎯 巧妙的贪心策略
- 💡 使用long类型避免溢出
- 🔍 高效的区间合并
- 🎨 代码结构清晰,易于理解
常见错误分析
- 🚫 没有处理整数溢出
- 🚫 贪心策略选择错误
- 🚫 区间更新逻辑错误
- 🚫 边界条件处理不当
解法对比
| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 贪心算法 | O(n) | O(1) | 高效简洁 | 思路不易想到 |
| 动态规划 | O(n^2) | O(n) | 直观易懂 | 效率较低 |
相关题目
- LeetCode 55. 跳跃游戏 - 中等
- LeetCode 45. 跳跃游戏 II - 中等
- LeetCode 1306. 跳跃游戏 III - 中等
📖 系列导航
🔥 算法专题合集 - 查看完整合集
📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新至第330题。
💬 互动交流
感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。
如果这篇文章对你有帮助,请:
- 👍 点个赞,让更多人看到这篇文章
- 📁 收藏文章,方便后续查阅复习
- 🔔 关注作者,获取更多高质量算法题解
- 💭 评论区留言,分享你的解题思路或提出疑问
你的支持是我持续分享的动力!
💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!