From 5c3106632b6242e315fe641c700b31bffe61c22a Mon Sep 17 00:00:00 2001 From: Zero-1016 Date: Sun, 5 Jul 2026 10:50:07 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- combination-sum/Zero-1016.ts | 0 decode-ways/Zero-1016.ts | 0 maximum-subarray/Zero-1016.ts | 0 number-of-1-bits/Zero-1016.ts | 0 valid-palindrome/Zero-1016.ts | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 combination-sum/Zero-1016.ts create mode 100644 decode-ways/Zero-1016.ts create mode 100644 maximum-subarray/Zero-1016.ts create mode 100644 number-of-1-bits/Zero-1016.ts create mode 100644 valid-palindrome/Zero-1016.ts diff --git a/combination-sum/Zero-1016.ts b/combination-sum/Zero-1016.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/decode-ways/Zero-1016.ts b/decode-ways/Zero-1016.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/maximum-subarray/Zero-1016.ts b/maximum-subarray/Zero-1016.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/number-of-1-bits/Zero-1016.ts b/number-of-1-bits/Zero-1016.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/valid-palindrome/Zero-1016.ts b/valid-palindrome/Zero-1016.ts new file mode 100644 index 0000000000..e69de29bb2 From 64e0213c27de8cb941ecd7dbbb90c34a7602db96 Mon Sep 17 00:00:00 2001 From: Zero-1016 Date: Sun, 5 Jul 2026 11:07:34 +0900 Subject: [PATCH 2/6] feat: valid-palindrome --- valid-palindrome/Zero-1016.ts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/valid-palindrome/Zero-1016.ts b/valid-palindrome/Zero-1016.ts index e69de29bb2..02b64e1ed6 100644 --- a/valid-palindrome/Zero-1016.ts +++ b/valid-palindrome/Zero-1016.ts @@ -0,0 +1,34 @@ +/** + * 시간 복잡도 O(N) + * 공간 복잡도 O(1) + */ +const isNotAlphanumeric = /[^a-zA-Z0-9]/; + +function isPalindrome(s: string): boolean { + let leftCursor = 0; + let rightCursor = s.length - 1; + + while (leftCursor < rightCursor) { + const currentLeftAlpha = s[leftCursor]; + const currentRightAlpha = s[rightCursor]; + + if (isNotAlphanumeric.test(currentLeftAlpha)) { + leftCursor++; + continue; + } + + if (isNotAlphanumeric.test(currentRightAlpha)) { + rightCursor--; + continue; + } + + if (currentLeftAlpha.toLowerCase() === currentRightAlpha.toLowerCase()) { + leftCursor++; + rightCursor--; + } else { + return false; + } + } + + return true; +} From 31eec440f290f215fa6c276d333cd8d487ff7697 Mon Sep 17 00:00:00 2001 From: Zero-1016 Date: Sun, 5 Jul 2026 11:20:06 +0900 Subject: [PATCH 3/6] feat: number-of-1-bits --- number-of-1-bits/Zero-1016.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/number-of-1-bits/Zero-1016.ts b/number-of-1-bits/Zero-1016.ts index e69de29bb2..bede6de8f2 100644 --- a/number-of-1-bits/Zero-1016.ts +++ b/number-of-1-bits/Zero-1016.ts @@ -0,0 +1,21 @@ +/** + * 시간 복잡도 O(N) + * 공간 복잡도 O(N) + */ +function hammingWeight1(n: number): number { + const bitNumber = n.toString(2); + return bitNumber.split("").filter((char) => char === "1").length; +} + +/** + * 시간 복잡도 O(N) + * 공간 복잡도 O(1) + */ +function hammingWeight2(n: number): number { + let count = 0; + while (n > 0) { + count += n & 1; // 마지막 비트가 1인지 확인 + n = n >>> 1; // 우측으로 1비트 시프트 (부호 없는 우측 시프트) + } + return count; +} From 66960cdba40974c35d5800b4c5191830d086323a Mon Sep 17 00:00:00 2001 From: Zero-1016 Date: Sun, 5 Jul 2026 13:58:59 +0900 Subject: [PATCH 4/6] feat: combination-sum --- combination-sum/Zero-1016.ts | 88 ++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/combination-sum/Zero-1016.ts b/combination-sum/Zero-1016.ts index e69de29bb2..6ef22517e1 100644 --- a/combination-sum/Zero-1016.ts +++ b/combination-sum/Zero-1016.ts @@ -0,0 +1,88 @@ +/** + * Combination Sum1 (같은 숫자 재사용 가능) — 비효율 버전 + * + * 표기: + * n = candidates 길이 + * T = target + * M = candidates 중 최솟값 + * D = T / M (재귀 트리의 최대 깊이) + * 시간 복잡도: O(nᴰ × D) + * - start 인덱스가 없어 매번 0부터 탐색 → [2,2,3], [2,3,2], [3,2,2] 같은 + * 순열을 전부 방문 (조합 하나당 최대 D! 개) + * - 정답 발견 시 경로 복사 O(D), 후처리(sort + join + Set) 비용은 탐색량에 묻힘 + * + * 공간 복잡도: O(D! × 정답 개수 × D) + * - 중복 조합이 제거 전까지 combinations에 전부 쌓임 → OOM 위험 + * - 재귀 스택: O(D) + */ +function combinationSum1(candidates: number[], target: number): number[][] { + const combinations: number[][] = []; + + const backtrack = (currentPath: number[], currentSum: number) => { + const pathCopy = [...currentPath]; + const remainingTarget = target - currentSum; + + if (remainingTarget === 0) { + combinations.push(pathCopy); + } + + for (let i = 0; i < candidates.length; i++) { + const candidate = candidates[i]; + + if (remainingTarget - candidate >= 0) { + pathCopy.push(candidate); + backtrack(pathCopy, currentSum + candidate); + pathCopy.pop(); + } + } + }; + + backtrack([], 0); + + // 중복 조합 제거 후 반환 + return [...new Set(combinations.map((path) => path.sort().join(",")))].map( + (str) => str.split(",").map(Number), + ); +} + +/** + * Combination Sum2 (같은 숫자 재사용 가능) — 최적화 버전 + * + * 표기: + * n = candidates 길이 + * T = target + * M = candidates 중 최솟값 + * D = T / M (재귀 트리의 최대 깊이) + * + * 시간 복잡도: O(nᴰ × D) + * - Big-O 상한은 1번과 같지만 실제 탐색량은 훨씬 작음: + * 1) start 인덱스 → 순열 중복 탐색 원천 차단 (조합당 정확히 1회 방문) + * 2) 정렬 + break → 무효한 가지를 통째로 절단 + * - 정렬 비용 O(n log n)은 지수 항에 묻힘 + * + * 공간 복잡도: O(D + 정답 개수 × D) + * - 재귀 스택 + 공유 path: O(D) + * - 출력 배열: 정답 개수 × 평균 길이 (출력 자체라 최소 비용) + */ +function combinationSum2(candidates: number[], target: number): number[][] { + const combinations: number[][] = []; + candidates.sort((a, b) => a - b); + + const backtrack = (start: number, path: number[], remaining: number) => { + if (remaining === 0) { + combinations.push([...path]); + return; + } + + for (let i = start; i < candidates.length; i++) { + if (candidates[i] > remaining) break; + + path.push(candidates[i]); + backtrack(i, path, remaining - candidates[i]); + path.pop(); + } + }; + + backtrack(0, [], target); + return combinations; +} From faa8fb06f2a892092611ee3574f50109eecb275a Mon Sep 17 00:00:00 2001 From: Zero-1016 Date: Sun, 5 Jul 2026 14:12:02 +0900 Subject: [PATCH 5/6] feat: maximum-subarray --- maximum-subarray/Zero-1016.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/maximum-subarray/Zero-1016.ts b/maximum-subarray/Zero-1016.ts index e69de29bb2..ea9b67cd9f 100644 --- a/maximum-subarray/Zero-1016.ts +++ b/maximum-subarray/Zero-1016.ts @@ -0,0 +1,17 @@ +/** + * 시간 복잡도 O(n) + * 공간 복잡도 O(1) + */ +function maxSubArray(nums: number[]): number { + let currentSum = 0; + let maxSum = -Infinity; + + for (let i = 0; i < nums.length; i++) { + let n = nums[i]; + + currentSum = Math.max(currentSum + n, n); + maxSum = Math.max(maxSum, currentSum); + } + + return maxSum; +} From a642d65bd9b33ffcf9abd54831a5db20ea54b763 Mon Sep 17 00:00:00 2001 From: Zero-1016 Date: Sun, 5 Jul 2026 15:21:44 +0900 Subject: [PATCH 6/6] feat: numDecodings --- decode-ways/Zero-1016.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/decode-ways/Zero-1016.ts b/decode-ways/Zero-1016.ts index e69de29bb2..b1eb6eb9ca 100644 --- a/decode-ways/Zero-1016.ts +++ b/decode-ways/Zero-1016.ts @@ -0,0 +1,25 @@ +/** + * 시간 복잡도 O(n) + * 공간 복잡도 O(1) + */ +function numDecodings(s: string): number { + const n = s.length; + if (n === 0 || s[0] === "0") return 0; + + // prev2 = dp[i-2], prev1 = dp[i-1] + let prev2 = 1; // dp[0] + let prev1 = 1; // dp[1] (s[0]이 '0'이 아님을 위에서 보장) + + for (let i = 2; i <= n; i++) { + let cur = 0; + const one = s[i - 1]; // 마지막 한 자리 + const two = Number(s.slice(i - 2, i)); // 마지막 두 자리 + + if (one !== "0") cur += prev1; // 한 자리로 끊기 + if (two >= 10 && two <= 26) cur += prev2; // 두 자리로 끊기 + + prev2 = prev1; + prev1 = cur; + } + return prev1; +}