leetcode-1785-构成特定和需要添加的最少元素

给你一个整数数组 nums ,和两个整数 limitgoal 。数组 nums 有一条重要属性:abs(nums[i]) <= limit

返回使数组元素总和等于 goal 所需要向数组中添加的 最少元素数量 ,添加元素 不应改变 数组中 abs(nums[i]) <= limit 这一属性。

注意,如果 x >= 0 ,那么 abs(x) 等于 x ;否则,等于 -x

示例 1:

输入:nums = [1,-1,1], limit = 3, goal = -4
输出:2
解释:可以将 -2 和 -3 添加到数组中,数组的元素总和变为 1 - 1 + 1 - 2 - 3 = -4 。

示例 2:

输入:nums = [1,-10,9,1], limit = 100, goal = 0
输出:1

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= limit <= 10^6
  • -limit <= nums[i] <= limit
  • -10^9 <= goal <= 10^9

分析

看到这道题,第一反应就是把nums中的数加起来,然后用加起来的值和goal的差值除以limit即可得到结果。

class Solution {
public:
    int minElements(vector<int>& nums, int limit, int goal) {
        int addnum = 0;
        for(auto num : nums)
            addnum += num;
        int gapnum = goal - addnum;
        return (abs(gapnum) - 1)/abs(limit) + 1;
    }
};

很遗憾只能满足65 / 77 个通过测试用例。原因在于后面的测试用例中nums的和非常大,超出了int所能表示的范围,因此我们还要考虑其他的方式。

为了防止超出范围,我想到了一个方法:

在nums求和的过程中,想办法让和的绝对值小于limit,我们可以通过给这个和加上或者减去limit来实现这个效果,并分别记录加上和减去的次数,这个次数在后面是可以相互抵消的。

依照这个思路可得到如下代码:

class Solution {
public:
    int minElements(vector<int>& nums, int limit, int goal) {
        int addnum = 0;//nums的和(其中加上和减去了多个limit)
        int minustimes = 0;//减limit次数
        int plustimes = 0;//加limit次数
        for(auto num : nums){
            addnum += num;
            if(addnum >= limit){//过大则减
                addnum -= limit;
                ++minustimes;
            }
            if(addnum <= -limit){//过小则加
                addnum += limit;
                ++plustimes;
            }
        }
        int gapnum = goal - addnum;//goal与addnum的差值
        if(gapnum == 0)//正好为0时,可直接返回差值
            return abs(minustimes - plustimes);
        int remaintimes = (abs(gapnum) - 1)/abs(limit) + 1;//加减limit后还需limit的个数
        int totaltimes = 0;//总次数
        if(gapnum > 0){//gapnum大于0时,remaintimes为加的次数
            totaltimes = abs(remaintimes + plustimes - minustimes);
        }else{//gapnum小于0时,remaintimes为减的次数
            totaltimes = abs(remaintimes + minustimes - plustimes);
        }
        return totaltimes;
    }
};

执行用时:88 ms, 在所有 C++ 提交中击败了92.20%的用户

内存消耗:71.6 MB, 在所有 C++ 提交中击败了78.72%的用户

通过测试用例:77 / 77

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值