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

零、本文只是自己做题时候的想法,仅供参考

一、滑动窗口,把长字符串上嵌入一个窗口,并滑动,好处有二:

1.窗口内的数据较少便于维护

2.滑动过程通常只需要遍历一遍主串

二、滑动窗口的“三步走”:

1.进窗口

2.判断出窗口条件

3.更新窗口

三、题目及代码详解:

补充:如果不习惯这里“先预测再执行”的更新窗口逻辑,其实也可以“先执行再更新”,不过那样就不是维护滑动窗口而是维护滑动窗户框了吧。

#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        // 滑动窗口
        vector<int> ans;
        int s_len = s.length();
        int p_len = p.length();
        int count[26];
        if (p_len > s_len) {
            return ans;
        }
        // 更新count,记录初始窗口主串和模式串的差异
        for (int i = 0; i < p_len; i++) {
            ++count[s[i] - 'a'];
            --count[p[i] - 'a'];
        }
        // 用differ记录不同字符的数量
        int differ = 0;
        for (int i = 0; i < 26; i++) {
            if (count[i] != 0) {
                ++differ;
            }
        }
        // 初始位置判断
        if (differ == 0) {
            ans.push_back(0);
        }
        // 滑动窗口
        for (int i = 0; i < s_len - p_len; ++i) {
            // 1.重点是滑动时的变化,只要关注变化前后s和p是否相同字符数变多(变少)就可以了,
            // 也就是说,只要看是不是+-1->0(异变同),或者0->+-1(同变异),除此之外的情况都会在窗口滑动的过程中自动维护,
            // 花开两朵,各表一枝:如果便会-+1或0,按照第一条处理;其他情况,因为维护的是count数组(窗口)和differ,一定是s和p不同;
            // count数组目前记录的是未滑动之前初始状态时s和p的differ,
            // 2.每次滑动更新一个窗口右侧字符和窗口左侧字符,左出(减)右进(加),
            // 出窗口判断(维护窗口左端)
            if (count[s[i] - 'a'] == 1) {
            // 初始窗口是我们前面自行构建的,这里的判断条件要和4.出窗口相结合去看,
            // 这个语句的count索引“[s[i] - 'a']”和维护窗口的索引一致,也就是先预测执行结果,然后执行,
            // (这两个if/else if判断其实是一回事,只不过一个在左一个在右罢了)
            // 事实上,++differ的时刻,count数组还没有变化。
            // 总而言之重点还是“变化”;。
                --differ;
            }
            else if (count[s[i] - 'a'] == 0) {// 一个“相同”因为维护移动窗口二减少了
                ++differ;
            }
            // 4.出窗口(维护窗口左端)
            --count[s[i] - 'a'];
            // 进窗口判断
            if (count[s[i + p_len] - 'a'] == -1) {
            // 举个例子,假设这是我们程序运行的某一时刻,我们的程序停止了(其实就是调试)
            // 这个“(count[s[i + p_len] - 'a'] == -1)”, 等于-1一定会被下面的5.进窗口(维护窗口右端)+1,变成0的,也就是异到同
                --differ;
            }
            else if (count[s[i + p_len] - 'a'] == 0) {// 同理由同到异
                ++differ;
            }
            // 5.进窗口(维护窗口右端)
            ++count[s[i + p_len] - 'a'];
            // differ等于0意味着这一时刻s和p的差异为0(异位词),记录索引
            // 至于+1,这时候虽然完成了维护,但是++i的步长还没有执行,所以+1才能正确定位
            if (differ == 0) ans.push_back(i + 1);
        }
    return ans;// 最后不要忘记返回结果
    }
};

int main() {

    return 0;
}

四、结尾:

本质上滑动窗口和双指针是普遍性和特殊性的关系,故而应当考虑双指针的一些条件:比如双指针的本质:优化和双指针的使用前提:单调性。

最后,如有问题,欢迎讨论和指正。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值