DAY2 - 209.长度最小的子数组,59.螺旋矩阵II,区间和,开发商购买土地
209.长度最小的子数组
子数组元素之和大于等于target
重点:滑动窗口
为什么用滑动窗口?子数组是连续的
一开始自己写的:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left=0;
int right=0;
int minlen=numeric_limits<int>::max();
int sum=0;
while(right<nums.size()){
int len=right-left+1;
if(sum==target){
minlen=(len<minlen)?len:minlen;
}else if(sum<target){
sum+=nums[right++];
}else{
sum-=nums[left++];
}
}
return minlen;
}
};
但是时间超过限制了。问题在于这个循环条件 while(right<nums.size())并不是每一次都更新的,所以相当于还是暴力解法。而且题目说的是大于等于target,而不是等于。
换一个方式来思考这个问题:暴力解法是两个for循环,一个是数组起始位置,一个是数组结束位置。现在要用一个for循环来解决问题,那么这个for循环应该是标记数组的结束位置,也就是窗口right。for循环内部则是用一个while来移动滑动窗口起始位置。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left=0;
int minlen=INT32_MAX;
int sum=0;
for(int right=0;right<nums.size();right++){
sum+=nums[right];
while(sum>=target){
int len=right-left+1;
minlen=min(len,minlen);
sum-=nums[left++]; // 减少一个元素看是否仍然符合条件,尝试更小值
}
}
return minlen==INT32_MAX ? 0:minlen;
}
};
59.螺旋矩阵II
没啥技巧,就是考验对转圈的控制能力
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));
int loop=n/2; //要转几圈
int start=0;
int cnt=1;
int offset=1; //这个自己没想到
int i,j;
while(loop--){
i=start;
j=start;
//上边
for(j; j<n-offset; j++){
res[i][j]=cnt++;
}
//右边
for(i; i<n-offset; i++){
res[i][j]=cnt++;
}
//下边
for(j; j>start; j--){ // 注意这个边界条件
res[i][j]=cnt++;
}
//左边
for(i; i>start; i--){
res[i][j]=cnt++;
}
start++;
offset++;
}
if(n%2){
res[n/2][n/2]=n*n;
}
return res;
}
};
设置 offset 变量是我一开始没想到的,用这个可以保证每转一圈就内推一格
区间和
核心思想:前缀和 presum [a,b]sum=p[b]-p[a-1]
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n,a,b;
cin >> n;
int presum=0;
vector<int> p(n);
int cur;
for(int i=0; i<n; i++){
cin >> cur; // scanf("%d", &vec[i]);
presum+=cur;
p[i]=presum;
}
int sum;
while(cin >> a >> b){ //while (~scanf("%d%d", &a, &b))
if(a==0) sum=p[b];
else sum=p[b]-p[a-1];
cout << sum << endl;
// printf("%d\n", sum);
}
return 0;
}
C++ 代码 面对大量数据 读取 输出操作,最好用scanf 和 printf,耗时会小很多:
开发商购买土地
区间和的应用,分成了行区间和/列区间和
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<int> sn(n,0);
vector<int> sm(m,0);
vector<vector<int>> nums(n, vector<int>(m)) ;
int sum=0;
for (int i=0; i<n; i++){
for (int j=0; j<m; j++){
cin>>nums[i][j];
sum=sum+nums[i][j];
sn[i]+=nums[i][j];//横前缀和(压缩列)
sm[j]+=nums[i][j];//纵前缀和(压缩行)
}
}
int minSum=INT_MAX;
//横切
int hengSum=0;
for (int hengCnt=0; hengCnt<n-1; hengCnt++){
hengSum+=sn[hengCnt];
minSum=min(minSum,abs(sum-hengSum-hengSum));
//abs((sum-hengSum)-hengSum) 是两半划分的差值
}
//纵切
int shuSum=0;
for (int shuCnt=0; shuCnt<m-1; shuCnt++){
shuSum+=sm[shuCnt];
minSum=min(minSum,abs(sum-shuSum-shuSum));
}
cout << minSum;
return 0;
}
浙公网安备 33010602011771号