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)
  • 贪心选择下一个需要添加的数字
  • 处理数组中的现有数字
  • 处理溢出问题

具体步骤:

  1. 初始化miss为1,表示需要覆盖的最小数字
  2. 遍历数组,更新可以表示的范围
  3. 当无法表示miss时,需要添加一个新数字
  4. 返回添加数字的个数

时间复杂度: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 性能最优

代码亮点

  1. 🎯 巧妙的贪心策略
  2. 💡 使用long类型避免溢出
  3. 🔍 高效的区间合并
  4. 🎨 代码结构清晰,易于理解

常见错误分析

  1. 🚫 没有处理整数溢出
  2. 🚫 贪心策略选择错误
  3. 🚫 区间更新逻辑错误
  4. 🚫 边界条件处理不当

解法对比

解法 时间复杂度 空间复杂度 优点 缺点
贪心算法 O(n) O(1) 高效简洁 思路不易想到
动态规划 O(n^2) O(n) 直观易懂 效率较低

相关题目


📖 系列导航

🔥 算法专题合集 - 查看完整合集

📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新至第330题。


💬 互动交流

感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。

如果这篇文章对你有帮助,请:

  • 👍 点个赞,让更多人看到这篇文章
  • 📁 收藏文章,方便后续查阅复习
  • 🔔 关注作者,获取更多高质量算法题解
  • 💭 评论区留言,分享你的解题思路或提出疑问

你的支持是我持续分享的动力!

💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!