代码随想录训练营day02|LeetCode209、LeetCode59

前言

这里记录一下陈菜菜的刷题记录,主要应对25秋招、春招
个人背景
211CS本+CUHK计算机相关硕,一年车企软件开发经验
代码能力:有待提高
常用语言:C++

系列文章目录

第一天 数组 part01

第二天 数组 part02


`



一、今日任务

双指针法、滑动窗口、前缀和

二、详细布置

209.长度最小的子数组

题目链接:力扣209
文章讲解:代码随想录-长度最小子数
视频讲解:代码随想录

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105

样例1:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。     
样例2:
输入:target = 4, nums = [1,4,4]
输出:1     
思路

这题采用滑动窗口的思路。
滑动窗口就是不断的调节子序列的起始位置和终止位置。核心思路是当起始位置和终止位置之间存在限定关系时,可以考虑只用一个for循环完成两重for循环。
在本题中实现滑动窗口,主要确定如下三点:
窗口内是什么?
如何移动窗口的起始位置?
如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

实战
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int j,i=0,sublen=0,result=INT32_MAX,sum=0;
        for(j=0;j<nums.size();j++){
            sum+=nums[j];
            while(sum>=target){
                sublen=j-i+1;
                sum-=nums[i];
                i++;
                if(result>sublen)
                    result=sublen;
            }
        }
        if(result==INT32_MAX)
            return 0;
        return result;
    }
};
踩坑

初始时,result定义为最大值,这样才能不断将最小值赋给result。故初始化时result=INT32_MAX。
同样当区间内没有符合条件的子序列,表明没有更改过result,此时应该返回0(坑!!!)

59.螺旋数组

题目链接:力扣链接
文章讲解:图文讲解
视频讲解:代码训练营

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

提示:

1 <= n <= 20

样例1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]] 
     
样例2:
输入:n = 1
输出:[[1]]
思路

这题真的看起来简单,做起来一点都不容易。一开始想找每个元素和下标的数学关系发现并不好构建数组,遂放弃。。。
看了一点提示发现二分法,构建的时候发现转角条件没处理好,做的稀碎。。。
码一下,这题还没完全理解。

实战
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; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            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, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }
};

58.区间和

题目链接:区间和
文章讲解:图文讲解

题目描述

给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。

输入描述

第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。

输出描述

输出每个指定区间内元素的总和。

提示:

数据范围:

0 < n <= 100000

样例1:
输入:
5
1
2
3
4
5
0 1
1 3

输出:
3
9  
思路

这题思路很明显,就是累加每个输入的数,存在一个数组nums里。其中nums[a]表示输入数组的前a项和。

实战
#include <iostream>
#include<cstdio>
using namespace std;
int main(){
    int n,i,temp;
    cin>>n;
    int sum=0;
    int A[n]={0};
    for(i=0;i<n;i++){
        ~scanf("%d",&temp);
        //cin>>temp;
        sum+=temp;
        A[i]=sum;
        
    }
    int a,b;
    while(~scanf("%d%d", &a, &b)){
        if(a==0)
            printf("%d\n", A[b]);
            //cout<<A[b]<<endl;
        else
            printf("%d\n", A[b]-A[a-1]);
            //cout<<A[b]-A[a-1]<<endl;
    }
    return 0;
}
踩坑

当a=0时,a[-1]不存在,故需要单独处理。
C++ 代码面对大量数据读取输出操作,最好用scanf 和 printf,耗时会小很多(同样的代码cin,cout超时,换成scanf和printf就过了,码一下,很重要的技巧!!!)

44.开发商购买土地

题目链接:开发商购买土地
文章讲解:图文讲解

题目描述

在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。

现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。

然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。

为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。

注意:区块不可再分。

【输入描述】

第一行输入两个正整数,代表 n 和 m。

接下来的 n 行,每行输出 m 个正整数。

【输出描述】

请输出一个整数,代表两个子区域内土地总价值之间的最小差距。

提示:

数据范围:
1 <= n, m <= 100;
n 和 m 不同时为 1。

样例1:
输入:
3 3
1 2 3
2 1 3
1 2 3
输出:
0

提示信息:
如果将区域按照如下方式划分:

1 2 | 3
2 1 | 3
1 2 | 3 

两个子区域内土地总价值之间的最小差距可以达到 0
思路

这题和上一题一样,就是统计前缀和。唯一的区别就是数组要分行列来统计。但是初拿到这题还有点懵,在想会不会有切多刀的情况。。。ACM后遗症。只切一刀就很简单了。

实战
#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main(){
    int n,m;
    int sum=0;
    cin>>n>>m;
    vector<vector<int>> earth(n,vector<int> (m,0));
    int i,j;
    
    for(i=0;i<n;i++){
        for(j=0;j<m;j++){
            cin>>earth[i][j];
            sum+=earth[i][j];
        }
    }
    
    int hsum[n]={0};
    for(i=0;i<n;i++){
        for(j=0;j<m;j++){
            hsum[i]+=earth[i][j];
        }
    }
    
    int vsum[m]={0};
    for(j=0;j<m;j++){
        for(i=0;i<n;i++){
            vsum[j]+=earth[i][j];
        }
    }
    
    int result=INT32_MAX;
    
    int h=0;
    for(i=0;i<n;i++){
        h+=hsum[i];
        result=min(result,abs(sum-2*h));
    }
    
    int v=0;
    for(i=0;i<m;i++){
        v+=vsum[i];
        result=min(result,abs(sum-2*v));
    }
    
    cout<<result;
    return 0;
}
踩坑

求两个子区间差不能是sum-2*a,因为如果恰好a是较大的数,这个就变成负数了,会影响结果,要用绝对值函数。

总结

今天主要学习了滑动窗口、模拟、前缀和,
完成刷题3题,待掌握题目1题(螺旋数组)。
今天是训练营第二天,今天非常累,白天写作业(为什么计算机还要学金融啊我,真不会做),下午预习,晚上上课,一度想放弃了,但是强迫自己完成今天的训练,成就感满满!!
加油,坚持打卡的第二天。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值