From 7a7a4e760cdd7faebbe674728a05f889eaecb331 Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Wed, 29 Jun 2022 13:50:47 +0900 Subject: [PATCH 01/10] :white_check_mark: Finish 'what is sliding window' --- 15/yongki/SlidingWindow.md | 101 +++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 15/yongki/SlidingWindow.md diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md new file mode 100644 index 0000000..fcb616a --- /dev/null +++ b/15/yongki/SlidingWindow.md @@ -0,0 +1,101 @@ +# 슬라이딩 윈도우 + +## 이론 + +
+
+ +대표적으로 배열에서 연이은 k개의 최대합을 구하는 문제에 사용된다. + +Brute force의 O(kn)으로 해결하는 문제를 O(n)으로 줄일수 있다. + +**Brute force** + +```js +function maxSum(arr, k) { + let max = 0; + const N = arr.length; + + for (let i = 0; i <= N - k; i++) { + let sum = 0; + + for(let j = 0; j < k; j++) + sum = sum + arr[i + j]; + + max = Math.max(max, sum); + } + + return max; +} + +(function main() { + assert.equal( + maxSum( + arr = [1, 4, 2, 10, 2, 3, 1, 0, 20], + k = 4 + ), + 24 + ) +})(); +``` + +**슬라이딩 윈도우** + + arr = [1, 4, 2, 10, 2, 3, 1, 0, 20] + k = 4 + + k만큼의 요소를 arr에서 sum하면 14이다. + + [1, 4, 2, 10] + + k인덱스부터 루프를 돈다. + + [2, 3, 1, 0, 20] + + sum은 k만큼의 요소의 합을 유지한다. + + [4, 2, 10, 2]를 유지하기 위해 요소1을 제거 + + 매 루프마다 max와 sum의 max를 구한다. + +```js +function maxSum(arr, k) { + let max = 0; + let sum = 0; + + const N = arr.length; + + for (let i = 0; i < k; i++) { + sum += arr[i]; + max = sum; + } + + for (let i = k; i < N; i++) { + sum += arr[i] - arr[i - k]; + + max = Math.max(max, sum); + } + + return max; +} + +(function main() { + assert.equal( + maxSum( + arr = [1, 4, 2, 10, 2, 3, 1, 0, 20], + k = 4 + ), + 24 + ) +})(); +``` + +
+ +## 문제 리스트 + +
+ +## 참고 문헌 + +[Window Sliding Technique](https://www.geeksforgeeks.org/window-sliding-technique/) ━ *GeeksforGeeks* \ No newline at end of file From 24f378b8bda0cb44f5dbe6952c65f714b1a64ed3 Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Wed, 29 Jun 2022 18:53:17 +0900 Subject: [PATCH 02/10] :white_check_mark: Solve 219 --- 15/yongki/SlidingWindow.md | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index fcb616a..f671b54 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -94,6 +94,48 @@ function maxSum(arr, k) { ## 문제 리스트 +
+219. Contains Duplicate II + 👊 + + +### 문제 회고 + +이전 해결했던 이력이 있었다. + +다만 슬라이딩 윈도우를 푼것인지도 몰랐다. + +이론에서 다룬 형태외에도 Map을 사용한 형태도 해당됨을 알게되었다. + +### 문제 풀이 + +```js +/** + * @param {number[]} nums + * @param {number} k + * @return {boolean} + * + * time: O(n) + * space: O(k) + */ +var containsNearbyDuplicate = function (nums, k) { + const window = new Map(); + + for (const [idx, num] of nums.entries()) { + if ( + window.has(num) + && Math.abs(idx - window.get(num)) <= k + ) + return true; + + window.set(num, idx); + } + return false; +}; +``` + +
+
## 참고 문헌 From 7a88ccc089bac1e37a6ca9ceb27442084b306cc2 Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Thu, 30 Jun 2022 17:29:33 +0900 Subject: [PATCH 03/10] :white_check_mark: Solve 643 --- 15/yongki/SlidingWindow.md | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index f671b54..bc53076 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -136,6 +136,48 @@ var containsNearbyDuplicate = function (nums, k) { +
+643. Maximum Average Subarray I + 👊 + + +### 문제 회고 + +이론에서 다룬 형태와 같아 고민없이 풀 수 있었다. + +자바스크립트에서 `Math.avg`는 없는것도 알 수 있었다. + +### 문제 풀이 + +```js +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + * + * time: O(n) + * space: O(1) + */ +var findMaxAverage = function (nums, k) { + let max = 0; + let sum = 0; + + for (let i = 0; i < k; i++) { + sum += nums[i]; + max = sum / k; + } + + for (let i = k; i < nums.length; i++) { + sum += nums[i] - nums[i - k]; + max = Math.max(max, (sum / k)); + } + + return max; +}; +``` + +
+
## 참고 문헌 From 17f2a055c30f43d16a50d6e4ea4b026dd6b74dcd Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Fri, 1 Jul 2022 17:17:12 +0900 Subject: [PATCH 04/10] :white_check_mark: Solve 2269 --- 15/yongki/SlidingWindow.md | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index bc53076..265bf41 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -178,6 +178,52 @@ var findMaxAverage = function (nums, k) { +
+2269. Find the K-Beauty of a Number + 👊 + + +### 문제 풀이 + +```js +/** + * @param {number} num + * @param {number} k + * @return {number} + * + * time: O(n) + * space: O(n) + */ +var divisorSubstrings = function (num, k) { + const letterList = num.toString().split(''); + + let cur = ''; + let cnt = 0; + + for (let i = 0; i < k; i++) + cur += letterList[i]; + + if (isZeroDivisor(num, parseInt(cur))) + cnt += 1; + + for (let i = k; i < letterList.length; i++) { + cur = cur.substring(1); + cur += letterList[i]; + + if (isZeroDivisor(num, parseInt(cur))) + cnt += 1; + } + + return cnt; +}; + +var isZeroDivisor = function (num, target) { + return (num % target) === 0; +}; +``` + +
+
## 참고 문헌 From 545c882bdc441a9dfacedf4625ccacb76a661406 Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Mon, 4 Jul 2022 19:10:46 +0900 Subject: [PATCH 05/10] :test_tube: Fail testcase at 1763 --- 15/yongki/SlidingWindow.md | 77 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index 265bf41..8e7d47f 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -224,6 +224,83 @@ var isZeroDivisor = function (num, target) { +
+1763. Longest Nice Substring + 👊 + + +### 문제 회고 + +가변적인 결과값이 예상되어 `슬라이딩 윈도우`보단 `투 포인터` 알고리즘이 필요하다고 판단하였다. + +현재 동일한 알파벳의 niceSubstring은 완성하지만 + + Input: "dDzeE" + Output: "dD" + +여러 알파벳의 niceSubstring은 찾지 못했다. + + Input: "cChH" + Output: "cC" + Expected: "cChH" + +### 문제 풀이 + +```js +/** + * @param {string} s + * @return {string} + * + * time: O(n²) + * space: O(n) + */ +var longestNiceSubstring = function (s) { + var getLongestSubstring = function (...args) { + return args.reduce((a, b) => { + return (a.length === b.length) ? a + : (a.length > b.length) ? a + : b; + }); + } + + var getNiceSubstring = function (left, right) { + let cur = ''; + + while ( + left >= 0 + && right < N + && s[left].toLowerCase() === s[right].toLowerCase() + ) { + cur = s.substring(left, right + 1); + right += 1; + } + + return cur; + } + + /// +++ start + const N = s.length; + let result = ''; + + if (N < 2) + return result; + + for (let i = 0; i < N; i++) { + const niceSubstring = getNiceSubstring(i, i); + + if (niceSubstring.length === 1) + continue; + + result = getLongestSubstring(result, niceSubstring); + console.log(result); + } + + return result; +}; +``` + +
+
## 참고 문헌 From 5654e9efa058e4f2f2c150c22da63ad796814b71 Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Tue, 5 Jul 2022 17:15:05 +0900 Subject: [PATCH 06/10] :white_check_mark: Solve 1876 --- 15/yongki/SlidingWindow.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index 8e7d47f..e1fda41 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -299,6 +299,43 @@ var longestNiceSubstring = function (s) { }; ``` + + +
+1876. Substrings of Size Three with Distinct Characters + 👊 + + +### 문제 풀이 + +```js +/** + * @param {string} s + * @return {number} + * + * time: O(n) + * space: O(1) + */ +var countGoodSubstrings = function (s) { + var isGoodSubstrings = function (s) { + return s === [...new Set(s.split(''))].join(''); + } + + // +++ Start + const L = 3; + let result = 0; + + for (let i = 0; i < s.length; i++) { + const substring = s.substring(i, i + L); + + if (substring.length === L && isGoodSubstrings(substring)) + result += 1; + } + return result; +}; +``` + +

From e153fab48d983b700c17237d454411b874e7b470 Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Wed, 6 Jul 2022 17:30:03 +0900 Subject: [PATCH 07/10] :white_check_mark: Solve 1984 --- 15/yongki/SlidingWindow.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index e1fda41..699dfde 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -334,7 +334,41 @@ var countGoodSubstrings = function (s) { return result; }; ``` + + +
+1984. Minimum Difference Between Highest and Lowest of K Scores + 👊 + + +### 문제 풀이 + +```js +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + * + * time: O(n) + * space: O(1) + */ +var minimumDifference = function (nums, k) { + nums.sort((a, b) => a - b); + + const kIdx = k - 1; + let highScore = nums[kIdx]; + let lowScore = nums[0]; + let min = highScore - lowScore; + + for (let i = kIdx; i < nums.length; i++) { + const diffScore = nums[i] - nums[i - kIdx]; + min = Math.min(min, diffScore); + } + + return min; +}; +```
From 4cc978527ebdab3b10bf70828a8d74db2dcb382f Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Thu, 7 Jul 2022 16:22:24 +0900 Subject: [PATCH 08/10] =?UTF-8?q?:test=5Ftube:=20Fail=20testcase=20at=20?= =?UTF-8?q?=EB=B3=B4=EC=84=9D=20=EC=87=BC=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 15/yongki/SlidingWindow.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index 699dfde..7e18930 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -372,6 +372,42 @@ var minimumDifference = function (nums, k) { +
+보석 쇼핑 + 👊 + + +### 문제 회고 + +제시된 예제는 패스했지만, 제출시 테스트케이스는 해결하지 못했다. + +### 문제 풀이 + +```js +/* +* time: O(n) +* space: O(n) +*/ +function solution(gems) { + const gemTypeLength = new Set([...gems]).size; + const window = new Map(); + + for (const [idx, gem] of gems.entries()) { + window.set(gem, idx + 1); + + if (gemTypeLength === [...window.values()].length) + break; + } + + return [ + Math.min(...window.values()), + Math.max(...window.values()) + ]; +} +``` + +
+
## 참고 문헌 From 94bf6ee1442760706a63880c23ab564292b5ebc1 Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Thu, 7 Jul 2022 20:24:19 +0900 Subject: [PATCH 09/10] =?UTF-8?q?:white=5Fcheck=5Fmark:=20Solve=20?= =?UTF-8?q?=EB=B3=B4=EC=84=9D=20=EC=87=BC=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 15/yongki/SlidingWindow.md | 91 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index 7e18930..9368d66 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -379,9 +379,7 @@ var minimumDifference = function (nums, k) { ### 문제 회고 -제시된 예제는 패스했지만, 제출시 테스트케이스는 해결하지 못했다. - -### 문제 풀이 +처음 접근은 다음과 같다. ```js /* @@ -406,10 +404,95 @@ function solution(gems) { } ``` +해당 테스트케이스는 해결하지 못했다. + + ["A","B","B","B","B","B","B","C","B","A"] [8,10] + + Output: [1, 8] + Expected: [8, 10] + +### 문제 풀이 + +문제 풀이자는 범위를 모두 기억해둔 뒤, 적은 범위 순대로 정렬을 해두었다. + + // +++ map by for loop + Map(1) { 'A' => 0 } + Map(2) { 'A' => 0, 'B' => 1 } + Map(2) { 'A' => 0, 'B' => 2 } + Map(2) { 'A' => 0, 'B' => 3 } + Map(2) { 'A' => 0, 'B' => 4 } + Map(2) { 'A' => 0, 'B' => 5 } + Map(2) { 'A' => 0, 'B' => 6 } + Map(3) { 'A' => 0, 'B' => 6, 'C' => 7 } + Map(3) { 'A' => 0, 'C' => 7, 'B' => 8 } + Map(3) { 'C' => 7, 'B' => 8, 'A' => 9 } + + // +++ ranges + [ + { start: 1, end: 8 }, + { start: 1, end: 9 }, + { start: 8, end: 10 } + ] + + // +++ sort by compact ranges + [ + { start: 8, end: 10 } // +++ result! + { start: 1, end: 8 }, + { start: 1, end: 9 }, + ] + +인상적인 것은 map의 values의 순서를 오름차순으로 맞추도록 key를 갱신하는 작업이 있었다는 것이다. + +이는 범위를 추가할때, 어디가 start인지 end인지를 찾는 작업을 없애주었다. + +또한, 범위의 start를 찾을 때 다음과 같은 방법외에 + + start: [...gemMap.values()][0] + 1, + +이터레이터를 활용했다는 점이 인상깊었다. + + start: gemMap.values().next().value + 1, + +```js +/* +* time: O(n) +* space: O(n) +*/ +function solution(gems) { + const gemTypeLength = new Set(gems).size; + const gemMap = new Map(); + const gemRanges = []; + + for (const [idx, gem] of gems.entries()) { + gemMap.delete(gem); + gemMap.set(gem, idx); + + if (gemTypeLength === gemMap.size) + gemRanges.push({ + start: gemMap.values().next().value + 1, + end: idx + 1 + }); + } + + gemRanges.sort((a, b) => { + return (a.end - a.start) === (b.end - b.start) + ? a.end - b.end + : (a.end - a.start) - (b.end - b.start); + }) + + return [ + gemRanges[0].start, + gemRanges[0].end + ]; +} +``` +
## 참고 문헌 -[Window Sliding Technique](https://www.geeksforgeeks.org/window-sliding-technique/) ━ *GeeksforGeeks* \ No newline at end of file +[Window Sliding Technique](https://www.geeksforgeeks.org/window-sliding-technique/) ━ *GeeksforGeeks* + +[Simple Solution at 보석 쇼핑](https://school.programmers.co.kr/learn/courses/30/lessons/67258/solution_groups?language=javascript&type=all) ━ *Programmers* \ No newline at end of file From c9a5af007a54f9f41d30256b3751aec88855c27a Mon Sep 17 00:00:00 2001 From: Brave Kim Date: Sat, 16 Jul 2022 18:41:17 +0900 Subject: [PATCH 10/10] :white_check_mark: Solve 1763 --- 15/yongki/SlidingWindow.md | 67 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/15/yongki/SlidingWindow.md b/15/yongki/SlidingWindow.md index 9368d66..7413d12 100644 --- a/15/yongki/SlidingWindow.md +++ b/15/yongki/SlidingWindow.md @@ -244,8 +244,6 @@ var isZeroDivisor = function (num, target) { Output: "cC" Expected: "cChH" -### 문제 풀이 - ```js /** * @param {string} s @@ -299,6 +297,69 @@ var longestNiceSubstring = function (s) { }; ``` +### 문제 풀이 + +분할 정복 방법으로 해결하는 풀이었다. + +```js +/** + * @param {string} s + * @return {string} + * + * m as nice substring + * n as string + * + * time: O(n²) + * space: O(mn) + */ +var longestNiceSubstring = function (s) { + const N = s.length; + const set = new Set(); + let longestSize = 0; + + for (let i = 0; i < N; i++) { + for (let j = i; j < N; j++) { + const substring = s.slice(i, j + 1); + + if (isNiceSubstring(substring)) { + set.add(substring); + longestSize = Math.max(longestSize, substring.length); + } + } + } + + for (const each of set) { + if (each.length === longestSize) + return each; + } + + return ''; +}; + +function isNiceSubstring(letters) { + let lower = new Set(); + let upper = new Set(); + + for (const letter of letters) { + isLowerCaseLetter(letter) ? lower.add(letter) : upper.add(letter); + } + + for (const each of lower) { + if (!upper.has(each.toUpperCase())) return false; + } + + for (const each of upper) { + if (!lower.has(each.toLowerCase())) return false; + } + + return true; +} + +function isLowerCaseLetter(letter) { + return letter === letter.toLowerCase(); +} +``` +
@@ -495,4 +556,6 @@ function solution(gems) { [Window Sliding Technique](https://www.geeksforgeeks.org/window-sliding-technique/) ━ *GeeksforGeeks* +[Simple Solution at 1763. Longest Nice Substring](https://leetcode.com/problems/longest-nice-substring/discuss/1076734/javascript-direct-way-200ms) ━ *Leetcode* + [Simple Solution at 보석 쇼핑](https://school.programmers.co.kr/learn/courses/30/lessons/67258/solution_groups?language=javascript&type=all) ━ *Programmers* \ No newline at end of file