【算法】滑动窗口——找到字符串中所有字母异位词

本节博客是对题目——找到字符串中所有字母异位词的从读题到代码实现以及优化的详细解读,有需要借鉴即可。

1.题目

题目链接:LINK
在这里插入图片描述

首先来解释一下什么是异位词,所谓“异位词”,即不要求字母顺序的字符串。

其实这个题目思路很快就可以想到,拿个left,right指针,使两者间距始终等于p字符串长度,再与p字符串对比一下就行了。

说起来这个思路那不就是“滑动窗口”嘛,因为两个指针都是从左到右移动的。
那异位怎么进行比较的呢?可以搞一个哈希数组进行依次比较即可。

2.滑动窗口 + 哈希数组

于是,我们可以写出下面的代码:

class Solution
{
public:
 bool check(int* p, int*s)
 {
    for(int i = 0;i < 128;i++)
    {
        if(p[i] != s[i])
        {
            return false;
        }
    }

    return true;
 }
 vector<int> findAnagrams(string s, string p) 
 {
    //统计一下p字符串的字符信息
    size_t len = p.size();
    int hash_p[128] = {0};
    for(int i = 0;i<len;i++)
    {
        hash_p[p[i]]++;
    }

    int n = s.size();
    int hash_s[128] = {0};
    vector<int> ret;
    //滑动窗口
    for(int right = 0,left = 0;right < n;right++)
    {
        //进窗口
        hash_s[s[right]]++;

        //判断,出窗口
        if(right - left + 1 > len)
        {
            hash_s[s[left]]--;
            left++;
        }

        //更新结果
        if(check(hash_p,hash_s) && right - left + 1 == len)
        {
            ret.push_back(left);
        }
    }

    return ret;
 }
};

实际上,题目中明确说只有小写字母,所以说可以把哈希数组搞成26个的:


class Solution
{
public:
    bool check(int* p, int* s)
    {
        for (int i = 0; i < 26; i++)
        {
            if (p[i] != s[i])
            {
                return false;
            }
        }

        return true;
    }

    vector<int> findAnagrams(string s, string p)
    {
        //统计一下p字符串的字符信息
        size_t len = p.size();
        int hash_p[26] = { 0 };
        for (int i = 0; i < len; i++)
        {
            hash_p[p[i] - 'a']++;
        }

        int n = s.size();
        int hash_s[26] = { 0 };
        vector<int> ret;
        //滑动窗口
        for (int right = 0, left = 0; right < n; right++)//"cbaebabacd"
        {
            //进窗口
            hash_s[s[right] - 'a']++;

            //判断,出窗口
            if (right - left + 1 > len)
            {
                hash_s[s[left] - 'a']--;
                left++;
            }

            //更新结果
            if (check(hash_p, hash_s) && right - left + 1 == len)
            {
                ret.push_back(left);
            }
        }

        return ret;
    }
};

3.异位词优化

虽然这样可以解题,不过问题是如果是比较的是比较多的字符呢?不仅仅是26的小写字母。我想如果这样比较,复杂度瞬间就会上来了。

所以,在比较异位词时,我们需要再优化一下:
思路大致是下面这样的,如下:
在这里插入图片描述
所以,可以优化为下面代码:


class Solution
{
public:
    vector<int> findAnagrams(string s, string p)
    {
        //统计一下p字符串的字符信息
        size_t len = p.size();
        int hash_p[26] = { 0 };
        for (int i = 0; i < len; i++)
        {
            hash_p[p[i] - 'a']++;
        }

        int n = s.size();
        int count = 0;//count标识有效字符的个数,即p字符串的长度
        int hash_s[26] = { 0 };
        vector<int> ret;
        //滑动窗口
        for (int right = 0, left = 0; right < n; right++)//"cbaebabacd"
        {
            //进窗口
            hash_s[s[right] - 'a']++;
            if(hash_s[s[right]-'a'] <= hash_p[s[right]-'a'])count++;//进窗口,维护有效字符个数

            //判断,出窗口
            if (right - left + 1 > len)
            {
                if(hash_s[s[left] - 'a'] <= hash_p[s[left] - 'a'])count--;//出窗口,维护有效字符个数
                hash_s[s[left] - 'a']--;
                left++;
            }

            //更新结果
            if (count == len)
            {
                ret.push_back(left);
            }
        }

        return ret;
    }
};

4.总结

其实总结一下来看,这个题目除了异位词问题之外也没什么东西,这个题目是一个典型的“固定长度的滑动窗口”,要解出来难度不大。


EOF

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值