diff --git a/top-interview-leetcode150/sliding-Window/209长度最小的子数组.js b/top-interview-leetcode150/sliding-Window/209长度最小的子数组.js new file mode 100644 index 0000000..31d34b3 --- /dev/null +++ b/top-interview-leetcode150/sliding-Window/209长度最小的子数组.js @@ -0,0 +1,61 @@ +/** + * https://leetcode.cn/problems/minimum-size-subarray-sum/?envType=study-plan-v2&envId=top-interview-150 + * @param {number} target + * @param {number[]} nums + * @return {number} + */ +const minSubArrayLen = function (target, nums) { + +}; + +/* +题目要求我们找到最短的子数组,子数组就是原数组中连续的某部分,我们先遍历原数组,之后在遍历到的位置开始往下遍历,并且求和 +如果结果大于等于target就返回这个长度 +*/ +function f1(target, nums) { + let minLen = Infinity; // 初始化最小长度 + for (let left = 0; left < nums.length; left++) { + let sum = 0; // 保存当前子数组的和 + for (let right = left; right < nums.length; right++) { + sum += nums[right]; + if (sum >= target) { + minLen = Math.min(minLen, right - left + 1); + // 后面匹配的结果都会符合sum>=target但是一定比当前子数组长,所以直接break + break; + } + } + } + return minLen === Infinity ? 0 : minLen; // 注意清理初始化的值,如果没有符合要求的,返回0,而不是Infinity +} + +function f2(target, nums) { + let minLen = Infinity; // 初始化最小长度 + let left = 0; // 滑动窗口的左边界 + let sum = 0; // 滑动窗口中所有值的和 + for (let right = 0; right < nums.length; right++) { + sum += nums[right]; + while (sum >= target) { + minLen = Math.min(minLen, right - left + 1); + // 如果靠近right的数值很大,靠近left的数值很小,会造成数组长度很长所以要从左缩小窗口 + sum -= nums[left]; + left++; + } + } + return minLen === Infinity ? 0 : minLen; // 注意清理初始化的值,如果没有符合要求的,返回0,而不是Infinity +} + +function f3(target, nums) { + let minLen = Infinity; // 初始化最小长度 + let left = 0; // 滑动窗口的左边界 + let sum = 0; // 滑动窗口中所有值的和 + for (let right = 0; right < nums.length; right++) { + sum += nums[right]; + while (sum >= target) { + minLen = Math.min(minLen, right - left + 1); + // 如果靠近right的数值很大,靠近left的数值很小,会造成数组长度很长所以要从左缩小窗口 + sum -= nums[left]; + left++; + } + } + return minLen === Infinity ? 0 : minLen; // 注意清理初始化的值,如果没有符合要求的,返回0,而不是Infinity +} diff --git a/top-interview-leetcode150/sliding-Window/438找到字符串中所有字母异位词.js b/top-interview-leetcode150/sliding-Window/438找到字符串中所有字母异位词.js new file mode 100644 index 0000000..10bcc99 --- /dev/null +++ b/top-interview-leetcode150/sliding-Window/438找到字符串中所有字母异位词.js @@ -0,0 +1,112 @@ +/** + * https://leetcode.cn/problems/find-all-anagrams-in-a-string/ + * @param {string} s + * @param {string} p + * @return {number[]} + */ +const findAnagrams = function (s, p) { + +}; + +/* +按照暴力解法的话我们可能会把p的所有异位词都枚举出来,之后遍历遍历所有的异位词,利用indexof查看每一个异位词在s中的位置,如果 +这个异位词在s中存在,那么就把起始下标放入到结果集中,如果p非常长的话那么所有异位词就是一个长度的全排列!m,加上对s的查找,那就是一个 +(n+m)*!m, 这显然是不能接受的,所以我们需要换一种思路. +思路:异位词和原词在单词数量上是一致的,所以我们可以维护一个在s上,长度位p.length的窗口,只要这个窗口里面所有单词出现的数量和 +p中所有单词出现的数量一致的话,那么就认为这个窗口表示的单词是p的一个异位词,最后只需把窗口的起始下标放入结果集合即可 +*/ +function f1(s, p) { + const result = []; // 返回的结果集 + if (s.length < p.length) return result; // p比s还长,在s中不可能有p的异位词,直接返回 + const need = new Map(); // 记录p中每一个词出现的次数,用于验证异位词 + const window = new Map(); // 记录当前窗口中的异位词 + // 统计p的所有字符出现的次数 + for (const char of p) { + need.set(char, (need.get(char) || 0) + 1); + } + + let left = 0; // 滑动窗口的左边界 + let right = 0; // 滑动窗口的右边界 + let valid = 0; // 滑动窗口中符合异位字的字符数量; + + while (right < s.length) { + const char = s[right]; + if (need.has(char)) { + window.set(char, (window.get(char) || 0) + 1); + if (window.get(char) === need.get(char)) { + valid++; + } + } + + // 如果窗口长度等于异位字符p的长度,那么就检测当前窗口是否是一个异位词 + if (right - left + 1 === p.length) { + if (valid === need.size) { + result.push(left); // 把left添加到结果集中 + } + const leftChar = s[left]; + // 收缩窗口 + left++; + // 判断收缩掉的这个字符是否是need中的某一个字符 + if (need.has(leftChar)) { + if (window.get(leftChar) === need.get(leftChar)) { + valid--; // 验证符合异位词字符个数的词减1 + } + window.set(leftChar, window.get(leftChar) - 1); // 使这个字符的数量减1 + } + } + // 扩展窗口 + right++; + } + return result; +} + +function f3(s, p) { + const result = []; // 返回的结果集 + if (s.length < p.length) return result; // p比s还长,在s中不可能有p的异位词,直接返回 + + const need = new Map(); // 记录p中每一个字符出现的次数,用于验证异位词 + const window = new Map(); // 记录当前窗口中的异位词 + + // 统计p的所有字符出现的次数 + for (const char of p) { + need.set(char, (need.get(char) || 0) + 1); + } + + let left = 0; // 滑动窗口的左边界 + let right = 0; // 滑动窗口的右边界 + + while (right < s.length) { + const char = s[right]; + // 扩展窗口 + window.set(char, (window.get(char) || 0) + 1); + + // 如果当前窗口大小达到p的长度,判断是否为异位词 + if (right - left + 1 === p.length) { + // 比较窗口内字符的频次是否和p中一致 + let isAnagram = true; + for (const [key, value] of need) { + if (window.get(key) !== value) { + isAnagram = false; + break; + } + } + + if (isAnagram) { + result.push(left); // 将符合条件的起始索引加入结果 + } + + // 收缩窗口 + const leftChar = s[left]; + window.set(leftChar, window.get(leftChar) - 1); // 减少左边字符的频次 + if (window.get(leftChar) === 0) { + window.delete(leftChar); // 如果频次为0,移除该字符 + } + left++; // 移动左指针 + } + + // 扩展右指针 + right++; + } + + return result; +}