LeetCode——567. 字符串的排列

文章介绍了LeetCode上的一道题目,要求判断字符串s2是否包含s1的排列。提供了两种C++解法,一种使用滑动窗口,另一种使用双指针,分别详细解释了代码逻辑,并分析了时间复杂度和空间复杂度。

一、题目

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

换句话说,s1 的排列之一是 s2 的子串
在这里插入图片描述

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/permutation-in-string/description/

二、C++解法

我的思路及代码

滑动窗口

采用 left 和 right 来维护窗口当前的大小,两个 map 为 need 和 win 分别维护当前字串中所含有的各个字符的个数和当前窗口中含有目标字符的个数,valid 来维护当前窗口内满足需求的字符个数。总体思路为,先初始化窗口内的目标字符数量,然后同步扩大 left 和 right ,当 valid = need 的大小时,就说明此时的子串已经满足了需求,返回 true 即可,当 while 结束后说明不能满足条件,返回 false 。

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        if(s1.size()>s2.size()) return false;
        int left,right,valid;
        left = valid = 0;
        right = s1.size();//维护一个大小为s1.size的窗口
        unordered_map<char,int> need,win;

        //初始化need表中的有效元素
        for(int i=0;i<s1.size();i++)
            need[s1[i]]++;

        //初始化窗口中的有效元素
        for(int i=0;i<s1.size();i++){
            if(need.count(s2[i])){
                win[s2[i]]++;
                if(need[s2[i]] == win[s2[i]])
                    valid++;
            }     
        }

        //右指针越界的时候遍历结束        
        while(right<s2.size()){
            //判断是否满足返回条件,放在前面是因为初始化valid和need后还木有进行判断,所以开始判断一次
           if(valid == need.size())
                return true;

            char c = s2[left];
            left++;

            if(need.count(c)){
                if(need[c] == win[c])
                    valid--;
                win[c]--;
            }
                
            c = s2[right];
            right++;

            if(need.count(c)){
                win[c]++;
                if(need[c] == win[c])
                    valid++;
            }
        }
        //结尾的时候right越界,但是还没有进行最后的判断,所以在返回时一并处理
        return valid == need.size()?true:false; 
    }
};
  • 时间复杂度:O(n+m+∣Σ∣),其中 n 是字符串 s1的长度,m 是字符串 s2的长度,Σ 是字符集,这道题中的字符集是小写字母,∣Σ∣=26
  • 空间复杂度:空间复杂度:O(∣Σ∣)

官方参考代码

双指针

在这里插入图片描述

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        int n = s1.length(), m = s2.length();
        if (n > m) {
            return false;
        }
        vector<int> cnt(26);
        for (int i = 0; i < n; ++i) {
            --cnt[s1[i] - 'a'];
        }
        int left = 0;
        for (int right = 0; right < m; ++right) {
            int x = s2[right] - 'a';
            ++cnt[x];
            while (cnt[x] > 0) {
                --cnt[s2[left] - 'a'];
                ++left;
            }
            if (right - left + 1 == n) {
                return true;
            }
        }
        return false;
    }
};
  • 时间复杂度:O(n+m+∣Σ∣),其中 n 是字符串 s1的长度,m 是字符串 s2的长度,Σ 是字符集,这道题中的字符集是小写字母,∣Σ∣=26
  • 空间复杂度:空间复杂度:O(∣Σ∣)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天地神仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值