字符串、序列相关总感觉很麻烦,在考虑边界,递归的过程中,总是碍手碍脚的,感觉。
模版:双 while 循环

  1. function test(s) {
  2. let n = s.length;
  3. let left = 0;
  4. let right = 0;
  5. while (right < n) {
  6. while(check()) { // 满足某个条件
  7. left++;
  8. }
  9. right++; // 不满足某个条件
  10. }
  11. };

3. 无重复字符的最长子串

  1. var lengthOfLongestSubstring = function(s) {
  2. let n = s.length;
  3. let map = new Map();
  4. let left = 0;
  5. let right = 0;
  6. let max = 0;
  7. while (right < n) {
  8. map.set(s[right], (map.get(s[right]) || 0) + 1);
  9. while(check(map)) { // 有重复
  10. let leftValue = s[left];
  11. map.set(leftValue, map.get(leftValue) - 1);
  12. left++;
  13. }
  14. // 无重复,计算最大长度的地方
  15. if (max < (right - left + 1)) {
  16. max = right - left + 1;
  17. }
  18. right++;
  19. }
  20. return max;
  21. };
  22. function check(map) {
  23. for (let [key, value] of map) {
  24. if (value > 1) {
  25. return true;
  26. }
  27. }
  28. return false;
  29. }

76. 最小覆盖子串

精彩的题解(动画特别好):
https://leetcode-cn.com/problems/minimum-window-substring/solution/shu-ju-jie-gou-he-suan-fa-hua-dong-chuan-p6ip/

  1. var minWindow = function(s, t) {
  2. let n_s = s.length;
  3. let n_t = t.length;
  4. if (n_s < n_t) {
  5. return '';
  6. }
  7. let map_t = new Map(); // 连 map 都类似窗口
  8. for (let char of t) {
  9. map_t.set(char, (map_t.get(char) || 0) + 1);
  10. }
  11. let left = 0;
  12. let right = 0;
  13. let min = Infinity;
  14. let range = [left, right]
  15. while (right < n_s) { // 三个 while 循环,也真是 威武大气
  16. let curRight = s[right];
  17. if (map_t.has(curRight)) {
  18. map_t.set(curRight, map_t.get(curRight) - 1);
  19. }
  20. while (check(map_t)) { // 包含的话,一直减左边界
  21. let curLeft = s[left];
  22. if (map_t.has(curLeft)) { // 有才有的说
  23. map_t.set(curLeft, map_t.get(curLeft) + 1);
  24. }
  25. if (min > (right - left + 1)) { // 取到最小的表现
  26. min = right - left + 1;
  27. range = [left, right];
  28. }
  29. left++;
  30. }
  31. right++;
  32. }
  33. if (min === Infinity) { //没有找到合适的窗口: Infinity 可以比较,也真是学习到了
  34. return '';
  35. }
  36. return s.slice(range[0], range[1] + 1);
  37. function check(store) {
  38. for (let [key, value] of store) {
  39. if (value > 0) {
  40. return false;
  41. }
  42. }
  43. return true;
  44. }
  45. };


209. 长度最小的子数组

和 76 题,基本上相同,代码结构都一样

  1. var minSubArrayLen = function(target, nums) {
  2. let n = nums.length;
  3. let left = 0;
  4. let right = 0;
  5. let minLength = Infinity;
  6. while (right < n) {
  7. let curRight = nums[right];
  8. target = target - curRight;
  9. while (target <= 0) {
  10. if (minLength > (right - left + 1)) {
  11. minLength = right - left + 1;
  12. }
  13. let curLeft = nums[left];
  14. target = target + curLeft;
  15. left++;
  16. }
  17. right++;
  18. }
  19. if (minLength === Infinity) {
  20. return 0;
  21. }
  22. return minLength;
  23. };

567. 字符串的排列

76 209 567 题目一样,代码结构都相同。

  1. var checkInclusion = function(s1, s2) {
  2. let map_s1 = new Map();
  3. for (let char of s1) {
  4. map_s1.set(char, (map_s1.get(char) || 0) + 1);
  5. }
  6. let map = new Map();
  7. let left = 0;
  8. let right = 0;
  9. while (right < s2.length) {
  10. let curRight = s2[right];
  11. if (map_s1.has(curRight)) {
  12. map.set(curRight, (map.get(curRight) || 0) + 1);
  13. }
  14. while (check(map, map_s1)) {
  15. let curLeft = s2[left];
  16. if (right - left + 1 === s1.length) {
  17. return true;
  18. }
  19. if (map.has(curLeft)) {
  20. map.set(curLeft, map.get(curLeft) - 1);
  21. }
  22. left++;
  23. }
  24. right++;
  25. }
  26. function check (current, target) {
  27. for (let [key, value] of target) {
  28. if ((current.get(key) || 0) < value) {
  29. return false;
  30. }
  31. }
  32. return true;
  33. }
  34. return false;
  35. };

219. 存在重复元素 II

固定窗口宽度,窗口内元素使用 set 存

  1. var containsNearbyDuplicate = function(nums, k) { // 滑动窗口
  2. let n = nums.length;
  3. let set = new Set();
  4. for (let i = 0; i < n; i++) {
  5. let cur = nums[i];
  6. if (set.has(cur)) {
  7. return true;
  8. }
  9. set.add(nums[i]); // 现添加元素,然后再判断 set 是否超出容量
  10. if (set.size > k) {
  11. set.delete(nums[i - k]);
  12. }
  13. }
  14. return false;
  15. };