i位置为结尾的所有的子数组
[0, i - 1]区间内,有多少个前缀和等于sum[i] - k -> <前缀和, 次数>[0, i - 1]区间内,找有多少个前缀和等于sum[i] - ki位置之前,哈希表里面只保存[0, i - 1]位置的前缀和i位置之前,有多少个前缀和等于sum[i] - kk呢?
hash[0] = 1
int SubarraySum(vector<int>& nums, int k)
{
unordered_map<int, int> hash; // <前缀和, 次数>
hash[0] = 1;
int ret = 0, sum = 0; // 标识前一个位置的前缀和
for(auto& e : nums)
{
sum += e; // 计算当前位置的前缀和
if(hash.count(sum - k))
{
ret += hash[sum - k];
}
hash[sum]++; // 将i位置的前缀和入hash
}
return ret;
}
(a - b) / p = k -> a % p == b % pa % p + p(a % p + p) % pi位置为结尾的所有的子数组
[0, i - 1]区间内,有多少个前缀和的余数等于(sum % k + k) % k -> <前缀和, 次数>[0, i - 1]区间内,找有多少个前缀和的余数等于(sum % k + k) % ki位置之前,哈希表里面只保存[0, i - 1]位置的前缀和的余数i位置之前,有多少个前缀和的余数等于(sum % k + k) % kk呢?
hash[0] = 1
int subarraysDivByK(vector<int>& nums, int k)
{
unordered_map<int, int> hash;// <前缀和余数, 次数>
hash[0] = 1;
int sum = 0, ret = 0; // 用于标记前一个位置的前缀和
for(auto& e : nums)
{
sum += e; // 计算当前位置的前缀和
int tmp = (sum % k + k) % k; // 修正后的余数
if(hash.count(tmp))
{
ret += hash[tmp];
}
hash[tmp]++; // 将i位置的前缀和的余数入hash
}
return ret;
}
问题转化:
[和为k的子数组] -> [和为0的子数组]
思路:前缀和 + 哈希表
i位置为结尾的所有的子数组
[0, i - 1]区间内,有多少个前缀和等于sum -> <前缀和,下标>
细节处理:
i位置之前,哈希表里面只保存[0, i - 1]位置的前缀和(sum, i),如何存?
(sum, i)即可i位置之前,有多少个前缀和等于sumhash[0] = -1i - j
int FindMaxLength(vector<int>& nums)
{
unordered_map<int, int> hash; // <前缀和, 下标>
hash[0] = -1; // 默认有一个前缀和为0的情况
int sum = 0, len = 0; // 标记前一次的前缀和
for(int i = 0; i < nums.size(); i++)
{
sum += nums[i] == 0 ? -1 : 1;
if(hash.count(sum))
{
len = max(len, i - hash[sum]); // 更新最大长度
}
else
{
hash[sum] = i; // 将(sum, i)入hash
}
}
return len;
}
该题就是对**[二维前缀和]**的一个实际应用
左上角/右上角坐标可能会越界

下标的映射关系:

vector<vector<int>> MatrixBlockSum(vector<vector<int>>& mat, int k)
{
int row = mat.size(), col = mat[0].size();
// 预处理前缀和数组
vector<vector<int>> dp(row + 1, vector<int>(col + 1));
for(int i = 1; i <= row; i++)
{
for(int j = 1; j <= col; j++)
{
// 下标映射关系 dp[x, y] -> mat[x - 1][y - 1]
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] \
- dp[i - 1][j - 1] + mat[i - 1][j - 1];
}
}
// 使用前缀和数组
vector<vector<int>> ret(row, vector<int>(col));
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
// 下标映射关系 ret[x][y] -> dp[x + 1][y + 1]
int x1 = max(0, i - k) + 1;
int y1 = max(0, j - k) + 1;
int x2 = min(row - 1, i + k) + 1;
int y2 = min(col - 1, j + k) + 1;
ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] \
- dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1];
}
}
return ret;
}