Skip to content

Commit 80e2e17

Browse files
togo26parkhojeongdahyeong-yun
authored
[togo26] WEEK 03 Solutions (#2723)
* contains-duplicate solution * two-sum solution * top-k-frequent-elements solution * longest-consecutive-sequence solution * house-robber solution * valid-anagram solution * climbing-stairs solution * product-of-array-except-self solution * 3sum solution * validate-binary-search-tree solution * Apply suggestion from @parkhojeong Co-authored-by: Hojeong Park <parkhj062@gmail.com> * valid-palindrome solution * number-of-1-bits solution * combination-sum solution * decode-ways solution * maximum-subarray solution * Update valid-palindrome/togo26.js Remove unnecessary regex construction Co-authored-by: polymorph <33543196+dahyeong-yun@users.noreply.github.com> * Update decode-ways/togo26.js Remove redundant code range validation Co-authored-by: polymorph <33543196+dahyeong-yun@users.noreply.github.com> --------- Co-authored-by: Hojeong Park <parkhj062@gmail.com> Co-authored-by: polymorph <33543196+dahyeong-yun@users.noreply.github.com>
1 parent e9336ed commit 80e2e17

5 files changed

Lines changed: 253 additions & 0 deletions

File tree

combination-sum/togo26.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @param {number[]} candidates
3+
* @param {number} target
4+
* @return {number[][]}
5+
*/
6+
7+
// C = candidates, T = target, m = smallest candidate value
8+
// TC: O(C^(T/m)) -> 후보와 타겟 깊이 간 지수적 증가
9+
// SC: O(T/m) -> 재귀 스택 깊이 (*출력 결과는 복잡도 계산 제외)
10+
var combinationSum = function (candidates, target) {
11+
const result = [];
12+
13+
function go(candi, combi, acc, start) {
14+
if (acc === target) {
15+
result.push(combi);
16+
return;
17+
}
18+
19+
for (let i = start; i < candi.length; i++) {
20+
const newAcc = acc + candi[i];
21+
const newCombi = [...combi, candi[i]];
22+
if (newAcc > target) break;
23+
go(candi, newCombi, newAcc, i);
24+
}
25+
}
26+
27+
go(
28+
[...candidates].sort((a, b) => a - b), // 값 순서 보장으로 새로운 누적 값에서 조기 종료 가능. 오름차순에 따라 newAcc가 target을 넘어가면 이후의 후보들은 계산할 필요 없음.
29+
[],
30+
0,
31+
0,
32+
);
33+
34+
return result;
35+
};

decode-ways/togo26.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* @param {string} s
3+
* @return {number}
4+
*/
5+
6+
// TLE
7+
// var numDecodings = function(s) {
8+
// const codeMap = {};
9+
// for (let i = 1; i <= 26; i++) {
10+
// codeMap[i] = String.fromCharCode(64 + i);
11+
// }
12+
13+
// const memo = {};
14+
// let count = 0;
15+
// function go(string, start) {
16+
// if (start >= string.length) {
17+
// count++;
18+
// return;
19+
// }
20+
21+
// const firstDigit = string[start];
22+
// const secondDigit = string[start + 1];
23+
// if (firstDigit === "0") return;
24+
25+
// if (codeMap[firstDigit]) {
26+
// go(string, start + 1);
27+
// }
28+
29+
// const twoDigits = firstDigit + secondDigit;
30+
// if (Number(twoDigits) <= 26 && codeMap[twoDigits]) {
31+
// go(string, start + 2);
32+
// }
33+
// }
34+
35+
// go(s, 0, "");
36+
37+
// return count;
38+
// };
39+
40+
// TC: O(n) -> string 길이만큼
41+
// SC: O(n) -> string 길이만큼 스택 생성
42+
var numDecodings = function (s) {
43+
const codeMap = {};
44+
for (let i = 1; i <= 26; i++) {
45+
codeMap[i] = String.fromCharCode(64 + i);
46+
}
47+
48+
const memo = {};
49+
50+
function go(start) {
51+
if (start >= s.length) return 1;
52+
if (memo[start] !== undefined) return memo[start];
53+
54+
const firstDigit = s[start];
55+
const secondDigit = s[start + 1];
56+
57+
if (firstDigit === '0') return 0;
58+
59+
let ways = 0;
60+
61+
ways += go(start + 1);
62+
const twoDigits = firstDigit + secondDigit;
63+
if (Number(twoDigits) <= 26) {
64+
ways += go(start + 2);
65+
}
66+
67+
memo[start] = ways;
68+
69+
return ways;
70+
}
71+
72+
return go(0);
73+
};

maximum-subarray/togo26.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @param {number[]} nums
3+
* @return {number}
4+
*/
5+
6+
// TLE
7+
// var maxSubArray = function(nums) {
8+
// if (nums.length <= 1) return nums[0];
9+
10+
// const sum = (arr) => arr.reduce((acc, cur) => {
11+
// acc += cur;
12+
// return acc;
13+
// }, 0);
14+
15+
// let total = -Infinity;
16+
// for (let i = 0; i < nums.length; i++) {
17+
// for (let j = i; j < nums.length; j++) {
18+
// const result = sum(nums.slice(i, j + 1));
19+
// total = Math.max(total, result);
20+
// }
21+
// }
22+
23+
// return total;
24+
// };
25+
26+
// TLE
27+
// var maxSubArray = function(nums) {
28+
// if (nums.length <= 1) return nums[0];
29+
30+
// let total = -Infinity;
31+
// for (let i = 0; i < nums.length; i++) {
32+
// let acc = 0;
33+
// for (let j = i; j < nums.length; j++) {
34+
// acc += nums[j];
35+
// total = Math.max(total, acc);
36+
// }
37+
// }
38+
39+
// return total;
40+
// };
41+
42+
// TC: O(n) / SC: O(1)
43+
var maxSubArray = function (nums) {
44+
let total = nums[0];
45+
let acc = nums[0];
46+
47+
for (let i = 1; i < nums.length; i++) {
48+
acc = Math.max(nums[i], acc + nums[i]); // 이전 누적값 선택 vs 현재값 선택 (카데인 알고리즘)
49+
total = Math.max(total, acc); // 최대 합산 값 갱신
50+
}
51+
52+
return total;
53+
};

number-of-1-bits/togo26.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @param {number} n
3+
* @return {number}
4+
*/
5+
6+
// 31 비트 범위는 상수로 취급
7+
8+
// Log-based calculation
9+
// TC: O(1) / SC: O(1)
10+
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(logn)
11+
var hammingWeight = function (n) {
12+
const BIT_RANGE = 31;
13+
let bits = Array.from({ length: BIT_RANGE }).fill(0);
14+
15+
let remainder = n;
16+
while (remainder > 0) {
17+
const exp = Math.min(Math.floor(Math.log2(remainder)), BIT_RANGE - 1);
18+
bits[exp] = true;
19+
const value = remainder <= 1 ? 1 : Math.pow(2, exp);
20+
remainder -= value;
21+
}
22+
23+
return bits.filter(value => value).length;
24+
};
25+
26+
// Log-based calculation without an array
27+
// TC: O(1) / SC: O(1)
28+
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(1)
29+
var hammingWeight = function (n) {
30+
const BIT_RANGE = 31;
31+
let bitCount = 0;
32+
33+
let remainder = n;
34+
while (remainder > 0) {
35+
const exp = Math.min(Math.floor(Math.log2(remainder)), BIT_RANGE - 1);
36+
const value = remainder <= 1 ? 1 : Math.pow(2, exp);
37+
remainder -= value;
38+
bitCount++;
39+
}
40+
41+
return bitCount;
42+
};
43+
44+
// Converting binary string with the JS feature
45+
// TC: O(1) / SC: O(1)
46+
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(logn)
47+
var hammingWeight = function (n) {
48+
const binaryString = n.toString(2);
49+
return [...binaryString].filter(v => v === '1').length;
50+
};
51+
52+
// Bit manipulation
53+
// TC: O(1) / SC: O(1)
54+
// 비트 제약이 없을 경우 -> TC: O(logn) / SC: O(logn)
55+
var hammingWeight = function (n) {
56+
let count = 0;
57+
58+
while (n > 0) {
59+
n = n & (n - 1);
60+
count++;
61+
}
62+
63+
return count;
64+
};

valid-palindrome/togo26.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @param {string} s
3+
* @return {boolean}
4+
*/
5+
// TC: O(n) / SC: O(n)
6+
var isPalindrome = function (s) {
7+
const processed = s.toLowerCase().replaceAll(/[^a-z0-9]+/g, '');
8+
const reversed = [...processed].reverse().join('');
9+
return processed === reversed;
10+
};
11+
12+
// TC: O(n) / SC: O(1)
13+
// With two pointers
14+
var isPalindrome = function (s) {
15+
const nonAlphanumeric = /[^a-zA-Z0-9]+/;
16+
let left = 0;
17+
let right = s.length - 1;
18+
19+
while (left < right) {
20+
while (left < right && nonAlphanumeric.test(s[left])) left++; // 단일 문자 테스트 O(1) 상수 취급
21+
while (left < right && nonAlphanumeric.test(s[right])) right--;
22+
if (s[left].toLowerCase() !== s[right].toLowerCase()) return false;
23+
left++;
24+
right--;
25+
}
26+
27+
return true;
28+
};

0 commit comments

Comments
 (0)