给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

    异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

    示例 1:

    输入: s = “cbaebabacd”, p = “abc”
    输出: [0,6]
    解释:
    起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。
    起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。
    示例 2:

    输入: s = “abab”, p = “ab”
    输出: [0,1,2]
    解释:
    起始索引等于 0 的子串是 “ab”, 它是 “ab” 的异位词。
    起始索引等于 1 的子串是 “ba”, 它是 “ab” 的异位词。
    起始索引等于 2 的子串是 “ab”, 它是 “ab” 的异位词。

    1. /**
    2. * @param {string} s
    3. * @param {string} p
    4. * @return {number[]}
    5. */
    6. var findAnagrams = function (s, p) {
    7. //需要的字符
    8. let need = {}, win = {};
    9. //统计异位词的数量
    10. for (let a of p) {
    11. need[a] = (need[a] || 0) + 1;
    12. }
    13. //左右指针
    14. let l = 0, r = 0;
    15. //窗口中和need中字符数量一致的字符种类
    16. let val = 0;
    17. let res = [];
    18. while (r < s.length) {
    19. let c = s[r];
    20. // 右边的字符进入窗口
    21. r += 1;
    22. if (need[c]) {
    23. // 当前字符在need中,更新窗口中的字符数量
    24. win[c] = (win[c] || 0) + 1;
    25. if (win[c] == need[c]) {
    26. // 该字符在窗口中和need中的字符匹配时,字符种类+1
    27. val += 1;
    28. }
    29. }
    30. // 不断出窗口
    31. while (r - l >= p.length) {
    32. // 如果此时窗口中的子串和p是异位词则将左边界加入res中
    33. if (val == Object.keys(need).length) {
    34. res.push(l);
    35. }
    36. let d = s[l];
    37. // 出窗口
    38. l += 1;
    39. // 如果该字符在need中 更新窗口中的字符数量 和字符种类
    40. if (need[d]) {
    41. if (win[d] == need[d]) {
    42. val -= 1;
    43. }
    44. win[d] -= 1;
    45. }
    46. }
    47. }
    48. return res;
    49. };

    image.png