滑动窗口思路总结:
思路一:数组模拟双端队列
步骤1:定义一个数组(大小看题目中的窗口大小),用于表示双端队列,记录窗口内元素的下标。
步骤2:定义双端队列的队头、队尾(队头hh从0开始,队尾tt从-1开始),hh++表示将当前窗口从队头向后移动一位(减少窗口元素数量),++tt表示窗口从队尾向后移动一位(增加窗口元素数量)。
步骤3:定义与题相关的某些变量
步骤4:开始for循环遍历数组
步骤5:通过对双端队列中的队头队尾进行相应的++--,找到对应的满足的窗口,记录对应的值
思路二:使用一个变量记录窗口的起始位置,遍历数组,不断调整窗口
LeetCode209、长度最小的子数组
题目链接:209、长度最小的子数组
1、使用双端队列记录窗口
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
//使用数组模拟双端队列解题
//定义双端队列数组,用于记录窗口中的下标
int q[100010];
//定义双端队列的队头、队尾
int hh=0,tt=-1;//使用队尾=-1,每次向双端队列中添加元素就使++tt,出队就hh++;
//定义窗口中的元素和:
int sum = 0;
//定义窗口中的元素个数
int n = nums.size()+1;//当最后是这个数值返回0,不是这个数值返回最小的
//开始遍历数组,向双端队列中添加数组下标
for(int i=0;i<nums.size();i++)
{
//向窗口中添加当前的新元素
sum +=nums[i];
//增加窗口的长度
q[++tt] = i;
//判断窗口元素和是不是满足sum>=target,同时双端队列不为空
while(sum>=target&&hh<=tt)
{
//窗口中的元素和大于等于target,需要记录窗口中的元素个数、去掉队头一位
n = n<=q[tt]-q[hh]+1?n:q[tt]-q[hh]+1;//记录窗口当前的元素数
sum -=nums[q[hh]];//记录之后的sum和
hh++;//队头移动一位
}
//此时已经不满足sum>=target,窗口可以向后移动了
}
return n==nums.size()+1?0:n;
}
};
2、使用变量i记录窗口起始位置
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
//不使用双端队列记录窗口,使用一个变量记录当前窗口的起始位置
//定义一个窗口的起始位置
int i=0;
//定义滑动窗口的元素和
int sum = 0;
//定义滑动窗口的长度
int length =0;
//定义最小数量
int res = nums.size()+1;
//使用for循环遍历
for(int j=0;j<nums.size();j++)
{
sum +=nums[j];
while(sum>=target)
{
//获取窗口元素数量
length =j-i+1;
//减去窗口起始位置的元素,窗口向后走
sum -=nums[i];
res = res<length?res:length;
i++;
}
}
return res==nums.size()+1?0:res;
}
};
螺旋矩阵思路总结:
主要思想:让值能够顺序的填入,在需要转弯的地方设置转弯条件
转弯条件:
1、当向右水平移动时(x不变,y增加),在最后会出界,需要向下转弯
2、当向下竖直移动时(x增减,y不变),在最后会出界,需要向左转弯
3、当向左水平移动时(x不变,y减少),在最后会出界,需要向上转弯
3、当向上竖直移动时(x减少,y不变),在最后会覆盖(0,0),需要向右转弯
综上,需要设置的转弯条件有:
1、y的下一个值>=n时,向下转弯
2、x的下一个值>=n时,向左转弯
3、y的下一个值<0时,向上转弯
4、之后,如果下一个位置已经存在填入的值,就向右、向下、向左、向上、、、循环
思路:
对x轴、y轴设置偏移量,dx、dy
dx[4]={0,1,0,-1}
dy[4]={1,0,-1,0}
使用(x+dx[d],y+dy[d])的形式获取下一个(x,y)坐标,当下一个位置触发转弯限制,就将d增加1
d = (d+1)%4
LeetCode59、螺旋矩阵Ⅱ
题目链接:螺旋矩阵Ⅱ
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
//定义一个返回数组res,大小是(n,n),初始是0
vector<vector<int>>res(n,vector<int>(n,0));
//定义当前位置:
int x=0,y=0,d=0;
//定义偏移矩阵(垂直、水平)
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
//使用for循环遍历从1-n*n
for(int i=1;i<=n*n;i++)
{
//填入当前位置的值
res[x][y] = i;
//设置转弯位置的限制
//1、下一个位置出界>=n,<0
//2、下一个位置已经存在值了
if(y+dy[d]>=n||x+dx[d]>=n||y+dy[d]<0||res[x+dx[d]][y+dy[d]]!=0)
{
//要转弯,就将偏移值移动到下一位
d =(d+1)%4;//确保一直是0,1,2,3
}
//更新位置
x +=dx[d];
y +=dy[d];
}
//返回矩阵
return res;
}
};
前缀和思路总结:
思路1(当输入是自己设置,较为合适:循环从1开始):
1、使用公式A[i] = A[i-1]+Array[i]来计算前缀和
2、计算相应的区间和:res = A[b]-A[a-1];
注意点:
1、循环要从1开始for(int i=1;i<=nums.size(),i++)
2、如果要计算的是下标的区间和需要使用res =A[b+1]-A[a];
思路2(输入不是自己设置,是给好的数组时:循环从0开始)
1、同样使用公式A[i] = A[i-1]+Array[i],但是因为存在0-1=-1,需要使用中间变量获取元素的和,再存入对应的前缀和数组的对应位置
int presum=0;//定义中间变量
for()
{
presum +=Array[i]记录当前位置的和(注意从下标0开始)
A[i] = presum;
}
2、计算区间和需要判断(所以喜欢使用第一种思路)
if(a==0)res = A[b]
else if(a!=0)res = A[b]-A[a-1]
KamaCoder58、区间和
题目链接:KamaCoder58、区间和
//使用思路1
//循环从1开始,
//直接使用公式 A[i] = A[i-1]+Array[i];计算区间和
//最后输出需要判断l,r是不是下标,是下标需要 res = A[b+1]-A[a];
#include <iostream>
const int N =100010;
int Array[N];
int A[N];//前缀和数组
using namespace std;
int main()
{
int n;
scanf("%d",&n);
//获取数组
for(int i=1;i<=n;i++)
{
scanf("%d",&Array[i]);
}
//计算前缀和
for(int i=1;i<=n;i++)
{
A[i] = A[i-1]+Array[i];
}
//计算需要的区间和
int l,r;
while(cin>>l,cin>>r)
{
printf("%d\n",A[r+1]-A[l]);//因为是下标,需要加1
}
return 0;
}
//使用思路二
//循环从0开始,加入中间变量presum来获取元素和,再赋值给A[i]
//最后计算区间和需要判断左端点是不是为0
#include <iostream>
const int N =100010;
int Array[N];
int A[N];//前缀和数组
using namespace std;
int main()
{
int n;
scanf("%d",&n);
//获取数组
for(int i=0;i<n;i++)
{
scanf("%d",&Array[i]);
}
//计算前缀和
int presum=0;
for(int i=0;i<n;i++)
{
presum +=Array[i];
A[i] = presum;
}
//计算需要的区间和
int l,r;
while(cin>>l,cin>>r)
{
if(l==0)
printf("%d\n",A[r]);//需要判断是不是为0
else
printf("%d\n",A[r]-A[l-1]);
}
return 0;
}
KamaCoder44、开发商购买土地
题目链接:KamaCoder44、开发商购买土地
思路:
分竖直、水平分别计算前缀和,遍历前缀和,计算左右、上下两段的区间和,寻找最小值
//这道题目使用前缀和
//分别计算出行的前缀和数组、列的前缀和数组
//使用for循环遍历前缀和数组,获取从[0,i],[i+1,end]的差值,取最小值
#include <iostream>
#include <vector>
#include <climits>//定义INT_MAX
using namespace std;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
//前缀和使用思路1的从1开始计算
vector<vector<int>> Array (n+1 , vector<int>(m+1,0));
//输入数组Array
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&Array[i][j]);
}
}
//获取每一行的和
vector<int>hang(n+1,0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
hang[i] +=Array[i][j];
}
}
//获取每一列的和
vector<int>lie(m+1,0);
for(int j=1;j<=m;j++)
{
for(int i=1;i<=n;i++)
{
lie[j] +=Array[i][j];
}
}
//获取行的前缀和数组
vector<int>hang_s(n+1,0);
for(int i=1;i<=n;i++)
{
hang_s[i] = hang_s[i-1]+hang[i];
}
//获取列的前缀和数组
vector<int>lie_s(m+1,0);
for(int i=1;i<=m;i++)
{
lie_s[i] = lie_s[i-1]+lie[i];
}
//开始判断哪种最小
int res=INT_MAX;
for(int i=1;i<=n;i++)
{
res = min(res,abs((hang_s[i]-hang_s[0])-(hang_s[n]-hang_s[i])));
}
for(int i=1;i<=m;i++)
{
res = min(res,abs((lie_s[i]-lie_s[0])-(lie_s[m]-lie_s[i])));
}
printf("%d",res);
return 0;
}