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;
}