赞
踩
方法1: class Solution { public: int subarraySum(vector<int>& nums, int k) { unordered_map<int, int> mp; int pre = 0; int cnt = 0; vector<int> preSum(nums.size() + 1); preSum[0] = 0; // key1:包含0个元素(不选取任何元素)时和为0 mp[0] = 1; // key2:和为0的个数(不选取任何元素)至少有1个 for (int i = 1; i <= nums.size(); i++) { preSum[i] += nums[i - 1] + preSum[i - 1]; if (mp.find(preSum[i] - k) != mp.end()) { cnt += mp[preSum[i] - k]; } if (mp.find(preSum[i]) != mp.end()) { mp[preSum[i]]++; } else { mp[preSum[i]] = 1; } } return cnt; } }; 方法2: class Solution { public: int subarraySum(vector<int>& nums, int k) { unordered_map<int, int> mp; int pre = 0; int cnt = 0; for (int i = 0; i < nums.size(); i++) { pre += nums[i]; // check itself if (pre == k) { cnt++; } // check before: check "pre - k" whether exist if (mp.find(pre - k) != mp.end()) { cnt += mp[pre - k]; } // add "pre" to map if (mp.find(pre) != mp.end()) { mp[pre]++; } else { mp[pre] = 1; } } return cnt; } };
class Solution { public: bool checkSubarraySum(vector<int>& nums, int k) { if (nums.size() < 2) { return false; } vector<int> pres(nums.size(), 0); int pre = 0; for (int i = 0; i < nums.size(); i++) { pre += nums[i]; pres[i] = pre; } for (int i = 0; i < nums.size(); i++) { for (int j = i + 1; j < nums.size(); j++) { // key1, j = i + 1 if (k == 0) { // key2 if (pres[j] == 0) { return true; } if ((pres[j] - pres[i] == 0) && (j - i >= 2)) { // key3 return true; } } else { if (pres[j] % k == 0) { return true; } if (((pres[j] - pres[i]) % k) == 0 && (j - i >= 2)) { // key3 return true; } } } } return false; } };
思路2:
Sum[i, j] = preSum[i] - preSum[j - 1]
目标:(preSum[i] - preSum[j - 1] % k) == 0 等价于 (preSum[i] % k ) == (preSum[j - 1] % k)
另外,由于i > j所以i - (j - 1) >= 2,这个是索引下标的条件;
用hash表保存余数和对应的索引下标!!!
class Solution { public: bool checkSubarraySum(vector<int>& nums, int k) { if (nums.size() < 2) { return false; } int N = nums.size(); if (k == 0) { for (int i = 1; i < N; i++) { if (nums[i] == 0 && nums[i] == nums[i - 1]) { return true; } } return false; } unordered_map<int, vector<int>> mp; // 余数,出现的索引 mp[0].push_back(0); // key1, 默认在数组前面添加一个0元素 int sum = 0; for (int i = 1; i <= N; i++) { // 注意索引要从1开始遍历,0已结被默认添加了 if (nums[i - 1] < 0) { nums[i - 1] = k - (abs(nums[i - 1]) % k); } sum += nums[i - 1]; int res = sum % k; if (mp.find(res) != mp.end()) { for (auto it : mp[res]) { if (i - it >= 2) { // key2 return true; } } } mp[res].push_back(i); } return false; } };
方法1:暴力算法,会超时
class Solution { public: int subarraysDivByK(vector<int>& A, int K) { if (A.size() == 0) { return 0; } vector<int> pres(A.size() + 1); for (int i = 1; i <= A.size(); i++) { pres[i] = pres[i - 1] + A[i - 1]; } int count = 0; for (int i = 0; i <= A.size(); i++) { for (int j = i + 1; j <= A.size(); j++) { if ((pres[j] - pres[i]) % K == 0) { count++; } } } return count; } };
方法2 思路:通过判断两个位置的余数是否相等,从而判断他们的子区间的和是否为K的倍数。[523. 连续的子数组和]更简单一点,只要找出一个即可。
本题将负数进行同余预处理。如给出:[2,-2,2,-4],K=6。同余处理之后得到[2,4,2,2],K=6,求余数之后为[0,2,0,2,4] (第一个0是做前缀和时总是会添加的数), 余数相等的有两对,答案是2.
class Solution { public: int subarraysDivByK(vector<int>& A, int K) { if (A.size() == 0) { return 0; } unordered_map<int, int> mp; // key是余数,value是个数 mp[0] = 1; // 对于前缀和相当于在数组头插入了个0元素 int sum = 0; int count = 0; for (int i = 0; i < A.size(); i++) { A[i] = (A[i] < 0) ? (K - abs(A[i]) % K) : A[i]; // 需要做同余处理,否则会漏掉一部分组合 sum += A[i]; int res = sum % K; if (mp.find(res) != mp.end()) { count += mp[res]; mp[res]++; } else { mp[res] = 1; } } return count; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。