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;
}
posted @ 2025-03-16 21:54  ChloeChen0221  阅读(613)  评论(0)    收藏  举报