【LeetCode】滑动窗口解决字符串问题

滑动窗口

  • 209. 长度最小的子数组
    • 题目描述
    • 方法1 暴力搜索 复杂度为O(n3)
    • 方法2 滑动窗口
    • 方法3 二分查找
  • 3. 无重复字符的最长子串
    • 题目描述
    • 方法1 标准格式的滑动窗口
    • 方法2 使用while循环直到将左指针滑到合适位置
  • 438. 找到字符串中所有字母异位词
    • 题目描述
    • 算法实现
      • 三级目录
  • 76. 最小覆盖子串
    • 题目描述
    • 算法实现
  • 总结滑动窗口公式

209. 长度最小的子数组

题目描述

【LeetCode】滑动窗口解决字符串问题_第1张图片

方法1 暴力搜索 复杂度为O(n3)

   int minSubArrayLen(int s, vector<int>& nums) {
        //int sum = 0;
        int minlen = nums.size() + 1;
        for (int i = 0;i < nums.size();i++)
        {
            int subsum = 0;
            for (int j = i;j < nums.size();j++)
            {
                int len = j - i + 1;
                subsum += nums[j];
                if (subsum >= s)
                {
                    minlen = min(minlen, len);
                }
            }
        }
        return minlen == nums.size() + 1 ? 0 : minlen;
    }

方法2 滑动窗口

    int minSubArrayLen(int s, vector<int>& nums) {
        //int sum = 0;
        int minlen = nums.size() + 1;
        int l = 0;//[l,r]为满足条件的字符串
        int r = -1;
        int sum = 0;
        while (l < nums.size())
        {
            if(sum<s&&r+1<nums.size())
            {
                sum += nums[++r];
            }
            else 
            {
                sum -= nums[l++];
            }
            if (sum >= s)
            {
                minlen = min(minlen, r - l + 1);
            }
        }
        return minlen == nums.size() + 1 ? 0 : minlen;
    }

方法3 二分查找

    int binarysearch(int l, int r, int* nums, int target)
    {
        int k = l;//[l..mid]
        while (l <= r)
        {
            int mid = l + (r - l) / 2;
            if (l==r)//循环结束条件
            {
                if(nums[l] >=target)
                    return l;
                else //没有找到
                {
                    return -1;
                }
            }
            else if (nums[mid] < target)//小于 mid不可能是目标
            {
                l = mid+1;//抛弃mid
            }
            else//大于等于目标 那么mid有可能是要找到目标
            {
                r = mid;
            }
        }
        return -1;//一般不会出现
    }
    int minSubArrayLen(int s, vector<int>& nums) {
        //int sum = 0;
        int minlen = nums.size() + 1;
        int len = nums.size();
        if (len == 0)return 0;
        int* sums = new int[len];
        sums[0] = nums[0];
        for (int i = 1;i < len;i++)
        {
            sums[i] = sums[i - 1] + nums[i];//求和
        }
        int l = 0;
        int r = len - 1;
        for (int i = 0;i < len;i++)
        {
            int target = s + sums[i] - nums[i];//保证s[j]-s[i]+nums[i]>=s 所以 s[j]>=s+s[i]-nums[i]
            int ret = binarysearch(i, r, sums, target);//二分查找
            if (ret - i + 1 < minlen && ret != -1)
            {
                minlen = ret - i + 1;
            }
        }
        return minlen == nums.size() + 1 ? 0 : minlen;
    }

3. 无重复字符的最长子串

题目描述

【LeetCode】滑动窗口解决字符串问题_第2张图片

方法1 标准格式的滑动窗口

    int lengthOfLongestSubstring1(string s) {
        int freq[256] = { 0 };
        int l = 0, r = -1;
        int res = 0;
        while (l < s.size())
        {
            if (r + 1 < s.size() && freq[s[r + 1]] == 0)
            {
                freq[s[++r]]++;
            }
            else
            {
                freq[s[l++]]--;
            }
            res = max(res, r - l + 1);
        }
        return res;

    }

方法2 使用while循环直到将左指针滑到合适位置

比较复杂 逻辑混乱 边界还容易错

      int lengthOfLongestSubstring(string s) {
            int freq[256] = { 0 };
            int l = 0, r = -1;
            int res = 0;
            while (l < s.size() && r + 1 < s.length())
            {
                if (r + 1 < s.length() && freq[s[r + 1]] == 0)
                {
                    freq[s[++r]] ++;
                }
                else
                {
                    while (freq[s[r + 1]] != 0)
                    {
                        freq[s[l++]]--;
                    }
                    if (r + 1 < s.length())
                    {
                        freq[s[++r]] ++;
                    }
                }
                res = max(res, r - l + 1);
            }
            return res;
        }

438. 找到字符串中所有字母异位词

题目描述

【LeetCode】滑动窗口解决字符串问题_第3张图片

算法实现

    vector<int> findAnagrams(string s, string p) {
        int freq1[256] = { 0 };
        int freq2[256] = { 0 };
        vector<int> res;
        for (int i = 0;i < p.length();i++)
        {
            freq2[p[i]]++;
        }
        int l = 0;
        int r = -1;
        while (l < s.size())
        {
            if (freq1[s[r + 1]] < freq2[s[r + 1]])
            {
                r++;
                freq1[s[r]]++;
            }
            else
            {
                freq1[s[l]]--;
                l++;
            }
            if(r-l+1==p.size())
            {
                res.push_back(l);
            }

        }
        return res;
    }

三级目录

76. 最小覆盖子串

题目描述

【LeetCode】滑动窗口解决字符串问题_第4张图片

算法实现

感觉不是很清楚 但是做对了 有空再看

    string minWindow(string s, string t) {
        int freq1[256] = { 0 };
        int freq2[256] = { 0 };
        vector<int> res;
        for (int i = 0;i < t.length();i++)
        {
            freq2[t[i]]++;
        }
        int need = t.length();
        int l = 0;
        int fl = -1;
        int fr = -1;
        int r = -1;
        int mins = s.size()+1;
        while (l < s.size())
        {
            if (need > 0&&r+1<s.size())
            {
                r++;
                freq1[s[r]]++;
                if (freq1[s[r ]]>0&& freq1[s[r]] <= freq2[s[r ]])
                {
                    need = need -1;
                }
            }
            else
            {

                freq1[s[l]]--;
                
                if (freq1[s[l]] < freq2[s[l]] && freq2[s[l]] != 0)
                {
                    need++;
                }
                l++;
            }
            if (need == 0)
            {
                if (r - l + 1 < mins)
                {
                    mins = min(mins, r - l + 1);
                    fl = l;
                    fr = r;
                }
            }

        }
        string ret;
        if (mins != s.size() + 1)
        {
            for (int i = fl;i <= fr;i++)
            {
                ret+=s[i];
            }
        }
        return ret;

    }

总结滑动窗口公式

我写了一首诗,把滑动窗口算法变成了默写题

        int l = 0;//左边界
        int r = -1;//右边界
        while (l < s.size())//停止条件一般为右边界小于size
        {
            if (freq1[s[r + 1]] < freq2[s[r + 1]])//右指针滑动条件 可以加上边界条件 如r + 1 < s.size() r+1位置的元素满足条件
            {
                r++;
                freq1[s[r]]++;
            }
            else
            {
                freq1[s[l]]--;//否则就左指针滑动
                l++;
            }
            if(r-l+1==p.size())//题目要求 最长最短等等目的
            {
                res.push_back(l);
            }

        }
        return res;
    }

你可能感兴趣的:(做题)