layout: posttitle: PHP 滑动窗口算法实现找出所有字母异位词
subtitle: PHP 滑动窗口算法实现找出所有字母异位词
date: 2020-06-02
author: he xiaodong
header-img: img/default-post-bg.jpg
catalog: true
tags:
- Go
- PHP
- LeetCode
- 字母异位词
- 滑动窗口算法

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

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。
示例 1:

  1. 输入:
  2. s: "cbaebabacd" p: "abc"
  3. 输出:
  4. [0, 6]
  5. 解释:
  6. 起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
  7. 起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。

示例 2:

  1. 输入:
  2. s: "abab" p: "ab"
  3. 输出:
  4. [0, 1, 2]
  5. 解释:
  6. 起始索引等于 0 的子串是 "ab", 它是 "ab" 的字母异位词。
  7. 起始索引等于 1 的子串是 "ba", 它是 "ab" 的字母异位词。
  8. 起始索引等于 2 的子串是 "ab", 它是 "ab" 的字母异位词。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string

解题思路

1、我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引左闭右开区间 [left, right) 称为一个「窗口」。

2、我们先不断地增加 right 指针扩大窗口 [left, right),直到窗口中的字符串符合要求(包含了 T 中的所有字符)。

3、此时,我们停止增加 right,记录一下 left 的值,然后转而不断增加 left 指针缩小窗口 [left, right),直到窗口中的字符串不再符合要求(不包含 T 中的所有字符了)。

4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。

PHP 实现
  1. function findAnagrams($s, $p) {
  2. $need = [];
  3. $window = [];
  4. $length = strlen($p);
  5. // 测试用例里有一些奇葩的,这里加个判断
  6. if ($length > strlen($s)) {
  7. return [];
  8. }
  9. // 将寻找的字符串装入 $need 数组
  10. for ($c = 0; $c < $length; $c++) {
  11. $need[$p[$c]] = isset($need[$p[$c]]) ? $need[$p[$c]] + 1 : 1;
  12. }
  13. $left = 0;
  14. $right = 0;
  15. $valid = 0;
  16. $arr = [];
  17. while ($right < strlen($s)) {
  18. // $c 是将移入窗口的字符
  19. $c = $s[$right];
  20. // 右移窗口
  21. $right++;
  22. // 进行窗口内数据的一系列更新
  23. if (isset($need[$c])) {
  24. $window[$c] = isset($window[$c]) ? $window[$c] + 1 : 1;
  25. if ($window[$c] === $need[$c]) {
  26. $valid++;
  27. }
  28. }
  29. // 判断左侧窗口是否要收缩
  30. while ($right - $left >= $length) {
  31. // 当窗口符合条件时,把起始索引加入 res
  32. if ($valid == count($need)) {
  33. $arr[] = $left;
  34. }
  35. // d 是将移出窗口的字符
  36. $d = $s[$left];
  37. // 左移窗口
  38. $left++;
  39. // 进行窗口内数据的一系列更新
  40. if (isset($need[$d])) {
  41. if ($window[$d] === $need[$d]) {
  42. $valid--;
  43. }
  44. $window[$d]--;
  45. }
  46. }
  47. }
  48. // 返回结果集
  49. return $arr;
  50. }
  51. return findAnagrams($s = "cbaebabacd", $p = "abc"); // output: [0, 6]

参考链接:

  1. 滑动窗口解题框架思路,强烈推荐这个网站的作者

最后恰饭 阿里云全系列产品/短信包特惠购买 中小企业上云最佳选择 阿里云内部优惠券