523. 连续的子数组和 同余定理,前缀和,set

博客围绕“连续的子数组和”问题展开,给出题目,即根据特定条件判断能否从二进制字符串下标 0 移动到最后一位。介绍两种解法,解法一利用前缀和性质与同余定理,避免超时;解法二为暴力解法,但会超时。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

523. 连续的子数组和 同余定理,前缀和

题目:

给你一个下标从 0 开始的二进制字符串 s 和两个整数 minJump 和 maxJump 。一开始,你在下标 0 处,且该位置的值一定为 ‘0’ 。当同时满足如下条件时,你可以从下标 i 移动到下标 j 处:

i + minJump <= j <= min(i + maxJump, s.length - 1) 且
s[j] == ‘0’.
如果你可以到达 s 的下标 s.length - 1 处,请你返回 true ,否则返回 false 。

解法一:

区间和:

由前缀和的性质,preSum[j] - preSum[i]可以得到 (i+1) ~ j 区间内的和。

余数等于k:

作判断时需用到同余定理,不然会超时。

同余定理总结下:

  • (a+b)mod n = ((a mod n)+(b mod n)) mod n
  • (a-b) mod n = ((a mod n) - (b mod n)) mod n
  • ab mod n = ((a mod n) (b mod n) mod n

(a - b)mod n = 0 -> a mod n = b mod n

于是我们可以用上最后一条的性质,从i = 2 开始循环,每次插入preSum[i-2]%k到容器中,并对preSum[i]%k作判断,天然的能保证preSum[i]%k是与i-2及之前的前缀和作判断即:

((preSum[i] - preSum[j]) mod k = 0 -> preSum[i] mod k == preSum[j] mod k == 0或t, j = 0~i-2 ),这样就可以不用map存键值对,直接用set存preSum就好。同时我们还可以边求前缀和边作判断。

class Solution {
public:
    bool checkSubarraySum(vector<int>& nums, int k) {
        const int len = nums.size();
        int preSum[len+2];
        preSum[0] = 0, preSum[1] = nums[0]%k;
        for(int i = 2; i <= len; i++) {
            preSum[i] = (preSum[i-1] + nums[i-1])%k;
            set.insert(preSum[i-2]);
            if(set.count(preSum[i]%k))
                return true;
        }
        return false;
    }
private:
    unordered_set<int> set;
};

解法二:

暴力解法,感觉还是挺简练的,虽然会超时:

class Solution {
public:
    bool checkSubarraySum(vector<int>& nums, int k) {
        const int len = nums.size();
        int preSum[len+2];
        preSum[0] = 0;
        for(int i = 1; i <= len; i++)
            preSum[i] = (preSum[i-1] + nums[i-1])%k;
        for(int i = 0, j = len; j != 2 ; i++) {
            if(i == j-1 && i) j--, i = 0;//有j = 2的情况。
            if((preSum[j]-preSum[i])%k == 0)
                return true;
        }
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值