踩坑记录[8]——LeetCode 567题:字符串的排列

踩坑记录[8]——LeetCode 567题:字符串的排列

题目描述

题目链接

给你两个字符串 s1s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false

换句话说,s1 的排列之一是 s2子串

示例 1:

输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").

示例 2:

输入:s1= "ab" s2 = "eidboaoo"
输出:false

答案(C++语言,已通过LeetCode测试)

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
      unordered_map<char, int> need, window;
      for (auto c: s1) need[c]++;
      int left = 0, right = 0;
      int value = 0;

      while(right < s2.size()){
        
        char c = s2[right];
        right++;

        if(need.count(c)){
          window[c]++;
          if (window[c] == need[c])  value++;  // 相同时才++
        }

        while(value == need.size()){
          // 判断是否满足条件
          if ((right - left) == s1.size()){
            cout << left << right << s1.size() << endl;
            return true;
          }
          
          // 执行收缩窗口
          char c = s2[left];
          left++;

          if(need.count(c)){
            if (window[c] == need[c]) value--;
            window[c]--;
          }
        }
      }
      return false;

    }
};

方案描述

本题目主要利用滑动窗口的思想,在遍历过程中动态维护窗口,通过更新窗口内字符的出现次数来判断是否满足条件。具体步骤如下:

  1. 初始化映射表: 创建两个unordered_map,need用于存储字符串s1中字符的出现次数,window用于存储当前窗口内字符的出现次数。
  2. 滑动窗口遍历: 使用双指针leftright遍历s2字符串。
  3. 向右扩展窗口: 右指针right向右移动,每次移动将当前字符加入窗口window,并更新该字符在窗口中的出现次数。
  4. 检查窗口内字符是否满足要求: 检查窗口内字符的出现次数是否满足要求。如果window中某个字符的出现次数等于need中该字符的出现次数,则将value值加一。
  5. 收缩窗口: 当窗口内的字符已经满足要求时,开始收缩窗口。左指针left向右移动,每次移动将当前字符从窗口中移出,并更新窗口内该字符的出现次数。如果某个字符的出现次数小于need中该字符的出现次数,则将value值减一。
  6. 判断是否找到满足条件的窗口: 在窗口大小等于s1的长度时,即找到了一个长度与s1相等的子串。此时返回true
  7. 未找到满足条件的窗口: 如果遍历完整个s2字符串仍未找到满足条件的窗口,则返回false

踩坑记录

题目难度:中等

本题涉及到字符串的子串,一般需要考虑滑动窗口算法进行解决。滑动窗口算法本质上也是利用双指针,控制窗口的大小和移动。

  • 找到满足的字符串的条件是(right - left) == s1.size()

    而不是(right - left+1) == s1.size()这是因为在前面的时候有一个right++,即本轮中right已经比当前使用的多了1,所以不用再+1了。

思路参考

我写了首诗,把滑动窗口算法变成了默写题 | labuladong 的算法笔记

  • 26
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值