LeetCode 209. 长度最小的子数组 (滑动窗口 || 前缀和+二分查找)

长度最小的子数组
题意:
找到一个长度最小的子串,使得子串的和大于等于给定的s。

像这种子串最优解的问题,很多时候都可以用滑动窗口。此题用Sliding window 也是最明显的。

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& a) {
        int ans = 1e9,n = a.size();
        int l = 0 ,r = 0 ,cnt = 0;
        while(l<n){
            while(r<n && cnt<s){
                cnt += a[r++];
            }
            if(cnt>=s) ans = min(ans,r-l);
            cnt -= a[l];
            l++;
        }
        return ans==1e9?0:ans;
    }
};

如果用纯暴力法呢?
那就应该是枚举每一个位置作为子串的起点,然后挨个向后枚举,看看最近的终点在哪,(可以使得子串和大于等于s)?
由于题目给定所有的数都是正整数,所以完全可以二分查找最小的 r r ,使得,对于枚举的 l l ,使得 s [ r ] s [ l ] > = s s[r]-s[l]>=s
整体时间复杂度: O ( n l o g ( n ) ) O(n*log(n))

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& a) {
        int ans = 1e9 , n = a.size();
        vector<int> pre(n);
        if(n==0) return 0;
        pre[0] = a[0];
        for(int i=1;i<n;i++){
            pre[i] = pre[i-1]+a[i];
        }
        for(int i=0;i<n;i++){
            if((i==0 && pre[n-1]<s)|| (i && pre[n-1]-pre[i-1]<s)){continue;}
            int l = i,r = n-1;
            while(l<r){
                int mid = (l+r)/2 ,sum;
                if(i) sum = pre[mid]-pre[i-1];
                else sum = pre[mid];
                if(sum<s){
                    l = mid+1;
                }else{
                    r = mid;
                }
            }
            ans = min(ans,l-i+1);
        }
        return ans==1e9?0:ans;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/107309042
今日推荐