[Sliding window] algorithm practice


1. Algorithm principle

滑动窗口, as the name suggests, is a window with a variable size, and the left and right ends slide forward in the same direction (The right end is fixed, the left end slides; the left end is fixed, the right end slides)。

insert image description here

The essence of the sliding window is actually a double-pointer algorithm. It is based on 单调性the idea of ​​using " double pointers in the same direction " to index a range in a string or list [left,right].

The steps of a sliding window are generally as follows:

1. Use the left and right pointer technique in the double pointer in the sequence, initialize left = right = 0, and call the index closed interval [left, right]a window.
2. First continuously increase the right pointer to expand the window [left, right] until the sequence in the window meets the requirements.
3. At this time, stop increasing the right, and continuously increase the left pointer to shrink the window [left, right] until the sequence in the window no longer meets the requirements. At the same time, each time before adding left, a round of results must be updated.
4. Repeat steps 2 and 3 until right reaches the end of the sequence.


2. Algorithm combat

1. leetcode209 minimum length subarray

insert image description here
The smallest subarray

Problem-solving ideas:

insert image description here

Code:

class Solution {
    
    
public:
    int minSubArrayLen(int target, vector<int>& nums) {
    
    
        int left = 0, right = left, n = nums.size() - 1;
        int Min = 0, sum = 0;
        while(right <= n)
        {
    
    
            sum += nums[right];
            while(sum >= target)
            {
    
    
                int tmp = right - left + 1;
                Min = Min == 0 ? tmp : min(tmp, Min);
                sum -= nums[left++];
            }
            right++;
        }
        
        return Min;
    }
};

insert image description here


2. leetcode3 longest substring without repeating characters

insert image description here
Longest string without repeating characters

Problem-solving ideas: sliding window + hash table

The title requires no repeated characters. In order to count the number of occurrences of each character, here we can use a hash table to count the number of occurrences of each character.

insert image description here

Code:

class Solution {
    
    
public:
    //滑动窗口问题
    int lengthOfLongestSubstring(string s) {
    
    
        int hash[128] = {
    
    0};
        int n = s.size() - 1, len = 0;
        for(int left = 0, right = 0; right <= n; right++)
        {
    
    
            hash[s[right]]++; // 进窗口
            while(hash[s[right]] > 1)
            {
    
    
                hash[s[left]]--;//不满足要求,出窗口,直到满足要求为止
                left++;
            }
            len = max(len, right - left + 1);
        }
        return len;
    }
};

insert image description here


3. leetcode1004 maximum number of consecutive 1s

insert image description here
Maximum number of consecutive 1's III

Problem-solving ideas:

Because the array is 1 except for 0, the title requires that we can only flip k 0s at most, and we are looking for the longest continuous number of 1s after flipping k 0s.

We can change our thinking: find the longest sub-array, the number of 0s in the sub-array does not exceed k.

insert image description here

Code:

class Solution {
    
    
public:
    int longestOnes(vector<int>& nums, int k) {
    
    
        int n = nums.size();
        int zero = 0, ret = 0;
        for(int left = 0, right = 0; right < n; right++)
        {
    
    
            if(nums[right] == 0)
                zero++;
            while(zero > k)
            {
    
    
                if(nums[left] == 0)
                    zero--;
                left++;
            }
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

insert image description here


4. leetcode1685 The smallest operand to reduce x to 0

insert image description here
Minimum number of operands to decrement x to 0

We can further transform this problem: convert to --> find the length of the longest sub-array, the sum of all elements is exactly equalsum-x , and then use the sliding window to solve it.

Code:

class Solution {
    
    
public:
    int minOperations(vector<int>& nums, int x) {
    
    
        int n = nums.size();
        int sum = 0, target = 0;
        for(int i = 0; i < n; i++)
            sum += nums[i];
        target = sum - x, sum = 0;
        int len = -1;
        
        if(target < 0) return -1;
        for(int left = 0, right = 0; right < n; right++)
        {
    
    
            sum += nums[right]; // 进窗口
            while(sum > target) // 判断
            {
    
    
                sum -= nums[left++]; // 出窗口
            }
            if(sum == target) // 更新结果
                len = max(len, right - left + 1);
        }
        
        return len == -1 ? len : n - len;
    }
};

insert image description here


5. leetcode904 fruit basket

insert image description here
fruit basket

The solution to this problem is to use the sliding window + hash table . The elements in the array represent the number of the fruit type. We only need to use the sliding window to solve the problem. Find the fruit type in the basket that does not exceed 2. Find out The longest window will do.

Code:

class Solution {
    
    
public:
    int totalFruit(vector<int>& fruits) {
    
    
        int n = fruits.size(), hash[100010] = {
    
    0}, kinds = 0, len = 0;
        for(int left = 0, right = 0; right < n; right++)
        {
    
    
            if(++hash[fruits[right]] == 1) // 进窗口
                kinds++;
            while(kinds > 2) // 判断
            {
    
    
                if(--hash[fruits[left++]] == 0) // 出窗口
                    kinds--;
            }
            if(kinds <= 2) // 更新结果
                len = max(len, right - left + 1);
        }
        return len;
    }
};

insert image description here


6. leetcode438 find all anagrams in a string

insert image description here
Find all anagrams in a string

This question still uses sliding window + hash table , we can first count the number of occurrences in the target word and map it to the hash table. Maintain a variable cnt that judges the number of valid characters in the window , and use the sliding window to traverse from left to right. Here, because the length of the word is fixed, every time you enter a window, if the length of the window is greater than the length of the word, You must let the leftmost element out of the window.

Code:

class Solution {
    
    
public:
    vector<int> findAnagrams(string s, string p) {
    
    
        vector<int> ret;
        int hash1[26] = {
    
    0}, hash2[26] = {
    
    0}, len = p.size();
        for(auto&e : p)
            hash2[e - 'a']++;
        int cnt = 0;//判断窗口中的有效字符
        for(int left = 0, right = 0; right < s.size(); right++)
        {
    
    
            if(++hash1[s[right] - 'a'] <= hash2[s[right] - 'a']) //进窗口
                cnt++;
            if(right - left + 1 > len) // 判断
            {
    
    
                if(--hash1[s[left] - 'a'] < hash2[s[left] - 'a']) //出窗口
                    cnt--;
                left++;
            }
            //判断结构是否合法
            if(cnt == len) // 更新结果
                ret.emplace_back(left);
        }
        return ret;
    }
};

insert image description here


7. leetcode30 concatenates substrings of all words

insert image description here
Concatenate all word substrings

This question is very similar to the previous question, except that the previous question solved characters, and this question solved strings. The method still used is sliding window + hash table , because I told us in advance here-each word in the target string array has the same length. So according to this condition we can greatly reduce the time complexity.

insert image description here

What we need to pay attention to here is that during the process of entering and exiting the window, the moving step of the sliding window is the length of the word, and the number of times the sliding window is executed is the length of the word.

Code:

class Solution {
    
    
public:
    vector<int> findSubstring(string s, vector<string>& words) {
    
    
        unordered_map<string,int> hash2;//开两个哈希表
        for(auto& e : words)
            hash2[e]++;
        vector<int> ret;
        ret.reserve(s.size());
        int len = words.size(), cnt = 0, n = words[0].size();
        for(int i = 0; i < n; i++) // 执行n次
        {
    
    
            unordered_map<string,int> hash1; // 维护窗口内单词的频次
            cnt = 0; 
            for(int left = i, right = i + n; right <= s.size(); right += n)
            {
    
    
                string tmp = s.substr(right - n, n);
                if(hash2.count(tmp) && ++hash1[tmp] <= hash2[tmp])
                    cnt++;
                if(right - left > n*len) // 出窗口,维护cnt
                {
    
    
                    string tmp = s.substr(left, n);
                    if(hash2.count(tmp) && --hash1[tmp] < hash2[tmp])
                        cnt--;
                    left += n;
                }
                if(cnt == len) // 更新结果
                    ret.emplace_back(left);
            }
        }
        return ret;
    }
};

insert image description here


8. leetcode76 minimum coverage substring

insert image description here
minimum covering substring

The types of characters in our target string t given here may be repeated. ”找到字符串中所有字母异位词“It is different from the above topic :Here, the judgment condition when we enter the window should be: when the number of characters appearing in the window is equal to the number of a certain character in the target string, the variable cnt++ will ensure that the number of characters entering the window at the end is equal to the specified characters in the target string The number of hours, that is, when the update condition is met, in the 字符的种类 == 目标字符串window 窗口中的字符个数一定是 >= 目标字符串的字符. It is guaranteed that the string in the window must be able to completely cover the target string. Finally, in the loop that satisfies the judgment update condition, the window is continuously opened until it cannot be opened again.

Code:

class Solution {
    
    
public:
    string minWindow(string s, string t) {
    
    
        int hash1[128] = {
    
    0}, hash2[128] = {
    
    0}, kinds = 0;
        for(auto ch : t)
            if(hash2[ch]++ == 0) kinds++;
        int cnt = 0, Min = INT_MAX, begin = -1;
        for(int left = 0, right = 0; right < s.size(); right++)
        {
    
    
            if(++hash1[s[right]] == hash2[s[right]])
                cnt++;
            while(cnt == kinds)
            {
    
    
                if(right - left + 1 < Min)
                    Min = right - left + 1, begin = left;
                char out = s[left++];
                if(hash1[out]-- == hash2[out])
                    cnt--;
            }
        }
        if(begin == -1) return "";
        else return s.substr(begin, Min);
    }
};

insert image description here


3. Summary

Sliding window algorithms perform the required operation on an array or string given a specific window size. This technique can turn the nested loops in a part of the problem into a single loop, so it can reduce the time complexity. In short, the sliding window algorithm operates on a string or array of a specific size, not on the entire string or array, which reduces the complexity of the problem and thus reduces the nesting depth of the loop .


Guess you like

Origin blog.csdn.net/m0_67595314/article/details/131906034