feat: 添加滑动窗口相关算法209,438
This commit is contained in:
parent
09c5a746f1
commit
614b10bcd0
61
top-interview-leetcode150/sliding-Window/209长度最小的子数组.js
Normal file
61
top-interview-leetcode150/sliding-Window/209长度最小的子数组.js
Normal file
@ -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
|
||||
}
|
112
top-interview-leetcode150/sliding-Window/438找到字符串中所有字母异位词.js
Normal file
112
top-interview-leetcode150/sliding-Window/438找到字符串中所有字母异位词.js
Normal file
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user