• 算法刷题-数组


    算法刷题

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

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

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

    思路

    二分:

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

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

    时间复杂度为 O ( n l o g n ) 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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    滑动窗口:

        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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

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

    思路

    滑动窗口:

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

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

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

    时间复杂度为 O ( 26 n ) 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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    59. 螺旋矩阵 II-模拟

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

    思路

    按照题目模拟即可

    代码

    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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    54. 螺旋矩阵-模拟

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

    输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
    输出:[1,2,3,6,9,8,7,4,5]
    
    • 1
    • 2
    输入: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]
    
    • 1
    • 2

    思路

    模拟。

    代码

        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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

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

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

    示例 1:

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

    示例 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]
    
    • 1
    • 2

    思路

    模拟

    代码

        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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    Databricks notebook里面插入图片步骤图示
    语言大模型推理加速指南
    SpringSecurity+ Oauth2.0+JWT 0-1
    备战数学建模34-BP神经网络预测2
    算法通关村——滑动窗口高频问题
    JAVA中单例设计模式详解与实现方式
    MySQL进阶实战6,缓存表、视图、计数器表
    VSCode使用Qt的MinGW作为编译器编译C++
    将 Vue.js 项目部署至静态网站托管,并开启 Gzip 压缩
    【自动化测试】selenium工具
  • 原文地址:https://blog.csdn.net/m0_74085417/article/details/133976454