1.长度最小的子数组
1.1 题目链接
1.2 思路
滑动窗口
1.3 题解
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int slow=0;
int fast=0;
int sum=0;
int result=INT32_MAX;
int length=0;
while(fast<nums.size())
{
sum+=nums[fast];
while(sum>=target)
{
length=fast-slow+1;
if(length<result)
{
result=length;
}
sum-=nums[slow];
slow++;
}
fast++;
}
if(result==INT32_MAX)
{
return 0;
}
return result;
}
};
1.4 解释
定义一个快指针和慢指针,实际上可以看作一个滑动窗口,不断计算快指针与慢指针之间的元素和,如果和大于或等于target的值,就更新窗口的长度并减去慢指针所处位置的值。
1.5 复杂度
时间复杂度为O(n)
2.螺旋矩阵
2.1 题目链接
2.2 思路
以每一圈为一个任务,每一圈中再分为四条边,注意循环不变量左闭右开。
2.3 题解
class Solution {
public:
vector<vector<int>> generateMatrix(int n)
{
/*左闭右开写法*/
// 构建2维数组
vector<vector<int>> result(n,vector<int>(n,0));
// 边起始位置
int startx = 0;
int starty = 0;
// 边终止偏移量
int offset = 1;
// 数值
int count = 1;
//要转的圈数
int loop=n/2;
int x,y;
// 要转的圈数为循环条件
while (loop--)
{
x = startx;
y = starty;
// 从左到右第一条边
for (; x < n - offset; x++)
{
result[y][x] = count++;
}
// 从上到下第二条边
for (; y < n - offset; y++)
{
result[y][x] = count++;
}
// 从右到左第三条边
for (; x > startx; x--)
{
result[y][x] = count++;
}
// 从下到上第四条边
for (; y > starty; y--)
{
result[y][x] = count++;
}
startx++;
starty++;
offset++;
}
//为奇数的情况下
if (n % 2 == 1)
{
result[n / 2][n / 2] = n * n;
}
return result;
}
};
2.4 复杂度
时间复杂度为O()
),相当于遍历2维数组。
3.区间和
3.1 题目链接
3.2 思路
先计算前缀和,之后利用前缀和相减就能得出结果
3.3 题解
#define _CRT_SECURE_NO_WARNINGS //防止在VS中报错:scanf是不安全的。VS中有一个独有的scanf_s,只能在VS上运行
using namespace std;
#include <iostream>
#include <vector>
int main()
{
//数组的长度
int n;
//输入的左区间
int left;
//输入的右区间
int right;
//从控制台输入数组长度
scanf("%d", &n);
vector<int> vec(n);
int input;
int add=0;
//输入数组的元素
for (int i = 0; i < n; i++)
{
//求前缀和之后再放入数组
scanf("%d", &input);
add += input;
vec[i] = add;
}
//输入左右区间
while (~scanf("%d%d", &left,&right))//当报错时,scanf一般会返回-1,但是在while循环中,-1仍然会继续循环,所以应该用符号~取其二进制反码使其为0从而循环停止
{
int sum;
//左边界为0时要单独考虑
if (left == 0)
{
sum = vec[right];
}
else
{
sum = vec[right] - vec[left - 1];
}
printf("%d\n", sum);
}
}
3.4 解释
比如说区间[a,b],先求原数组的前缀和得到一个新数组,那么区间[a,b]之间的和就等同于新数组索引b处的元素减去索引a-1处元素。
4.开发商购买土地
4.1 题目链接
4.2 思路
可以考虑前缀和,分别求出纵向和横向的前缀和数组。
4.3 题解
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#include <iostream>
#include <vector>
int main()
{
int n;
int m;
cin >> n >> m;
vector<vector<int>> vec(n, vector<int>(m, 0));
//构建二维数组
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> vec[i][j];
}
}
//求纵向前缀和数组
//先构建数组
vector<int> vec_x;
int csum1 = 0;
for (int i = 0; i < n; i++)
{
int sum_x = 0;
for (int j = 0; j < m; j++)
{
sum_x += vec[i][j];
}
csum1 += sum_x;
vec_x.push_back(csum1);
}
//求横向前缀和数组
//先构建数组
vector<int> vec_y;
int csum2 = 0;
for (int i = 0; i < m; i++)
{
int sum_y = 0;
for (int j = 0; j < n; j++)
{
sum_y += vec[j][i];
}
csum2 += sum_y;
vec_y.push_back(csum2);
}
//纵向分割
int result1 = INT32_MAX;
int min_split1 = 0;
//有n-1种分法
for (int i = 0; i < n-1; i++)
{
//前半部分的和
int sum_begin = vec_x[i];
//后半部分的和
int sum_end = vec_x[n-1] - vec_x[i];
//求差值,注意使用绝对值
min_split1 = abs(sum_end - sum_begin);
if (min_split1 < result1)
{
result1 = min_split1;
}
}
//纵向分割
int result2 = INT32_MAX;
int min_split2 = 0;
//有n-1种分法
for (int i = 0; i < m-1; i++)
{
//前半部分的和
int sum_begin = vec_y[i];
//后半部分的和
int sum_end = vec_y[m - 1] - vec_y[i];
//求差值,注意使用绝对值
min_split2 = abs(sum_end - sum_begin);
if (min_split2 < result2)
{
result2 = min_split2;
}
}
int res= result1 > result2 ? result2 : result1;
cout << res << endl;
}