跳到主要内容

算法刷题

209. 长度最小的子数组-二分或者滑动窗口

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0

思路

二分:

因为数据都是大于0的,因此数组的前缀和数组是单调增的,

我们遍历每一个元素,二分去小最小的满足s[r]-s[l-1]>=target的位置即可。

时间复杂度为O(nlogn)O(nlogn)

或者 :滑动窗口

维护一个变量sum,记录区间的和

两个指针l,r 指向区间的尾巴和头部,每次迭代,将nums[r]加入到sum中,

  • 如果满足sum>=target了,更新res,并且指针l右移,直到不满足sum>=target

代码

二分:

    int minSubArrayLen(int target, vector<int>& nums) {
int res=1e6;
int n=nums.size();
vector<int> s(n+10);
for(int i=1;i<=n;i++) s[i]=s[i-1]+nums[i-1];
for(int i=1;i<=n;i++){
int l=i,r=n;
while(l<r){
int m=(l+r)>>1;
if(s[m]-s[i-1]>=target) r=m;
else l=m+1;
}
if(s[l]-s[i-1]>=target){
res=min(res,l-i+1);
}
}
if(res==1e6) res=0;
return res;
}

滑动窗口:

    int minSubArrayLen(int target, vector<int>& nums) {
int res=1e6;
int l=0,r=0;
int sum=0;
int n=nums.size();
for(;r<n;r++){
sum+=nums[r];
while(sum>=target) res=min(res,r-l+1),sum-=nums[l++];
}
if(res==1e6) res=0;
return res;
}

904. 水果成篮-滑动窗口

你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

  • 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
  • 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
  • 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。

给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

思路

滑动窗口: 定义两个指针:指向区间的开始和结尾

开一个哈希表来记录区间内每个元素出现的次数,

如果哈希表的长度大于2了,那么就从左边开始删

注意当哈希表内没有这个元素的时候,需要删除key

代码

    int totalFruit(vector<int> &fruits) {
int n = fruits.size();
map<int, int> mp;
int l = 0, res = 0;
for (int r = 0; r < n; r++) {
mp[fruits[r]]++;
while (mp.size() > 2) {
auto it= mp.find(fruits[l]);
it->second--;
if (mp[fruits[l]] == 0) mp.erase(it);
l++;
}
res = max(res, r - l + 1);
}
return res;
}

76. 最小覆盖子串-滑动窗口

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""

思路

滑动窗口:

开两个哈希表,tt记录t中每个字符出现的次数,ss记录窗口中每个字符出现的次数

遍历字符串的右端点,每次去check是不是满足tt的字符包含于ss的字符个数。

如果满足,那么就可以不断缩小左端点,更新答案

时间复杂度为O(26n)O(26n)

代码

    string minWindow(string s, string t) {
int n = s.size();
map<int, int> tt, ss;
for (char c: t) tt[c]++;
int len = 1e6, ansL = -1;
int l = 0, r = -1;
auto check = [&]() -> bool {
for (auto [x, y]: tt) {
if (ss[x] < y) return false;
}
return true;
};
while (r < n) {
if (tt.find(s[++r]) != tt.end()) ss[s[r]]++;
while (check() && l <= r) {
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
}
if (tt.find(s[l]) != tt.end()) ss[s[l]]--;
l++;
}
}
string res = "";
if (ansL != -1) res = s.substr(ansL, len);
return res;
}

59. 螺旋矩阵 II-模拟

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

img

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

思路

按照题目模拟即可

代码

vector<vector<int>> generateMatrix(int n) {
int l=0,r=n-1,b=n-1,t=0;
vector<vector<int>> res(n,vector<int>(n));
int num=1,tar=n*n;
while(num<=tar){
for(int i=l;i<=r;i++) res[t][i]=num++;
t++;
for(int i=t;i<=b;i++) res[i][r]=num++;
r--;
for(int i=r;i>=l;i--) res[b][i]=num++;
b--;
for(int i=b;i>=t;i--) res[i][l]=num++;
l++;
}
return res;
}

54. 螺旋矩阵-模拟

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

img

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

思路

模拟。

代码

    vector<int> spiralOrder(vector<vector<int>>& matrix) {
int n=matrix.size(),m=matrix[0].size();
vector<int> res;
int l=0,r=m-1,t=0,b=n-1;
int sum=n*m;
while(sum){
for(int i=l;i<=r;i++) res.push_back(matrix[t][i]),sum--;
if(++t>b) break;
for(int i=t;i<=b;i++) res.push_back(matrix[i][r]),sum--;
if(--r<l) break;
for(int i=r;i>=l;i--) res.push_back(matrix[b][i]),sum--;
if(--b<t) break;
for(int i=b;i>=t;i--) res.push_back(matrix[i][l]),sum--;
if(++l>r) break;
}
return res;
}

LCR 146. 螺旋遍历二维数组-模拟

给定一个二维数组 array,请返回「螺旋遍历」该数组的结果。

螺旋遍历:从左上角开始,按照 向右向下向左向上 的顺序 依次 提取元素,然后再进入内部一层重复相同的步骤,直到提取完所有元素。

示例 1:

输入:array = [[1,2,3],[8,9,4],[7,6,5]]
输出:[1,2,3,4,5,6,7,8,9]

示例 2:

输入:array  = [[1,2,3,4],[12,13,14,5],[11,16,15,6],[10,9,8,7]]
输出:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

思路

模拟

代码

    vector<int> spiralArray(vector<vector<int>>& a) {
vector<int> res;
if(a.empty()) return res;
int n=a.size(),m=a[0].size();
int l=0,t=0,r=m-1,b=n-1;
while(1){
for(int i=l;i<=r;i++) res.push_back(a[t][i]);
if(++t>b) break;
for(int i=t;i<=b;i++) res.push_back(a[i][r]);
if(--r<l) break;
for(int i=r;i>=l;i--) res.push_back(a[b][i]);
if(--b<t) break;
for(int i=b;i>=t;i--) res.push_back(a[i][l]);
if(++l>r) break;
}
return res;
}