算法刷题-数组

算法刷题

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;
    }

滑动窗口:

    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 ( 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;
    }

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;
    }

54. 螺旋矩阵-模拟

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

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

你可能感兴趣的:(ACM-,ICPC,#,Leetcode,算法)