算法训练营Day2
209.长度最小的子数组,59.螺旋矩阵II,区间和,开发商购买土地
题目
209.长度最小的子数组
题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
思路
暴力解法会超时
滑动窗口
使用一个指针遍历一遍数组,表示滑动窗口的右边界,同时调整左边界(不变或者向右滑动),找到当前右边界下满足条件(总和大于等于target)的最大值,两个指针下标相减加1即为子数组长度
代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int sum = 0;
int ans = INT_MAX;
for(int i = 0, j = 0; i < n; i ++){
sum += nums[i];
while(sum >= target){
ans = ans < i - j + 1? ans: i - j + 1;
sum -= nums[j ++];
}
}
return ans == INT_MAX? 0 : ans;
}
};
59.螺旋矩阵II
题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/
思路
模拟题
自己的想法:自己列了前几组发现一个规律,就是螺旋是按照 → ↓ ← ↑ 的顺序为一个循环,总共要改变2n-1次方向,并且一个循环结束后相同方向上都会减少一个位置,也就是 i / 4个位置;经过将结果输出然后debug,成功ac了
题解思路:使用l,r,b,t记录边界位置,按照 → ↓ ← ↑ 的顺序为一个循环,每次改变方向时相应的边界就会减小一个,每次只需要从左边界遍历到右边界赋值(从上到下,从右到左,从下到上)即可
代码
//自己的想法,比较麻烦
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
int a[n][n];
int k = 0; // 记录当前需要填入的数字
vector<vector<int>> ans;
for (int i = 0; i < 2 * n - 1; i++) {
int m = i / 4; // 需要缩减的个数
if (i % 4 == 0) {
for (int j = m; j < n - m; j++)
a[m][j] = ++k;
} else if (i % 4 == 1) {
for (int j = m + 1; j < n - m; j++)
a[j][n - m - 1] = ++k;
}
else if (i % 4 == 2) {
for (int j = n - m - 2; j >= m; j--)
a[n - m - 1][j] = ++k;
} else {
for (int j = n - m - 2; j >= m + 1; j--)
a[j][m] = ++k;
}
}
for (int i = 0; i < n; i++) {
vector<int> temp;
for (int j = 0; j < n; j++) {
temp.push_back(a[i][j]);
cout << a[i][j] << ' ';
}
ans.push_back(temp);
}
return ans;
}
};
//题解代码
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> ans(n, vector<int>(n));
int l = 0, r = n - 1, t = 0, b = n - 1;
int k = 0;
while (l < n && t < n && r >= 0 && b >= 0) {
for (int i = l; i <= r; i++)
ans[t][i] = ++k;
t++;
for (int i = t; i <= b; i++)
ans[i][r] = ++k;
r--;
for (int i = r; i >= l; i--)
ans[b][i] = ++k;
b--;
for (int i = b; i >= t; i--)
ans[i][l] = ++k;
l++;
}
return ans;
}
};
区间和
题目链接:https://kamacoder.com/problempage.php?pid=1070
文章讲解:https://www.programmercarl.com/kamacoder/0058.%E5%8C%BA%E9%97%B4%E5%92%8C.html
思路
前缀和,空间换时间
从下标1开始存储,可以防止计算区间和时数组下标越界;用一个数组来存储从头到该下标位置的累加和,求区间范围时只需用右边界的累加和减去左边界前一个的累加和即可,需要注意从0开始存储还是从1开始存储
代码
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int n;
int t[100010], sum[100010]={0};
cin >> n;
// 从下标1开始存储
for(int i = 1; i <= n; i ++){
cin >> t[i];
sum[i] = sum[i - 1] + t[i];
}
int a, b;
while(cin >> a >> b){
cout << sum[b + 1] - sum[a]<< endl;
}
}
开发商购买土地
题目链接:https://kamacoder.com/problempage.php?pid=1044
思路
区间和
首先存储每行和每列的累加和,然后遍历每行和每列,存储当前行之前行的累加和(包括当前行);最后再遍历一遍行和一遍列,求两块之差的最小值
突然变成ACM模式,一直把答案return回去一直报错,要注意ACM模式是要将答案输出
代码
#include <iostream>
#include <climits>
using namespace std;
const int N = 110;
int main(){
int row[N] = {0}, col[N] = {0};
int a[N][N];
int n, m;
int ans = INT_MAX;
cin >> n >> m;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
cin >> a[i][j];
row[i] += a[i][j];
col[j] += a[i][j];
}
}
for(int i = 1; i <= n; i ++) {row[i] += row[i - 1]; }
for(int j = 1; j <= m; j ++) {col[j] += col[j - 1];}
for(int i = 1; i < n; i ++){
ans = abs(row[n] - 2 * row[i]) < ans? abs(row[n] - 2 * row[i]) : ans;
}
for(int j = 1; j < m; j ++){
ans = abs(col[m] - 2 * col[j]) < ans? abs(col[m] - 2 * col[j]) : ans;
}
cout << ans << endl;
return 0;
}