首页 > 编程知识 正文

13…(2n-1)(2n)…42逆序数,同余的性质

时间:2023-05-05 23:41:31 阅读:134013 作者:207

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 nab 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; }};

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。