代码随想录算法训练营day02(补1226)

1.长度最小的子数组

其实几个月前我做过一次这个题目,记得当初就是不太懂,然后去看卡哥的视频跟题解才大致懂了一些去完成。 没想到这次依旧是卡壳了,我大致明白滑动窗口的思路,但是无法将其具象化为代码写出来。最后还是去看了视频,回忆起了之前做的思路。还是没有完全吃透滑动窗口这个思想跟用法。

题目以及链接

https://leetcode.cn/problems/minimum-size-subarray-sum/description/

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 子数组

 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

思路以及难点

根据题目要求,我们需要通过不断调节数组的长度去达到条件——其总和大于等于 target 的长度最小的 子数组。 因此就要想到滑动窗口的思路,通过不断调节起始位置跟终止位置去得出想要的结果。

对于我遇到的难题就是我想不到如何去更新我的窗口内的值。通过学习得知是通过创造一个子序列长度去跟INT_MAX(int的最大值)去比较,取二者的最小值;然后是怎么更新,对于起始位置与终止位置的更新,在while循环里。

滑动窗口代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int res=INT_MAX,i=0,subL=0,sum=0;
        for(int j=0;j<nums.size();j++){
            sum+=nums[j];
            while(sum>=target){ //难点
                subL=j-i+1;
                res=min(res,subL); //想不到的点
                sum-=nums[i];
                i++; //起始位置的变更
            }
        }
        if(res==INT_MAX) res=0;
        return res;
    }
};

2.数组:螺旋矩阵II

这题首先是对代码分析能力的考研,要通过什么样的方式去填充那一圈的数字,一开始我就没想明白;其次是对细节的把控,四条边必须用相同的规则才可以,我用的是左闭右开;然后是对中间值的如何填充与循环的何时结束,在这方面我调了蛮久的bug

题目以及链接

题目链接

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

示例 1:

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
代码
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>>nums(n,vector<int>(n,0));  //二维数组的创建并将其初始化为0
        int x=0,y=0;//初始位置
        int offset=1;//保证区间正确
        int count=1;//赋值数
        int mid=n/2;
        int loop=n/2;//注意这个是用来控制循环次数的,不能直接省时间用mid,会导致后面if语句出现问题而报错
        while(loop--){
            for(int j=y;j<n-offset;j++){
                nums[x][j]=count++;
            }
            for(int i=x;i<n-offset;i++){
                nums[i][n-offset]=count++;
            }
            for(int j=n-offset;j>y;j--){
                nums[n-offset][j]=count++;
            }
            for(int i=n-offset;i>x;i--){
                nums[i][y]=count++;
            }
            x++;
            y++;
            offset++;
        }
        if(n%2!=0){
            nums[mid][mid]=count;
        }
        return nums;
    }
};
3.区间和

这题如果使用暴力解法思路还是比较明确的,我也不假思索地先用的暴力解法,可惜的是超时了。然后瞟了一眼卡哥的解法,说前缀和,大致就明白了,再创一个数组用来存前缀和然后相减即可。但是可以改进的是以后这种全部写代码的题目,数组要引用vector容器然后创建这种形式的数组;多次取值的方法是while(cin>>a)。

题目

区间和

题目描述

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

输入描述

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

输出描述

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

输入示例

5
1
2
3
4
5
0 1
1 3
输出示例
3
9
代码
#include<iostream>
#include<vector>
using namespace std;
//引入头文件然后使用vector容器——培养意识
//暴力解法——超时
int main(){
    int a,b,n;
    int temp=0;
    cin>>n;
    vector<int>arr(n);
    vector<int>sum(n);
    for(int i=0;i<n;i++){
        cin>>arr[i];
        temp+=arr[i];
        sum[i]=temp;//小技巧,如何通过中间值取得前缀和
    }
    while(cin>>a>>b){  //如何多次取值
        int m;
        if(a==0)m=sum[b];//使用中文括号报错
        else m=sum[b]-sum[a-1];
        cout<<m<<endl;
    }
    
}

4.开发商购买土地

这题一开始给我的感觉就是很懵,不知道这个切割是怎么个切割法,我要如何用数组完成想要的切割。联想到上一题的前缀和思路,我也仅仅是能够完成计算每行与每列的前缀和,并不知道切割的方法;所以对于数组的更新我还是比较薄弱的,包括滑动窗口也是,希望可以慢慢加强这方面思维。

然后对于这种实际题目与算法的结合,容易读不透题意,像这题,其实就是总和减去一部分面积得到A面积,剩下的为B面积,然后A面积-B面积就得到了需要的差值,然后创建一个值为INT_MAX的与之min一下就行了。

题目

题目链接

题目描述

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

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

然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。 为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。 

注意:区块不可再分。

输入描述

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

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

输出描述

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

输入示例
3 3
1 2 3
2 1 3
1 2 3
输出示例
0
提示信息

如果将区域按照如下方式划分:

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

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

数据范围:

1 <= n, m <= 100;
n 和 m 不同时为 1。

代码
#include<iostream>
#include<vector>
#include<climits>  //提供INT_MAX常量,否则编译器无法解析
using namespace std;

//这题没有什么比较明确的思路,不明白如何通过算法去求出土地价值之间的最小差距
int main(){
    int n,m,sum=0;
    cin>>n>>m;
    vector<vector<int>>nums(n,vector<int>(m,0));//n*m二维数组de创建
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>nums[i][j];
            sum+=nums[i][j];
        }
    }
    vector<int>sx(n,0);//每行面积
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            sx[i]+=nums[i][j];
        }
    }
    vector<int>sy(m,0);//每列面积
    for(int j=0;j<m;j++){
        for(int i=0;i<n;i++){
            sy[j]+=nums[i][j];
        }
    }
    //横向切割
    int xcut=0,res=INT_MAX,xum=0;
    for(int i=0;i<n;i++){
        xcut+=sx[i];
        xum=abs((sum-xcut)-xcut);//差值,就是这里值得好好思考,sum-xcut是A公司,那么剩下来的xcut就只能是B公司然后它们相减再取绝对值
        res=min(res,xum);
    }
    int ycut=0,yum=0;//纵向切割
    for(int j=0;j<m;j++){
        ycut+=sy[j];
        yum=abs((sum-ycut)-ycut);//同上
        res=min(res,yum);
    }
    cout<<res<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值