一、长度最小的子数组
1.题目:给定一个含有 n
个正整数的数组和一个正整数 target
。找出该数组中满足其总和大于等于 target
的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
2.思路: 滑动窗口
3.注意:
(1)所示代码中for循环内判断条件用while而不是if
循环体内使用 if 时,窗口左边界移动一次后尚未判断新窗口内子数组元素和是否 >= target 就会将右边界移动。
本人原本使用 if 思路:for 循环的第三个部分对窗口右边界移动的部分不写,然后窗口左边界移动后继续执行循环体,待符合条件的子数组变成不符合条件后再将右边界移动。
(2)对返回值的取值
本人起初是令返回值 numLenth 初始化时为 0,此时 while 循环体内的 if 判断会永远为假,所以修改为初始化为 nums.size(),但如下方代码中注释部分所示,在 return 时当 numLenth 为初始值时需要两层判断,所以最后将 numLenth 初始化为比 nums.size() 大的数值即可。
4.代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left=0,right=0;
int numLenth = nums.size() + 1;
int numsCount = 0;
int numsCount2 = 0;
int numsL,numsR;
for( right=0; right<nums.size(); right++)
{
numsCount = numsCount + nums[right];
// numsCount2 = numsCount2 + nums[right];
while( numsCount >= target )
{
if( numLenth > (right - left + 1) )
{
numsL = left;
numsR = right;
numLenth = right -left + 1;
}
numsCount = numsCount - nums[left];
left++;
}
}
return ( numLenth > nums.size() )?0:numLenth;
// if(numLenth < nums.size())
// {
// return numLenth;
// }else{
// return ( numsCount2 >= target )?nums.size():0;
// }
}
};
二、螺旋矩阵Ⅱ
1.题目:给你一个正整数 n
,生成一个包含 1
到 n²所有元素,且元素按顺时针顺序螺旋排列的 n*n
正方形矩阵 matrix
。
2.思路: 模拟运行即可
3.注意:
(1)思考循环不变量的使用
(2)n为奇数时需要单独给正中心的格子赋值
4.代码
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> result(n, vector<int>(n,0));
int startX,startY;
int i,j;
int loop = n/2;
int mid = n/2;
int count = 1;
int offset = 1;
while( loop-- )
{
i = startX;
j = startY;
// 填上方
for(j; j < n-offset; j++)
{
result[i][j] = count++;
}
// 填右侧
for(i; i < n - offset; i++)
{
result[i][j] = count++;
}
// 填下方
for(; j > startY; j--)
{
result[i][j] = count++;
}
// 填左侧
for(; i > startX; i--)
{
result[i][j] = count++;
}
// 循环一圈后需要进行的处理
startX++;
startY++;
offset++;
}
// n为奇数时,循环绕圈会漏掉最中心的格子
if( n % 2 )
{
result[mid][mid] = count;
}
return result;
}
};
三、区间和
1.题目:给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述:
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。
输出描述:
输出每个指定区间内元素的总和。
2.思路: 前缀和
3.注意:
(1)了解ACM答题模式,笔试/面试必备
(2)C++在面对大量数据的输入输出时,使用 scanf 和 printf 比 cin 和 cout 少很多时间
4.代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
int presum = 0;
for (int i = 0; i < n; i++) {
cin >> vec[i];
// scanf("%d", &vec[i]);
presum += vec[i];
p[i] = presum;
}
while (cin >> a >> b) {
int sum;
if (a == 0) sum = p[b];
else sum = p[b] - p[a - 1];
cout << sum << endl;
// printf("%d\n", sum);
}
}
四、开发商购买土地问题
1.题目:在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。 Ps:区块不可再分。
输入描述:
第一行输入两个正整数,代表 n 和 m。
接下来的 n 行,每行输出 m 个正整数。
输出描述:
请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
2.思路
3.注意
4.代码
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main () {
int n, m;
cin >> n >> m;
int sum = 0;
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];
sum += vec[i][j];
}
}
// 统计横向
vector<int> horizontal(n, 0);
for (int i = 0; i < n; i++) {
for (int j = 0 ; j < m; j++) {
horizontal[i] += vec[i][j];
}
}
// 统计纵向
vector<int> vertical(m , 0);
for (int j = 0; j < m; j++) {
for (int i = 0 ; i < n; i++) {
vertical[j] += vec[i][j];
}
}
int result = INT_MAX;
int horizontalCut = 0;
for (int i = 0 ; i < n; i++) {
horizontalCut += horizontal[i];
result = min(result, abs(sum - horizontalCut - horizontalCut));
}
int verticalCut = 0;
for (int j = 0; j < m; j++) {
verticalCut += vertical[j];
result = min(result, abs(sum - verticalCut - verticalCut));
}
cout << result << endl;
}