每日算法系列【LeetCode 330】按要求补齐数组

简介: 每日算法系列【LeetCode 330】按要求补齐数组

题目描述

给定一个已排序的正整数数组 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

题解

首先这题没有说数据范围,根据正解的时间复杂度,推测出 nums.length 的大小在 1e5 左右,而 n 的大小在 int 的最大值左右。

而不考虑数据范围,我刚开始的想法是,首先考虑简化问题:用 nums 数组中的数字可以表示出多少个不同的正整数?这可以用动态规划来解决,令 dp[S][i] 表示用前 i 个数凑出和 S 是否可行,那么状态转移方程就是:dp[S][i] = dp[S-nums[i]][i-1] || dp[S][i-1] 。然后遍历 dp[i][nums.length-1] ,如果发现等于 0 ,就说明 nums 数组无法凑出 i 这个和,于是新增加一个数 i ,并且将 [i, 2i)中的所有 dp 值都改成 1,直到 [1, n] 全部被覆盖了。后来看了才发现,我弱智了,这样不仅没必要,而且 n 太大会炸裂。

正解很简单。首先题目中有个词“已排序”,其实不是很重要,没排序的话我排个序也不怎么耗时间。那排完序怎么办呢,思路还是刚刚的思路,只是不用动态规划了。

试想从最小的 1 开始,如果 1 不在数组里,那一定要补上一个 1 的,然后 [1, 2) 范围里的数都可以被表示出来了。然后看下一个数,如果大于 2 ,那么 2 是没有办法通过数组里的数表示出来的,因为比它小的数只能凑出 [1, 2) ,所以 2 也要补上。如果下一个数小于等于 2 ,那么我们可以利用目前的数凑出 [1, 4) 里面的数,然后继续往下遍历,直到能够凑出 [1, n+1) 里面的数。

一般情况下,如果遍历到 nums[i-1] 时,可以表示出 [1, S) 范围内的数,那么如果 nums[i] > S ,那么需要补上 S ,并且可表示范围更新为 [1, 2S),然后继续看 nums[i] ;否则的话可表示范围更新为 [1, S+nums[i]) ,然后看 nums[i+1] 就行了。

这样就比原来的思路简化了很多了,那么时间复杂度怎么样呢?因为 S 每次更新有两种情况,要么乘以 2 ,要么加上了 nums[i] ,所以最终时间复杂度是  。

代码

c++

class Solution {
public:
    int minPatches(vector<int>& nums, int n) {
        int len = nums.size(), idx = 0, res = 0;
        long long r = 1;
        while (r <= n) {
            if (idx < len && nums[idx] <= r) {
                r += nums[idx++];
            } else {
                res++;
                r += r;
            }
        }
        return res;
    }
};

python


class Solution:
    def minPatches(self, nums: List[int], n: int) -> int:
        length = len(nums)
        idx = res = 0
        r = 1
        while r <= n:
            if idx < length and nums[idx] <= r:
                r += nums[idx]
                idx += 1
            else:
                res += 1
                r += r
        return res


目录
打赏
0
0
0
0
14
分享
相关文章
|
18天前
|
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
32 7
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
79 23
|
5月前
|
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
66 0
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
95 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
5月前
|
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
56 2
|
5月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
42 4
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
63 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
5月前
|
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
45 0
Leetcode第三十三题(搜索旋转排序数组)
|
5月前
|
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
102 0