209.长度最小的子数组
题目链接:
https://leetcode.cn/problems/minimum-size-subarray-sum/description/
这里是卡哥原文链接,讲的清晰明了:
暴力解法:
看了示例默写的代码:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int sublength = 0;
for (int i = 0; i < nums.size(); i++) {
sum = 0;
for (int j = i; j < nums.size(); j++) {
sum += nums[j];
if(sum > target) {
sublength = j - i + 1;
result = result < sublength ? result : sublength;
break;
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
代码错误:
进行判断是否赋值,if(sum > target) 应该是if(sum >= target),因为没好好读题,题目中说的是 找出该数组中满足其总和大于等于 target
的长度最小的子数组,可恶。。。。
代码分析:
- 两个循环,第一个循环表示起始位置,第二个循环表示从起始位置开始,不断向后遍历数组,并通过if判断是否赋值,注意满足判断条件后,应及时break;在第一层循环中应该重置sum的值;给result赋值的时候,将result的值与新的sublength的值作比较,返回小的那一个值。
- 关于INT32_MAX:INT_MAX 和 INT_MIN 是 C++ 的两个宏,代表了整型变量能够存储的最大正整数和最小负整数,分别为 2147483647 和 -2147483648,这两个宏在头文件 <limits.h> 中定义。
- 在本代码中,用INT32_MAX表示result(数组长度的最大值),然后不断地用sublength和result比较,如果符合题中条件,将会给result赋值,循环结束之后,如果result的值还是INT32_MAX,说明没有赋值,返回0,如果result的值是别的数,则返回result的值。
- 关于result和sublength,二者都是求得的数组的长度,sublength是一次循环操作的实时长度值,result是经过比较筛选出来的最小长度
滑动窗口
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
示例代码:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int sublength = 0;
int i = 0;
for (int j = 0; j < nums.size(); j++) {
sum += nums[j];
while (sum >= target) {
sublength = j - i + 1;
result = result > sublength ? sublength : result;
sum -= nums[i++];
}
}
return result == INT32_MAX ? 0 : result;
}
};
这里借助卡哥的两个图辅助分析:
思路:
本题的滑动窗口法和双指针法有异曲同工之妙。 窗口指的是满足条件的最小子数组,窗口的起始位置移动,也就是当满足sum>=target,终止位置不动,起始位置动,即sum -= nums[i++],动到不满足循环条件,终止位置再开始动, 再计算sum直到结束。
59.螺旋矩阵
直接看题解:https://www.programmercarl.com/0059.螺旋矩阵II.html#思路
代码示例:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));
int startx = 0;
int starty = 0;
int count = 1; //先使用后加加
int loop = n / 2;
int mid = n / 2;
int offset = 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++;
}
starty++;
startx++;
offset++;
}
if(n%2==1) {res[mid][mid] = n * n;}
return res;
}
};
代码疑点:
- 不会用vector创建二维数组
代码分析:
- 核心:注意循环不变量的使用,始终遵循左闭右开,按照矩阵规则设计i, j,(i是行,j是列)
- res[i][j] = count++; 这里的count先使用赋值再加加,所以count的起始值是1
- int offset = 1;for (j; j < n - offset; j++) ,offset是为了控制右边界,例如n=3,那第一次循环j的终点在1,(因为数组的起始下标是0)这里附上卡哥的图
- for (; j > starty; j--)这里不定义j是因为在上次循环中,j的值已经到了最后一列,直接循环即可。
- 每进行一圈赋值结束后,startx和starty都要加加,看图可知,而且赋值的圈数要减减,这也是循环的条件
- 注意n是奇数偶数
区间和
题目链接:
https://kamacoder.com/problempage.php?pid=1070
题目描述
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。
输出描述
输出每个指定区间内元素的总和。
输入示例
5
1
2
3
4
5
0 1
1 3
输出示例
3
9
数据范围:
0 < n <= 100000
这个题的主要目的是熟悉acm模式,并且学会使用vector的基本操作
方法:前缀和:通过vector创建两个数组,要统计 vec[i] 这个数组上的区间和,我们先做累加,即 p[i] 表示 下标 0 到 i 的 vec[i] 累加 之和,如图,例如要计算2到5的区间和,就用p[5]-p[1]
推导:
p[1] = vec[0] + vec[1];
p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];
p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5];
代码实现:
#include<iostream>
#include<vector>
using namespace std;
int main() {
int n,a,b;
int presum = 0;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
for (int i = 0; i < n; i++) {
scanf("%d", &vec[i]);
presum += vec[i];
p[i] = presum;
}
while (scanf("%d%d", &a, &b) == 2) {
int sum = 0;
if (a == 0) sum = p[b];
else sum = p[b] - p[a-1];
printf("%d\n", sum);
}
return 0;
}
注意:最后进行判断:a==0;C++ 代码 面对大量数据 读取 输出操作,最好用scanf 和 printf,耗时会小很多