代码随想录学习记录——数组篇-长度最小的子数组

209、长度最小的子数组

本题我尝试了两层循环去解决问题,但是超时了

class Solution {
public:
    int minSubArrayLen(int target, vector& nums) {
        int minLen = nums.size() + 1;
        for(int i = 0; i < nums.size();i++){
            int sumCur = nums[i];
            int lenCur = 1;
            int j = i+1;
            while(sumCur < target && j < nums.size()){
                sumCur += nums[j];
                j++;
                lenCur++;
            }

            if(sumCur >= target){
                if(lenCur < minLen ){
                    minLen = lenCur;
                }
            }else{
                continue;
            }
        }
        if(minLen <= nums.size()){
            return minLen;
        }else{
            return 0;
        }
    }
};

观看了代码随想录的讲解,了解到了滑动窗口的概念,这里的关键思路便是:

  • 如果当前窗口内总和小于 t a r g e t target target,那么终止位置就需要往后移动,纳入新的值
  • 如果当前窗口内总和大于 t a r g e t target target,那么就需要判断是否是最小长度,同时移动起始位置
class Solution {
public:
    int minSubArrayLen(int target, vector& nums) {
        int result = INT32_MAX;
        int sum = 0;
        int i = 0;
        int subLength = 0;
        for( int j = 0; j < nums.size(); j++){
            sum += nums[j];
            while(sum >= target){
                subLength = (j - i + 1);
                if(subLength < result){
                    result = subLength;
                }
                sum -= nums[i++];
            }
        }
        if(result == INT32_MAX){
            return 0;
        }else{
            return result;
        }
    }
};
904、水果成篮

这一题的滑动窗口我在更新的时候一直理不清方法,因此也是参考了大佬的代码,用了哈希表来实现:

class Solution {
public:
    int totalFruit(vector& fruits) {
        unordered_map basket;
        int maxLen = 0;
        int curLen = 0;
        int startIndex = 0;
        for(int i = 0;i 2){  //如果当前有的大于2了,那么要缩减
                basket[fruits[startIndex]]--; //减去当前起始位置的
                if(basket[fruits[startIndex]] == 0){  //如果该类等于0就可以删除了
                    basket.erase(fruits[startIndex]);
                }
                startIndex++; // 移动,如果还是大于2还要继续减
                curLen--;
            }
            if(   maxLen < curLen ){
                maxLen = curLen;
            }
        }
        return maxLen;
    }
};
76、最小覆盖字串

该题可以用滑动窗口解决,但是难点在于如果判断当前窗口内的子串满足条件,因此字符串 t t t中的字符有可能是重复的。

看了大神的思路,具体为:

  • 用一个变量cnt来记录当前滑动窗口的子串中,拥有 t t t中所含有字符的个数

  • 用一个哈希表记录 t t t中字符和对应的频数,用另一个哈希表来记录滑动窗口中的字符和对应频数

  • 用两个指针 i i i 和 $ j$ 来表示滑动窗口的前后

  • cnt的更新规则:如果 c n t < t . s i z e ( ) cnt < t.size() cnt<t.size() 那么说明此时滑动窗口的子串还没达到要求,那么 i + + i++ i++ ,往后延伸,只有当 w i n F r e q [ s [ i ] ] < = t F r e q [ s [ i ] ] winFreq[s[i]] <= tFreq[s[i]] winFreq[s[i]]<=tFreq[s[i]] 的时候才 c n t + + cnt++ cnt++,因为这样才说明此时未满足要求仍然需要纳入目标字符;只有当 w i n F r e q [ s [ j ] ] > t F r e q [ s [ j ] ] winFreq[s[j]] > tFreq[s[j]] winFreq[s[j]]>tFreq[s[j]] 时,才可以将末尾的字符丢弃,这样仍然能够满足该字符的要求,即对 c n t cnt cnt不做修改。重点就是只要当前的子串中目标字符的个数仍然没够,我们就纳入目标字符并增加cnt,直到子串满足了(即 c n t = = t . s i z e ( ) cnt==t.size() cnt==t.size() ),那么就判断是否是最小,然后将窗口末尾开始收缩。

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map winFreq;
        unordered_map tFreq;
        for(auto c:t){
            tFreq[c]++;
        }
        int cnt = 0;
        string result;
        for( int i = 0,j = 0; i < s.size(); i++){
            winFreq[s[i]]++;
            if( winFreq[s[i]] <= tFreq[s[i]]){
                cnt++;
            }
            while(winFreq[s[j]] > tFreq[s[j]]){
                winFreq[s[j++]]--;
            }
            if(cnt == t.size()){
                if(result.empty() || i-j+1 < result.size()){
                    result = s.substr(j,i-j+1);
                }
            }
        }
        return result;
    }
};

你可能感兴趣的:(力扣刷题记录,学习,leetcode,算法,c++,动态规划)