提示:DDU,供自己复习使用。欢迎大家前来讨论~
题目
第二天打卡,数组就结束了,一看就会,一做就废。要多多练习coding。简单记录一下。
一、209长度最小的子数组
主要是学习到了动态滑动窗口的使用,一般是使用while(),而不是if()。
注意最后返回的是res,不是subL
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int res=INT_MAX;//初始值最大,一般表示最小的变量。
int subL=0;
int sum=0;
int i=0;
for(int j=0;j<nums.size();j++){//j表示结尾的位置
sum += nums[j];
while(sum >= target){
subL = j - i + 1;
res = res > subL ? subL : res;
sum -= nums[i++];//动态调整起始的位置
}
}
return res == INT_MAX ? 0 : res;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(1)
二、59.螺旋矩阵II
采用顺时针转圈的逻辑,使用循环来填充数值。边界都是左闭右开的。
循环里面的边界的判断条件是一个变量,是会变化的。
n-offset;startx;starty;
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0)); // **使用vector定义一个二维数组**
int startx=0,starty=0;
int loop = n/2;
int offset = 1;
int mid = n/2;
int count = 1;
int i,j;
while(loop--){
i=startx;
j=starty;
//开始顺时针旋转;
//从左往右;
for(j;j<n-offset;j++){
res[i][j]=count++;
}
//右侧-从上往下;
for(i;i<n-offset;i++){
res[i][j]=count++;
}
//从右往左;
for(;j>starty;j--){
res[i][j]=count++;
}
//左侧-从下往上;
for(;i>startx;i--){
res[i][j]=count++;
}
//开始第二圈;起始点要往里面缩小一圈,所以横纵都要+1;
startx++;
starty++;
//横纵都加1,相当于外面是2
offset+=1;
}
//如果是奇数的话,要单独给中间的赋值。
if (n % 2) {
res[mid][mid] = count;
}
return res;
}
};
- 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
- 空间复杂度 O(1)
二、前缀和–算法的思想
这是一个很巧妙的思路,可以提前计算一下所有前i下标的总和,进而求一个子区间和,即两个大小下标总和的差值。
注意:P[b] - P[a-1],这里可以举例掌握一下。
区间和
```#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
int presum = 0;
for (int i = 0; i < n; i++) {
cin >> vec[i];
presum += vec[i];
p[i] = presum;
}
while (cin >> a >> b) {
int sum;
if (a == 0) sum = p[b];
else sum = p[b] - p[a - 1];
cout << sum << endl;
}
}
改进后的版本:面对大量数据 读取 输出操作,最好用scanf 和 printf,耗时会小很多
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
int presum = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &vec[i]);
presum += vec[i];
p[i] = presum;
}
while (~scanf("%d%d", &a, &b)) {
int sum;
if (a == 0) sum = p[b];
else sum = p[b] - p[a - 1];
printf("%d\n", sum);
}
}
- 时间复杂度: O(n^2)
开发商购买土地
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main () {
int n, m;
cin >> n >> m;
int sum = 0;
vector<vector<int>> vec(n, vector<int>(m, 0)) ;//二维数组的定义,掌握一下。
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> vec[i][j];
sum += vec[i][j];
}
}
int result = INT_MAX;
int count = 0; // 统计遍历过的行
for (int i = 0; i < n; i++) {
for (int j = 0 ; j < m; j++) {
count += vec[i][j];
// 遍历到行末尾时候开始统计,找到最小代价的距离。
if (j == m - 1) result = min (result, abs(sum - count - count));
}
}
count = 0; // 统计遍历过的列
for (int j = 0; j < m; j++) {
for (int i = 0 ; i < n; i++) {
count += vec[i][j];
// 遍历到列末尾的时候开始统计
if (i == n - 1) result = min (result, abs(sum - count - count));
}
}
cout << result << endl;
}
今日总结
- 了解动态的滑动窗口,双指针思想。
- 利用前缀和来求区间和,差值的思路。
代码还是要自己多敲!!多注意一些细节的点(二维数组的定义,边界的取值),很容易犯错。