209.长度最小的子数组
文章链接:代码随想录
题目链接:力扣题目链接
思路
题目要求
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
分析
题干要求寻找一个满足条件的长度最小的子数组,可以考虑使用双指针法。
初始化左、右指针指向数组的首部,随后右指针遍历数组,一边遍历,一遍将数组值加入到一个变量sum中(该变量用于计算从左指针到右指针的数组数值大小)。
当sum>=target时,进入while循环,计算此时子数组的长度,并将左指针向右移动。左指针移动的同时,sum要减去左指针指向的数值,直到不满足条件:sum>=target,退出while循环,右指针继续向右移动。
当遍历完整个数组时,便能找到答案。代码如下:
代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = INT_MAX;/*用于记录数组长度,因要求最小长度,所以初始化为最大值*/
int sum = 0;
int left = 0;
for(int right = 0;right<nums.size();++right){
sum += nums[right];
while(sum>=target){
n = min(n,right-left+1);
sum -= nums[left];
left++;
}
}
return n == INT_MAX?0:n;
}
};
904.水果成篮
题目链接:力扣题目链接
思路
题目要求
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits
表示,其中 fruits[i]
是第 i
棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
- 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
- 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
- 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits
,返回你可以收集的水果的 最大 数目。
分析
刚读完题目时感觉题目有点抽象,甚至不明白题目是什么含义。其实仔细分析,会发现,题目的意思其实是找出整数数组fruits中的最长子数组,要求子数组中只能含有两种数(注意!是两种数,不是两个数)。比如1、2或2、3,不能是1、2、3,因为此时含有三种类型的数。
明白题目要求后,现在开始解题。
初始化左右指针指向数组的首部,同时使用哈希表来记录子数组中数的种数,当种数大于2时,进入while循环,移动从哈希表中减去左指针指向的数,如果此时哈希表统计的左指针指向的数据的个数为0,则将该数从哈希表中移除,然后移动左指针(注意!是先减再移,不能先移再减)。直到种数小于等于2时,退出循环。
还需初始化一个变量len,用于记录子数组的长度,此时len在while循环之外。因为len只记录种数小于等于2的数组长度,当进入while循环时,说明此时种数已经大于2了,无需记录数组长度。
代码
class Solution {
public:
int totalFruit(vector<int>& fruits) {
int len = 0;
map<int,int> cnt;
int left = 0;
for(int right = 0;right<fruits.size();++right){
cnt[fruits[right]] += 1;
while(cnt.size() > 2){
cnt[fruits[left]] -= 1;
if(cnt[fruits[left]] == 0){
cnt.erase(fruits[left]);
}
left++;
}
len = max(len,right-left+1);
}
return len;
}
};
76.最小覆盖字串
题目链接:76. 最小覆盖子串 - 力扣(LeetCode)
思路
题目要求
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
分析
初始化两个哈希表s_cnt,t_cnt用于统计s、t中的字符个数。首先遍历t,统计t中的字母个数。
初始化变量min_left(记录最小字串的左端)、min_right(记录最小字串的右段)、left、right
接着初始化左右指针指向s的首部,右指针遍历字符串s,当出现左右指针的子串完全包含t的情况时,判断right-left是否小于min_right-min_left,即该子串是否为最小子串,若是,则记录,反之,则跳过。当遍历完s后,判断min_left是否为-1,如果是,证明s中不存在涵盖t所有字符的子串,此时返回空字符串,反之返回子串。
代码
class Solution {
public:
bool is_covered(unordered_map<char,int>& s_cnt,unordered_map<char,int>& t_cnt){
for(char i = 'A';i<='Z';++i){
if(s_cnt[i]<t_cnt[i]) return false;
}
for(char i = 'a';i<='z';++i){
if(s_cnt[i]<t_cnt[i]) return false;
}
return true;
}
string minWindow(string s, string t) {
unordered_map<char,int> s_cnt;
unordered_map<char,int> t_cnt;
for(char x:t){
t_cnt[x]++;
}
int min_left = -1,min_right = s.size();
int left = 0;
for(int right = 0;right<s.size();++right){
s_cnt[s[right]]++;
while(is_covered(s_cnt,t_cnt)){
if(right-left<min_right-min_left){
min_left = left;
min_right = right;
}
s_cnt[s[left]]--;
left++;
}
}
return min_left == -1?"":s.substr(min_left,min_right-min_left+1);
}
};
59.螺旋矩阵Ⅱ
文章链接:代码随想录
题目链接:59. 螺旋矩阵 II - 力扣(LeetCode)
思路
题目描述
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
分析
一、使用vector新建一个n*n的矩阵。
二、初始化startx,starty为0,表示转圈的行起点和列起点。
三、计算圈数loop为n/2,若n为偶数,则转完时,矩阵刚好填充完;若n为奇数,则转弯时,最中间的值需要手动进行赋值,此时最中间的坐标为[startx,starty]。初始化变量offset为1,因为遍历时要遵循左闭右开的原则,需要用offset来控制边的尾部。
四、进行while循环进行转圈遍历,循环条件为(loop--),遵循左闭右开的原则,即每次处理一条边时,处理边的首部,不处理边的尾部。每循环完一次,startx、starty、offset都要进行加1。
五、处理n为奇数的情况,进行单独赋值。
六、返回矩阵即可。
代码
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> matrix(n,vector<int>(n,0));
int startx = 0,starty = 0;
int quanshu = n/2;
int offset = 1;
int cnt = 1;
while(quanshu--){
int i = startx,j = starty;
for(;j<n-offset;j++){
matrix[i][j] = cnt++;
}
for(;i<n-offset;i++){
matrix[i][j] = cnt++;
}
for(;j>starty;j--){
matrix[i][j] = cnt++;
}
for(;i>startx;i--){
matrix[i][j] = cnt++;
}
startx++;
starty++;
offset++;
}
if(n % 2 == 1){
matrix[startx][starty] = cnt;
}
return matrix;
}
};
54.螺旋矩阵
题目链接:54. 螺旋矩阵 - 力扣(LeetCode)
思路
题目描述
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
分析
该题与59的区别在于,给定的矩阵的行和列不一定是相等的,所以需要一些额外的操作。
一、使用变量minimum来记录行和列的最小值,即minimum = min(m,n);
二、遍历的圈数loop由minimum来决定,即loop = minimum/2;
三、while循环遍历时,遍历列用n,遍历行用m(不要都顺手写成了n,不然会报错)。
四、while循环结束后,需判断minimum是奇数还是偶数,若为偶数,则说明矩阵已全部遍历完毕,若为奇数,则需要判断minimum是行还是列,若为行,则说明列大,需单独取剩余元素,若为列,则说明行大,需单独取剩余元素。
代码
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> ans;
int m = matrix.size();
int n = matrix[0].size();
int minimum = min(m,n);
int quanshu = minimum/2;
int startx = 0,starty = 0;
int offset = 1;
while(quanshu--){
int i = startx,j = starty;
for(;j<n-offset;++j){
ans.push_back(matrix[i][j]);
}
for(;i<m-offset;++i){
ans.push_back(matrix[i][j]);
}
for(;j>starty;--j){
ans.push_back(matrix[i][j]);
}
for(;i>startx;--i){
ans.push_back(matrix[i][j]);
}
startx++;
starty++;
offset++;
}
if(minimum % 2 == 1){
if(minimum == m){
for(int j = starty;j<=n-offset;++j){
ans.push_back(matrix[startx][j]);
}
}
else if(minimum == n){
for(int i = startx;i<=m-offset;++i){
ans.push_back(matrix[i][starty]);
}
}
}
return ans;
}
};
卡码网44.开发商购买土地
文章链接:代码随想录
题目链接:44. 开发商购买土地(第五期模拟笔试)
思路
题目描述
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。
然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。 为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。
注意:区块不可再分。
输入描述
第一行输入两个正整数,代表 n 和 m。
接下来的 n 行,每行输出 m 个正整数。
输出描述
请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
分析
该题目含义是将一个n*m矩阵通过横切或纵切的方式分为两个矩阵,且要求这两个矩阵的差值最小。
一、建立一个n*m的矩阵,初始化变量sum为0(sum用于记录矩阵的总值),边填充矩阵,边用sum记录总值。
二、初始化一个长度为n的数组,用于记录矩阵的行区间和,初始化一个长度为m的数组,用于记录矩阵的列区间和。
三、遍历行区间和,记录区间相减的最小值,遍历列区间和,记录区间相减的最小值。
四、比较并返回最小值。
代码
#include <iostream>
#include <vector>
#include <climits>/*若要使用INT_MAX,需引入该库*/
using namespace std;
int main(){
int n,m;
cin>>n>>m;
int sum = 0;
vector<vector<int>> matrix(n,vector<int>(m,0));
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
cin>>matrix[i][j];
sum += matrix[i][j];
}
}
vector<int> hang(n,0);
vector<int> lie(m,0);
for(int i = 0;i<n;++i){
for(int j = 0;j<m;++j){
hang[i] += matrix[i][j];
}
}
for(int j = 0;j<m;++j){
for(int i = 0;i<n;++i){
lie[j] += matrix[i][j];
}
}
int res_hang = INT_MAX,res_lie = INT_MAX;
int res_sum_hang = 0;
int res_sum_lie = 0;
for(int i=0;i<n;++i){
res_sum_hang += hang[i];
res_hang = min(res_hang,abs(sum-res_sum_hang-res_sum_hang));
}
for(int j = 0;j<m;++j){
res_sum_lie += lie[j];
res_lie = min(res_lie,abs(sum-res_sum_lie-res_sum_lie));
}
cout<<min(res_hang,res_lie);
return 0;
}