Skip to content

Commit 80d92b9

Browse files
authored
refactor: js - slidewindow (neetcode-gh#454)
1 parent 5920e71 commit 80d92b9

5 files changed

+227
-79
lines changed
Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
/**
2-
* @param {number[]} prices
2+
* https://leetcode.com/problems/best-time-to-buy-and-sell-stock/
3+
* Time O(N) | Space O(1)
4+
* @param {number} prices
35
* @return {number}
46
*/
5-
var maxProfit = function (prices) {
6-
let buy = prices[0];
7-
let profit = 0;
8-
for (let i = 0; i < prices.length; i++) {
9-
if (prices[i] < buy) {
10-
buy = prices[i];
11-
} else {
12-
profit = Math.max(prices[i] - buy, profit);
13-
}
7+
var maxProfit = function(prices) {
8+
let [ left, right, max ] = [ 0, 1, 0];
9+
10+
while (right < prices.length) {
11+
const canSlide = prices[right] <= prices[left];
12+
if (canSlide) left = right;
13+
14+
const window = prices[right] - prices[left];
15+
16+
max = Math.max(max, window);
17+
right++;
1418
}
15-
return profit;
16-
};
19+
20+
return max;
21+
}
Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
1-
var lengthOfLongestSubstring = function (str) {
2-
const hash = {};
3-
let start = 0;
4-
let max = 0;
1+
/**
2+
* https://leetcode.com/problems/longest-substring-without-repeating-characters/
3+
* Time O(N) | Space O(N)
4+
* @param {string} s
5+
* @return {number}
6+
*/
7+
var lengthOfLongestSubstring = function(s, map = new Map()) {
8+
let [ left, right, max ] = [ 0, 0, 0];
59

6-
for (let i = 0; i < str.length; i++) {
7-
let rightChar = str[i];
10+
while (right < s.length) {
11+
const rightChar = s[right];
812

9-
if (!(rightChar in hash)) hash[rightChar] = 0;
10-
hash[rightChar] += 1;
13+
const canSlide = map.has(rightChar);
14+
if (canSlide) {
15+
const rightIndex = map.get(rightChar) + 1;
1116

12-
while (hash[rightChar] > 1) {
13-
let leftChar = str[start];
14-
start += 1;
15-
16-
if (leftChar in hash) hash[leftChar] -= 1;
17-
if (hash[leftChar] === 0) delete hash[leftChar];
17+
left = Math.max(left, rightIndex);
1818
}
19-
max = Math.max(max, i - start + 1);
19+
20+
const window = (right - left) + 1;
21+
22+
max = Math.max(max, window);
23+
map.set(rightChar, right);
24+
right++;
2025
}
26+
2127
return max;
2228
};
Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,52 @@
11
/**
2+
* https://leetcode.com/problems/longest-repeating-character-replacement/
3+
* Time O(((N + 26) * N) * (M - N)) | Space O(1)
24
* @param {string} s
35
* @param {number} k
46
* @return {number}
57
*/
6-
var characterReplacement = function (s, k) {
7-
let sCharacterSet = {};
8-
let result = 0;
9-
let l = 0;
10-
let maxLength = 0;
11-
12-
for (let r = 0; r < s.length; r++) {
13-
if (sCharacterSet[s[r]] !== undefined) {
14-
sCharacterSet[s[r]] = 1 + sCharacterSet[s[r]];
15-
} else {
16-
sCharacterSet[s[r]] = 1;
17-
}
8+
var characterReplacement = function(s, k) {
9+
let [ left, right, longest, max ] = new Array(4).fill(0);
10+
const frequencyMap = new Array(26).fill(0);
1811

19-
maxLength = Math.max(maxLength, sCharacterSet[s[r]]);
12+
while (right < s.length) {
13+
const count = addRightFrequency(s, right, frequencyMap);
14+
15+
longest = Math.max(longest, count);
2016

21-
if (r - l + 1 - maxLength > k) {
22-
sCharacterSet[s[l]] -= 1;
23-
l += 1;
17+
let window = (right - left) + 1;
18+
const canSlide = k < (window - longest);
19+
if (canSlide) {
20+
subtractLeftFrequency(s, left, frequencyMap);
21+
left++;
2422
}
2523

26-
result = Math.max(result, r - l + 1);
24+
window = (right - left) + 1;
25+
max = Math.max(max, window);
26+
27+
right++;
2728
}
28-
29-
return result;
29+
30+
return max;
3031
};
32+
33+
const addRightFrequency = (s, right, map) => {
34+
const char = s[right];
35+
const index = getCode(char);
36+
37+
map[index]++;
38+
39+
return map[index];
40+
}
41+
42+
const subtractLeftFrequency = (s, left, map) => {
43+
const char = s[left];
44+
const index = getCode(char);
45+
46+
map[index]--;
47+
48+
return map[index];
49+
}
50+
51+
const getCode = (char) => char.charCodeAt(0) - 'A'.charCodeAt(0);
52+

javascript/567-Permutation-In-String.js

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,76 @@
1+
/**
2+
* https://leetcode.com/problems/permutation-in-string/
3+
* Time O(N + (M - N)) | Space O(1)
4+
* @param {string} s1
5+
* @param {string} s2
6+
* @return {boolean}
7+
*/
8+
var checkInclusion = (s1, s2) => {
9+
const isInvalid = s2.length < s1.length
10+
if (isInvalid) return false;
11+
12+
let [ left, right ] = [ 0, 0 ];
13+
const [ s1FrequencyMap, s2FrequencyMap ] = getFrequencyMaps(s1);
14+
15+
while (right < s2.length) {
16+
addRightFrequency(s2, right, s2FrequencyMap);
17+
18+
const window = (right - left) + 1;
19+
const isPermutation = (window === s1.length) && isSame(s1FrequencyMap, s2FrequencyMap);
20+
if (isPermutation) return true;
21+
22+
const canSlide = s1.length <= window;
23+
if (canSlide) {
24+
subtractLeftFrequency(s2, left, s2FrequencyMap);
25+
left++;
26+
}
27+
28+
right++;
29+
}
30+
31+
return false;
32+
}
33+
34+
const getFrequencyMaps = (s1) => {
35+
const [ s1FrequencyMap, s2FrequencyMap ] = new Array(2)
36+
.fill().map(() => new Array(26).fill(0))
37+
38+
for (const char of s1) s1FrequencyMap[getCode(char)]++;
39+
40+
return [ s1FrequencyMap, s2FrequencyMap ]
41+
}
42+
43+
44+
const getCode = (char) => char.charCodeAt(0) - 'a'.charCodeAt(0);
45+
46+
const addRightFrequency = (s, right, frequencyMap) => {
47+
const char = s[right];
48+
const index = getCode(char);
49+
50+
frequencyMap[index]++;
51+
52+
return frequencyMap[index];
53+
}
54+
55+
const subtractLeftFrequency = (s, left, frequencyMap) => {
56+
const char = s[left];
57+
const index = getCode(char);
58+
59+
frequencyMap[index]--;
60+
61+
return frequencyMap[index];
62+
}
63+
64+
const isSame = (a, b) => {
65+
for (let i = 0; i < 26; i++) {
66+
const isMatch = a[i] === b[i];
67+
if (!isMatch) return false
68+
}
69+
70+
return true;
71+
}
72+
73+
174
//////////////////////////////////////////////////////////////////////////////
275
// Static Sliding Window
376
// Time: Theta(l1 + l2) O(l1 + l2) Space: Theta(1) O(1)
@@ -13,7 +86,7 @@
1386
* @param {string} s2
1487
* @return {boolean}
1588
*/
16-
function checkInclusion(s1, s2) {
89+
function checkInclusion(s1, s2) {
1790
if (s1.length > s2.length) {
1891
return false;
1992
}
@@ -150,4 +223,4 @@ function checkInclusion(s1, s2) {
150223
}
151224

152225
return false;
153-
}
226+
}
Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,79 @@
1-
var minWindow = function (str, target) {
2-
const hash = target.split('').reduce((acc, val) => {
3-
if (!acc[val]) acc[val] = 0;
4-
acc[val] += 1;
5-
return acc;
6-
}, {});
7-
8-
let start = 0;
9-
let min = Infinity;
10-
let matched = 0;
11-
let subStringStart = null;
12-
13-
for (let i = 0; i < str.length; i++) {
14-
let rightChar = str[i];
15-
16-
if (rightChar in hash) hash[rightChar] -= 1;
17-
if (hash[rightChar] >= 0) matched += 1;
18-
19-
while (matched === target.length) {
20-
if (i - start + 1 < min) {
21-
subStringStart = start;
22-
min = i - start + 1;
23-
}
1+
/**
2+
* https://leetcode.com/problems/minimum-window-substring/
3+
* Time O(N + M) | SpaceO(N + M)
4+
* @param {string} s
5+
* @param {string} t
6+
* @return {string}
7+
*/
8+
var minWindow = function (s, t) {
9+
const isMissingArgs = !s.length || !t.length
10+
if (isMissingArgs) return '';
11+
12+
const frequencyMap = getFrequencyMap(t);
13+
const { start, end } = getWindowPointers(s, t, frequencyMap);
14+
15+
return getSubString(s, start, end);
16+
}
17+
18+
const getFrequencyMap = (str, frequencyMap = new Map()) => {
19+
for (const char of str) {
20+
frequencyMap.set(char, (frequencyMap.get(char) || 0) + 1);
21+
}
22+
23+
return frequencyMap;
24+
};
25+
26+
const getWindowPointers = (s, t, frequencyMap) => {
27+
let [ left, right, matched, start, end ] = [ 0, 0, 0, 0, (s.length + 1) ];
28+
29+
while (right < s.length) {
30+
matched = addRightFrequency(s, right, frequencyMap, matched);
2431

25-
let leftChar = str[start];
26-
start += 1;
32+
const canSlide = () => matched === t.length;
33+
while (canSlide()) {
34+
const window = (right - left) + 1;
2735

28-
if (leftChar in hash) {
29-
if (hash[leftChar] === 0) matched -= 1;
30-
hash[leftChar] += 1;
36+
const isSmaller = window < end;
37+
if (isSmaller) {
38+
[ start, end ] = [ left, window ];
3139
}
40+
41+
matched = subtractLeftFrequency(s, left, frequencyMap, matched);
42+
left++;
3243
}
44+
45+
right++;
46+
}
47+
48+
return { start, end };
49+
};
50+
51+
const addRightFrequency = (s, right, frequencyMap, matched) => {
52+
const char = s[right];
53+
54+
if (frequencyMap.has(char)) {
55+
frequencyMap.set(char, frequencyMap.get(char) - 1);
56+
57+
const isInWindow = 0 <= frequencyMap.get(char);
58+
if (isInWindow) matched++;
59+
}
60+
61+
return matched;
62+
};
63+
64+
const subtractLeftFrequency = (s, left, frequencyMap, matched) => {
65+
const char = s[left];
66+
67+
if (frequencyMap.has(char)) {
68+
const isOutOfWindow = frequencyMap.get(char) === 0;
69+
if (isOutOfWindow) matched--;
70+
71+
frequencyMap.set(char, frequencyMap.get(char) + 1);
3372
}
34-
return min === Infinity
35-
? ''
36-
: str.substring(subStringStart, subStringStart + min);
73+
74+
return matched;
3775
};
76+
77+
const getSubString = (s, start, end) => end <= s.length
78+
? s.slice(start, start + end)
79+
: '';

0 commit comments

Comments
 (0)