From 1fe7d80c17f714afdbf484135fa17da272180de5 Mon Sep 17 00:00:00 2001 From: youngduck Date: Mon, 28 Jul 2025 10:34:51 +0900 Subject: [PATCH 1/9] =?UTF-8?q?valid=20anagram=20=ED=92=80=EC=9D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- valid-anagram/youngduck.js | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 valid-anagram/youngduck.js diff --git a/valid-anagram/youngduck.js b/valid-anagram/youngduck.js new file mode 100644 index 000000000..6216bb35e --- /dev/null +++ b/valid-anagram/youngduck.js @@ -0,0 +1,66 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +var isAnagram = function (s, t) { + const mapS = new Map(); + const mapT = new Map(); + + [...s].map((item) => { + if (mapS.has(item)) { + const itemCount = mapS.get(item); + mapS.set(item, itemCount + 1); + } else { + mapS.set(item, 1); + } + }); + + [...t].map((item) => { + if (mapT.has(item)) { + const itemCount = mapT.get(item); + mapT.set(item, itemCount + 1); + } else { + mapT.set(item, 1); + } + }); + + // NOTE - t가 s의 anagram이라는 뜻을 갯수가 같지않아도 된다고 이해했으나 anagram정의는 s구성원을 모자람,남김없이 t를만들 수 있는 상태 + if (mapS.size !== mapT.size) { + return false; + } + + for (const [key, value] of mapS) { + if (mapT.get(key) !== value) { + return false; + } + } + + return true; + }; + + // 시간복잡도: O(n) + // - 문자열 s와 t를 각각 한 번씩 순회: O(n) + O(n) = O(2n) = O(n) + // - Map 비교를 위한 순회: O(k), 여기서 k는 고유 문자 개수 + // - 따라서 전체 시간복잡도는 O(n) + // 공간복잡도: O(1) + // - 두 개의 Map 객체 생성: mapS와 mapT + // - 각 Map은 최대 k개의 고유 문자를 저장 (k는 고유 문자 개수) + // - 소문자 영문자만 사용하므로 k ≤ 26 (a-z) + // - 따라서 전체 공간복잡도는 O(1) (상수 시간) + + // follow up: 유니코드 테스트 케이스. 큰 의미는 없음 + console.log(isAnagram("😀😀", "😀😀😀")); + // false + console.log(isAnagram("한글글", "글한글")); + // true + console.log(isAnagram("café", "éfac")); + // true + console.log(isAnagram("Hello世界", "世界Hello")); + // true + console.log(isAnagram("안녕 하세요", "하세요 안녕")); + // true + console.log(isAnagram("Café", "éfac")); + // false + console.log(isAnagram("Café", "Éfac")); + // false \ No newline at end of file From ce3d49d39ba31807fef550f595596d7731e11dfd Mon Sep 17 00:00:00 2001 From: youngduck Date: Mon, 28 Jul 2025 17:58:24 +0900 Subject: [PATCH 2/9] =?UTF-8?q?climbing=20stairs=20=ED=92=80=EC=9D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- climbing-stairs/youngduck.js | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 climbing-stairs/youngduck.js diff --git a/climbing-stairs/youngduck.js b/climbing-stairs/youngduck.js new file mode 100644 index 000000000..d95242159 --- /dev/null +++ b/climbing-stairs/youngduck.js @@ -0,0 +1,42 @@ +/** + * @param {number} n + * @return {number} + */ +var climbStairs = function (n) { + // 문제를 보자마자 든 생각: dfs처럼 하나씩,두개씩 가지뻗어가면서? -> 점화식,피보나치처럼 최적화된 형태겠는데? 여기까지는 생각. 근데 2칸전, 1칸전의 덧셈이라는 결론까지 내지는 못함 + + // 그래서 default값을 n=1,2,3까지 세팅해놓고 생각했었다. 다른사람의 점화식 풀이 참고 후 역순으로 출발해서 2칸전, 1칸전에 대한 상황에 집중하는 방식 이해 완료. 구현은 내가 직접. + if (n === 1) { + return 1; + } + + if (n === 2) { + return 2; + } + + return climbStairs(n - 1) + climbStairs(n - 2); +}; + +// 시간복잡도: O(2^n) +// 공간복잡도: O(n) + +/** + * @param {number} n + * @return {number} + */ +var climbStairs = function (n) { + const dp = Array(n).fill(0); + dp[1] = 1; + dp[2] = 2; + + if (n >= 3) { + for (let i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + } + + return dp[n]; +}; + +// 시간복잡도: O(n) +// 공간복잡도: O(n) !! dp라는 배열대신 변수 두개로 O(1)로 줄일 수 있음 From 87fc3f933321efa61fb63a64d8acb549201d20ba Mon Sep 17 00:00:00 2001 From: youngduck Date: Tue, 29 Jul 2025 10:20:38 +0900 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20=EB=A6=B0=ED=8A=B8=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- climbing-stairs/youngduck.js | 2 +- valid-anagram/youngduck.js | 105 ++++++++++++++++------------------- 2 files changed, 50 insertions(+), 57 deletions(-) diff --git a/climbing-stairs/youngduck.js b/climbing-stairs/youngduck.js index d95242159..abc9fd0b9 100644 --- a/climbing-stairs/youngduck.js +++ b/climbing-stairs/youngduck.js @@ -24,7 +24,7 @@ var climbStairs = function (n) { * @param {number} n * @return {number} */ -var climbStairs = function (n) { +var climbStairsOptimized = function (n) { const dp = Array(n).fill(0); dp[1] = 1; dp[2] = 2; diff --git a/valid-anagram/youngduck.js b/valid-anagram/youngduck.js index 6216bb35e..faa3857bf 100644 --- a/valid-anagram/youngduck.js +++ b/valid-anagram/youngduck.js @@ -4,63 +4,56 @@ * @return {boolean} */ var isAnagram = function (s, t) { - const mapS = new Map(); - const mapT = new Map(); - - [...s].map((item) => { - if (mapS.has(item)) { - const itemCount = mapS.get(item); - mapS.set(item, itemCount + 1); - } else { - mapS.set(item, 1); - } - }); - - [...t].map((item) => { - if (mapT.has(item)) { - const itemCount = mapT.get(item); - mapT.set(item, itemCount + 1); - } else { - mapT.set(item, 1); - } - }); - - // NOTE - t가 s의 anagram이라는 뜻을 갯수가 같지않아도 된다고 이해했으나 anagram정의는 s구성원을 모자람,남김없이 t를만들 수 있는 상태 - if (mapS.size !== mapT.size) { - return false; + const mapS = new Map(); + const mapT = new Map(); + + [...s].map((item) => { + if (mapS.has(item)) { + const itemCount = mapS.get(item); + mapS.set(item, itemCount + 1); + } else { + mapS.set(item, 1); + } + }); + + [...t].map((item) => { + if (mapT.has(item)) { + const itemCount = mapT.get(item); + mapT.set(item, itemCount + 1); + } else { + mapT.set(item, 1); } - - for (const [key, value] of mapS) { - if (mapT.get(key) !== value) { - return false; - } + }); + + // NOTE - t가 s의 anagram이라는 뜻을 갯수가 같지않아도 된다고 이해했으나 anagram정의는 s구성원을 모자람,남김없이 t를만들 수 있는 상태 + if (mapS.size !== mapT.size) { + return false; + } + + for (const [key, value] of mapS) { + if (mapT.get(key) !== value) { + return false; } - - return true; - }; + } + + return true; +}; - // 시간복잡도: O(n) - // - 문자열 s와 t를 각각 한 번씩 순회: O(n) + O(n) = O(2n) = O(n) - // - Map 비교를 위한 순회: O(k), 여기서 k는 고유 문자 개수 - // - 따라서 전체 시간복잡도는 O(n) - // 공간복잡도: O(1) - // - 두 개의 Map 객체 생성: mapS와 mapT - // - 각 Map은 최대 k개의 고유 문자를 저장 (k는 고유 문자 개수) - // - 소문자 영문자만 사용하므로 k ≤ 26 (a-z) - // - 따라서 전체 공간복잡도는 O(1) (상수 시간) +// 시간복잡도: O(n) +// - 문자열 s와 t를 각각 한 번씩 순회: O(n) + O(n) = O(2n) = O(n) +// - Map 비교를 위한 순회: O(k), 여기서 k는 고유 문자 개수 +// - 따라서 전체 시간복잡도는 O(n) +// 공간복잡도: O(1) +// - 두 개의 Map 객체 생성: mapS와 mapT +// - 각 Map은 최대 k개의 고유 문자를 저장 (k는 고유 문자 개수) +// - 소문자 영문자만 사용하므로 k ≤ 26 (a-z) +// - 따라서 전체 공간복잡도는 O(1) (상수 시간) - // follow up: 유니코드 테스트 케이스. 큰 의미는 없음 - console.log(isAnagram("😀😀", "😀😀😀")); - // false - console.log(isAnagram("한글글", "글한글")); - // true - console.log(isAnagram("café", "éfac")); - // true - console.log(isAnagram("Hello世界", "世界Hello")); - // true - console.log(isAnagram("안녕 하세요", "하세요 안녕")); - // true - console.log(isAnagram("Café", "éfac")); - // false - console.log(isAnagram("Café", "Éfac")); - // false \ No newline at end of file +// follow up: 유니코드 테스트 케이스. 큰 의미는 없음 +// console.log(isAnagram("😀😀", "😀😀😀")); // false +// console.log(isAnagram("한글글", "글한글")); // true +// console.log(isAnagram("café", "éfac")); // true +// console.log(isAnagram("Hello世界", "世界Hello")); // true +// console.log(isAnagram("안녕 하세요", "하세요 안녕")); // true +// console.log(isAnagram("Café", "éfac")); // false +// console.log(isAnagram("Café", "Éfac")); // false From d45338c1e5ea469cd3595e053e60a1a0463c39b7 Mon Sep 17 00:00:00 2001 From: youngduck Date: Thu, 31 Jul 2025 09:21:06 +0900 Subject: [PATCH 4/9] =?UTF-8?q?product-of-array-except-self=ED=92=80?= =?UTF-8?q?=EC=9D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- product-of-array-except-self/youngduck.js | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 product-of-array-except-self/youngduck.js diff --git a/product-of-array-except-self/youngduck.js b/product-of-array-except-self/youngduck.js new file mode 100644 index 000000000..033b00d86 --- /dev/null +++ b/product-of-array-except-self/youngduck.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var productExceptSelf = function (nums) { + const numsLength = nums.length; + + const result = new Array(numsLength).fill(1); + + let left = 1; + let right = 1; + + for (let i = 0; i < numsLength; i++) { + result[i] *= left; + left *= nums[i]; + + result[numsLength - i - 1] *= right; + right *= nums[numsLength - i - 1]; + } + + // TC: O(n), SC: O(1) + + return result; +}; + +console.log(productExceptSelf([1, 2, 3, 4])); From fa2826cf04529c7ba124ed2b1a9bdd211134db8d Mon Sep 17 00:00:00 2001 From: youngduck Date: Thu, 31 Jul 2025 09:21:17 +0900 Subject: [PATCH 5/9] =?UTF-8?q?product-of-array-except-self=ED=92=80?= =?UTF-8?q?=EC=9D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- product-of-array-except-self/youngduck.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/product-of-array-except-self/youngduck.js b/product-of-array-except-self/youngduck.js index 033b00d86..2d2f18d5f 100644 --- a/product-of-array-except-self/youngduck.js +++ b/product-of-array-except-self/youngduck.js @@ -7,6 +7,9 @@ var productExceptSelf = function (nums) { const result = new Array(numsLength).fill(1); + // for문 하나로 처리할경우 O(n^2). + // for문 두개로 나눠서 처리할경우 O(n). 누적곱 개념을 활용해줘야함 + let left = 1; let right = 1; @@ -18,9 +21,7 @@ var productExceptSelf = function (nums) { right *= nums[numsLength - i - 1]; } - // TC: O(n), SC: O(1) + // 시간복잡도: O(n), 공간복잡도: O(1) return result; }; - -console.log(productExceptSelf([1, 2, 3, 4])); From 9eb1636182ae0a78860d9b40c1ffe7be8abd7765 Mon Sep 17 00:00:00 2001 From: youngduck Date: Thu, 31 Jul 2025 09:30:10 +0900 Subject: [PATCH 6/9] =?UTF-8?q?=EB=88=84=EC=A0=81=EA=B3=B1=20=ED=92=80?= =?UTF-8?q?=EC=9D=B4=20=EC=A3=BC=EC=84=9D=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- product-of-array-except-self/youngduck.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/product-of-array-except-self/youngduck.js b/product-of-array-except-self/youngduck.js index 2d2f18d5f..971f9c631 100644 --- a/product-of-array-except-self/youngduck.js +++ b/product-of-array-except-self/youngduck.js @@ -7,8 +7,9 @@ var productExceptSelf = function (nums) { const result = new Array(numsLength).fill(1); - // for문 하나로 처리할경우 O(n^2). + // 일반적으로 for문 하나로 자기자신 제외하면서 곱셈을하면서 처리할경우 O(n^2). // for문 두개로 나눠서 처리할경우 O(n). 누적곱 개념을 활용해줘야함 + // for문 하나로 누적곱 개념을 활용해서 처리할경우 O(n). let left = 1; let right = 1; From fe593e35d81befc8bd0a24abadabce5aaa15bb3c Mon Sep 17 00:00:00 2001 From: youngduck Date: Sat, 2 Aug 2025 22:59:54 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=203sum=ED=92=80=EC=9D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3sum/youngduck.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 3sum/youngduck.js diff --git a/3sum/youngduck.js b/3sum/youngduck.js new file mode 100644 index 000000000..eafc1c399 --- /dev/null +++ b/3sum/youngduck.js @@ -0,0 +1,46 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +var threeSum = function(nums) { + + // 최악의 경우 3중 for문이므로 투포인터 기법을써서 최적화 해도 for문 하나는 필요함 + + // 결과 배열 + const result = []; + + // 투포인터 기법 사용을 위한 정렬 + nums.sort((a,b)=>a-b); + + for(let i = 0; i < nums.length - 2; i++){ + // 첫 번째 요소의 중복 건너뛰기 + if(i > 0 && nums[i] === nums[i-1]) continue; + + let left = i + 1; + let right = nums.length - 1; + + while(left < right){ + const sum = nums[i] + nums[left] + nums[right]; + + if(sum < 0){ + left++; + } + else if (sum > 0){ + right--; + } + else{ + // 합이 0인 경우 결과에 추가 + result.push([nums[i], nums[left], nums[right]]); + + // 두 번째, 세 번째 요소의 중복 건너뛰기 + while(left < right && nums[left] === nums[left + 1]) left++; + while(left < right && nums[right] === nums[right - 1]) right--; + + left++; + right--; + } + } + } + + return result; +}; \ No newline at end of file From 1204565f6ee0e76427554921fad3714cf7ffd067 Mon Sep 17 00:00:00 2001 From: youngduck Date: Sat, 2 Aug 2025 23:01:30 +0900 Subject: [PATCH 8/9] =?UTF-8?q?feat:=20=EC=8B=9C=EA=B0=84=EB=B3=B5?= =?UTF-8?q?=EC=9E=A1=EB=8F=84=EA=B3=B5=EA=B0=84=EB=B3=B5=EC=9E=A1=EB=8F=84?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3sum/youngduck.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/3sum/youngduck.js b/3sum/youngduck.js index eafc1c399..f839a9dff 100644 --- a/3sum/youngduck.js +++ b/3sum/youngduck.js @@ -43,4 +43,6 @@ var threeSum = function(nums) { } return result; -}; \ No newline at end of file +}; +// 시간복잡도: O(n^2) +// 공간복잡도: O(1) \ No newline at end of file From 0e431df0d67d6dc2d0fe71235ce1cebcbb6fab23 Mon Sep 17 00:00:00 2001 From: youngduck Date: Sat, 2 Aug 2025 23:06:20 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=EC=A4=84=EB=B0=94=EA=BF=88=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3sum/youngduck.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/3sum/youngduck.js b/3sum/youngduck.js index f839a9dff..36cf6e04d 100644 --- a/3sum/youngduck.js +++ b/3sum/youngduck.js @@ -45,4 +45,5 @@ var threeSum = function(nums) { return result; }; // 시간복잡도: O(n^2) -// 공간복잡도: O(1) \ No newline at end of file +// 공간복잡도: O(1) +