📝前言说明:
- 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分
- 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
- 文章中的理解仅为个人理解。如有错误,感谢纠错
🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础,python入门基础,C++学习笔记,Linux
🎀CSDN主页 愚润泽
视频
- [974. 和可被 K 整除的子数组](#974. 和可被 K 整除的子数组)
- [525. 连续数组](#525. 连续数组)
- [1314. 矩阵区域和](#1314. 矩阵区域和)
974. 和可被 K 整除的子数组
题目链接:974. 和可被 K 整除的子数组

个人解
思路:
和上篇文章的第三题一样,但是,因为哈希表里面可能有多个前缀和都满足要求,而我没想到如何快速搜索到这些前缀和。
暴力解法:O( n 2 n^2 n2)是过不了的。
优质解
思路:
- 哈希表里面有多个前缀和满足要求是因为:可能出现
dp[x2] = dp[x1] + k
的情况(即两数之间差nk
),导致对于dp[i]
,可能有多个前缀和与之匹配。那如何保证唯一且能把这些数全部统计到呢? - 我们可以在记录前缀和的时候,不记录前缀和,而是记录
前缀和 % k
的余数。 - 因为:如果
(dp[i] - dp[x]) % k == 0
,则dp[i] % k == dp[x] % k
- 细节问题:我们的数组中有负数,但是C++ 中的取模性质:
负数 % 正数 == 负数
。所以我们要对模出来的结果进行修正 - 修正:对于负数结果修正:
余数 = dp[i] % k + k
,但是为了正负数同一:余数 = (dp[i] % k + k) % k
代码:
cpp
class Solution {
public:
int subarraysDivByK(vector<int>& nums, int k) {
unordered_map<int, int> hash;
int ans = 0, sum = 0;
hash[0] = 1;
for(auto x: nums)
{
sum += x; // sum代表当前位置的前缀和
int modulus = (sum % k + k) % k;
if(hash.count(modulus)) ans += hash[modulus];
hash[modulus]++;
}
return ans;
}
};
时间复杂度:O( n n n)
空间复杂度:O( n n n)
525. 连续数组
题目链接:525. 连续数组

个人解
思路:
脑子锈了,只能想到O( n 2 n^2 n2)的解法。
优质解
思路:
- 把
0
变-1
- 问题变成:找子数组所有元素和为
0
的最长子数组。 - 细节1:哈希表存储什么? 答:
<前缀和,下标>
,并且如果遇到相同的前缀和,下标大的不存(因为子数组短) - 细节2:当前位置的信息使用完以后才存入哈希表,不然
dp[i] - dp[i]
这个子数组实际为空 - 细节3:默认前缀和
0
的位置要存在-1
代码:
cpp
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int ans = 0, sum = 0;
unordered_map<int, int> hash;
hash[0] = -1;
for(int i = 0; i < nums.size(); i++)
{
sum += (nums[i] == 0? -1 : 1);
if(hash.count(sum))
ans = max(ans, i - hash[sum]);
else
hash[sum] = i;
}
return ans;
}
};
时间复杂度:O(n)
空间复杂度:O(n)
1314. 矩阵区域和
题目链接:1314. 矩阵区域和

个人解
这道题和文章中第二题很像,这道题麻烦在下标对应。
思路:
- 题意:
answer
中每一格表示的是:以mat[r][c]
为中心的,边长为2k+1
的正方形中所有元素(且在mat
中)的和 - 建立一个二维前缀和数组:
dp[i][j]
代表mat
的[0, 0]
到[i, j]
这个矩阵内的元素和 - 然后利用这个前缀和数组来填写
answer
- 下标对应:初始化时:因为
mat
的元素是从下标[0, 0]
开始的,所以dp[i][j]
加的应该是mat[i - 1][j - 1]
- 使用时:
dp[1][1]
才对应mat
的第一个元素,所以,在使用dp
的时候下标都要-1
用时:20:00
屎山代码:
cpp
class Solution {
public:
vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
int m = mat.size(), n = mat[0].size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
vector<vector<int>> answer(m, vector<int>(n, 0));
// 初始化前缀和数组
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + mat[i - 1][j - 1];
}
for(int i = 0; i < m; i++)
{
for(int j = 0; j < n; j++)
{
int x1 = max(0, i - k);
int y1 = max(0, j - k);
int x2 = min(m - 1, i + k);
int y2 = min(n - 1, j + k);
answer[i][j] = dp[x2 + 1][y2 + 1] - dp[x1][y2 + 1] - dp[x2 + 1][y1] + dp[x1][y1];
}
}
return answer;
}
};
时间复杂度:O( m ∗ n m*n m∗n)
空间复杂度:O( m ∗ n m*n m∗n)
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!