Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions combination-sum/togo26.js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: Backtracking, Depth-First Search
  • 설명: 가능한 조합들을 탐색하며 조건에 맞는 해를 찾아내는 재귀적 깊이 우선 탐색 방식으로 작동합니다. 후보를 고정된 시작 인덱스에서만 이어서 탐색하고, 누적 합이 타깃을 초과하면 가지를 잘라 관련 패턴인 Backtracking과 DFS에 해당합니다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(C^(T/m)) O(k * n^k)
Space O(T/m) O(k)

피드백: 정렬 후 탐색 트리에서 누적합이 target을 넘으면 가지를 자르도록 하여 불필요한 재귀 호출을 제거했습니다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/

// C = candidates, T = target, m = smallest candidate value
// TC: O(C^(T/m)) -> 후보와 타겟 깊이 간 지수적 증가
// SC: O(T/m) -> 재귀 스택 깊이 (*출력 결과는 복잡도 계산 제외)
var combinationSum = function (candidates, target) {
const result = [];

function go(candi, combi, acc, start) {
if (acc === target) {
result.push(combi);
return;
}

for (let i = start; i < candi.length; i++) {
const newAcc = acc + candi[i];
const newCombi = [...combi, candi[i]];
if (newAcc > target) break;
go(candi, newCombi, newAcc, i);
}
}

go(
[...candidates].sort((a, b) => a - b), // 값 순서 보장으로 새로운 누적 값에서 조기 종료 가능. 오름차순에 따라 newAcc가 target을 넘어가면 이후의 후보들은 계산할 필요 없음.
[],
0,
0,
);

return result;
};
76 changes: 76 additions & 0 deletions decode-ways/togo26.js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: Dynamic Programming, Hash Map / Hash Set
  • 설명: 코드는 부분문제의 해를 저장하는 메모이제이션을 사용해, 문자열의 각 위치에서 가능한 해의 수를 재귀적으로 계산하고 중간 결과를 저장합니다. 이는 DP의 대표적 형태인 탑다운(d top-down) 방식에 해당하며, 해시맵을 이용해 메모이제이션을 구현합니다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(n) O(n)
Space O(n) O(n)

피드백: 숫자 문자열을 한 자리/두 자리로 분리해 가짓수를 누적하는 전형적인 DP 풀이입니다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* @param {string} s
* @return {number}
*/

// TLE
// var numDecodings = function(s) {
// const codeMap = {};
// for (let i = 1; i <= 26; i++) {
// codeMap[i] = String.fromCharCode(64 + i);
// }

// const memo = {};
// let count = 0;
// function go(string, start) {
// if (start >= string.length) {
// count++;
// return;
// }

// const firstDigit = string[start];
// const secondDigit = string[start + 1];
// if (firstDigit === "0") return;

// if (codeMap[firstDigit]) {
// go(string, start + 1);
// }

// const twoDigits = firstDigit + secondDigit;
// if (Number(twoDigits) <= 26 && codeMap[twoDigits]) {
// go(string, start + 2);
// }
// }

// go(s, 0, "");

// return count;
// };

// TC: O(n) -> string 길이만큼
// SC: O(n) -> string 길이만큼 스택 생성
var numDecodings = function (s) {
const codeMap = {};
for (let i = 1; i <= 26; i++) {
codeMap[i] = String.fromCharCode(64 + i);
}

const memo = {};

function go(start) {
if (start >= s.length) return 1;
if (memo[start] !== undefined) return memo[start];

const firstDigit = s[start];
const secondDigit = s[start + 1];

if (firstDigit === '0') return 0;

let ways = 0;

if (codeMap[firstDigit]) {
ways += go(start + 1);
}

const twoDigits = firstDigit + secondDigit;
if (Number(twoDigits) <= 26 && codeMap[twoDigits]) {
ways += go(start + 2);
}

memo[start] = ways;

return ways;
}

return go(0);
};
53 changes: 53 additions & 0 deletions maximum-subarray/togo26.js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: Greedy, Dynamic Programming
  • 설명: 카데인 알고리즘으로 알려진 Kadane를 사용하여 부분배열의 합의 최댓값을 구하는 방식으로, 현재 위치에서 시작하는 연속 부분배열과 전체의 최댓값을 비교하며 한 번의 순회로 해결한다. 이는 점화식 및 최적해를 이전 상태에서 계산하는 DP/그리디 성격을 모두 갖는다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(n) O(n)
Space O(n) O(1)

피드백: 현재 구현은 최적의 선형 알고리즘으로 공간도 상수이며, 음수 배열도 처리합니다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @param {number[]} nums
* @return {number}
*/

// TLE
// var maxSubArray = function(nums) {
// if (nums.length <= 1) return nums[0];

// const sum = (arr) => arr.reduce((acc, cur) => {
// acc += cur;
// return acc;
// }, 0);

// let total = -Infinity;
// for (let i = 0; i < nums.length; i++) {
// for (let j = i; j < nums.length; j++) {
// const result = sum(nums.slice(i, j + 1));
// total = Math.max(total, result);
// }
// }

// return total;
// };

// TLE
// var maxSubArray = function(nums) {
// if (nums.length <= 1) return nums[0];

// let total = -Infinity;
// for (let i = 0; i < nums.length; i++) {
// let acc = 0;
// for (let j = i; j < nums.length; j++) {
// acc += nums[j];
// total = Math.max(total, acc);
// }
// }

// return total;
// };

// TC: O(n) / SC: O(1)
var maxSubArray = function (nums) {
let total = nums[0];
let acc = nums[0];

for (let i = 1; i < nums.length; i++) {
acc = Math.max(nums[i], acc + nums[i]); // 이전 누적값 선택 vs 현재값 선택 (카데인 알고리즘)
total = Math.max(total, acc); // 최대 합산 값 갱신
}

return total;
};
64 changes: 64 additions & 0 deletions number-of-1-bits/togo26.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* @param {number} n
* @return {number}
*/

// 31 비트 범위는 상수로 취급

// Log-based calculation
// TC: O(1) / SC: O(1)
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(logn)
var hammingWeight = function (n) {
const BIT_RANGE = 31;
let bits = Array.from({ length: BIT_RANGE }).fill(0);

let remainder = n;
while (remainder > 0) {
const exp = Math.min(Math.floor(Math.log2(remainder)), BIT_RANGE - 1);
bits[exp] = true;
const value = remainder <= 1 ? 1 : Math.pow(2, exp);
remainder -= value;
}

return bits.filter(value => value).length;
};

// Log-based calculation without an array
// TC: O(1) / SC: O(1)
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(1)
var hammingWeight = function (n) {
const BIT_RANGE = 31;
let bitCount = 0;

let remainder = n;
while (remainder > 0) {
const exp = Math.min(Math.floor(Math.log2(remainder)), BIT_RANGE - 1);
const value = remainder <= 1 ? 1 : Math.pow(2, exp);
remainder -= value;
bitCount++;
}

return bitCount;
};

// Converting binary string with the JS feature
// TC: O(1) / SC: O(1)
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(logn)
var hammingWeight = function (n) {
const binaryString = n.toString(2);
return [...binaryString].filter(v => v === '1').length;
};

// Bit manipulation
// TC: O(1) / SC: O(1)
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(logn)
var hammingWeight = function (n) {
let count = 0;

while (n > 0) {
n = n & (n - 1);
count++;
}

return count;
};
28 changes: 28 additions & 0 deletions valid-palindrome/togo26.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @param {string} s
* @return {boolean}
*/
// TC: O(n) / SC: O(n)
var isPalindrome = function (s) {
const processed = s.toLowerCase().replaceAll(/[^a-z0-9]+/g, '');
const reversed = [...processed].reverse().join('');
return processed === reversed;
};

// TC: O(n) / SC: O(1)
// With two pointers
var isPalindrome = function (s) {
const nonAlphanumeric = new RegExp(/[^a-zA-Z0-9]+/);
let left = 0;
let right = s.length - 1;

while (left < right) {
while (left < right && nonAlphanumeric.test(s[left])) left++; // 단일 문자 테스트 O(1) 상수 취급
while (left < right && nonAlphanumeric.test(s[right])) right--;
if (s[left].toLowerCase() !== s[right].toLowerCase()) return false;
left++;
right--;
}

return true;
};
Loading