Skip to content

Commit 521c00b

Browse files
authored
Merge pull request #352 from naringst/main
[나리] WEEK 02 Solutions
2 parents d0eed34 + f449a1e commit 521c00b

File tree

4 files changed

+232
-0
lines changed

4 files changed

+232
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* [Idea]
3+
* preorder는 val -> left -> right
4+
* inorder는 left -> val -> right
5+
* 따라서 preorder의 val을 기준으로 inorder 배열을 왼, 오로 나누면 val의 왼쪽 트리, 오른쪽 트리 구조가 된다.
6+
*
7+
* node.val = preorder[i]
8+
* const leftAndRight = inorder.split(preorder[0])
9+
* node.left = leftAndRight[0]
10+
* node.right = leftAndRight[1]
11+
*
12+
* 구현이 안되어 코드 참고 ...
13+
* 직접 배열을 나누지 않고, val의 인덱스를 찾아 그 값을 기준으로 slice된 배열을 재귀적으로 buildTree에 넣는다.
14+
*
15+
*/
16+
17+
var buildTree = function (preorder, inorder) {
18+
if (preorder.length === 0 || inorder.length === 0) {
19+
return null;
20+
}
21+
const root = new TreeNode(preorder[0]);
22+
const rootIndex = inorder.indexOf(root.val);
23+
root.left = buildTree(
24+
preorder.slice(1, rootIndex + 1),
25+
inorder.slice(0, rootIndex)
26+
);
27+
root.right = buildTree(
28+
preorder.slice(rootIndex + 1, preorder.length),
29+
inorder.slice(rootIndex + 1, inorder.length)
30+
);
31+
return root;
32+
};

counting-bits/naringst.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* @param {number} n
3+
* @return {number[]}
4+
*/
5+
6+
/**
7+
* Runtime: 82ms, Memory: 57.03MB
8+
*
9+
* Time complexity: O(logN < N+1 ? N+1 : logN 단,보통의 경우 N+1)
10+
* Space complexity: O(N+1)
11+
*
12+
* Note: necessary to think of an alternative approach
13+
* **/
14+
15+
function decimalToBinary(decimal) {
16+
let binaryBitCount = 0;
17+
18+
while (decimal > 1) {
19+
binaryBitCount += decimal % 2 === 1 ? 1 : 0;
20+
decimal = Math.floor(decimal / 2);
21+
}
22+
binaryBitCount += decimal === 1 ? 1 : 0;
23+
24+
return binaryBitCount;
25+
}
26+
var countBits = function (n) {
27+
const answer = [];
28+
29+
for (let i = 0; i < n + 1; i++) {
30+
answer.push(decimalToBinary(i));
31+
}
32+
33+
return answer;
34+
};
35+
36+
/**
37+
* 인상 깊었던 풀이
38+
*
39+
* Runtime : 60ms
40+
*
41+
* 비트 연산의 속성과 dp를 활용해 푼 풀이
42+
*
43+
* [간단설명]
44+
* 4일때 100이고, 5일때 101, 6일때 110이다.
45+
* 이때 4를 2진수로 표현한 100이 가진 1의 개수를 활용해 5,6의 1의 개수를 찾는 것이다.
46+
* 100에서 1을 더한 101이나, 110은 100의 1의 개수인 1개에서 1을 더한 2개가 된다.
47+
* result[5 & 4] => 비트 연산을 통해 100과 101의 비트 앤드 연산을 해서 100이 되고, 이는 101의 가장 오른쪽 1을 제거한 값이 된다.
48+
* result[6 & 5] => 비트 연산을 통해 110과 101의 비트 앤드 연산을 해서 100이 되고, 이는 110의 가장 오른쪽 1을 제거한 값이 된다.
49+
* 이진수는 1씩 더하기 때문에 나보다 하나 큰 수와 앤드 연산을 하면 작은 수가 0으로 끝나면 큰 수는 1로 끝나고,
50+
* 작은 수가 1로 끝나면 큰 수는 0으로 끝나기 대문에 이런 속성을 갖는다.
51+
*
52+
*
53+
*/
54+
55+
var countBits = function (n) {
56+
let result = new Array(n + 1).fill(0);
57+
for (let i = 1; i <= n; i++) {
58+
result[i] = result[i & (i - 1)] + 1;
59+
}
60+
return result;
61+
};

decode-ways/naringst.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* 답안 참고 풀이
3+
* 💡 왜 못풀었을까?
4+
* 한 자리, 두 자리 경우 중 가능한 경우에 대해 조건 분기를 제대로 못했음.
5+
*/
6+
7+
var numDecodings = function (s) {
8+
const dp = Array(s.length + 1).fill(0);
9+
10+
// 예외 처리
11+
if (s[0] === "0") return 0;
12+
13+
dp[0] = 1;
14+
dp[1] = 1;
15+
16+
for (let i = 2; i <= s.length; i++) {
17+
// 1자리 값 , 2자리 값 파싱
18+
const oneDigit = +s.slice(i - 1, i);
19+
const twoDigits = +s.slice(i - 2, i);
20+
// 각 값이 가능한지 판단: 여기를 제대로 식을 세우지 못했음
21+
if (oneDigit > 0) dp[i] = dp[i - 1];
22+
if (twoDigits >= 10 && twoDigits <= 26) dp[i] += dp[i - 2];
23+
}
24+
return dp[s.length];
25+
};
26+
27+
/**
28+
* 처음 떠올렸던 방식인 dp로는 풀기 어려울 것 같아 풀이를 다시 생각해 봄.
29+
* 문자를 만드는 걸 숫자를 칸막이로 나누는 개념으로 생각. ex) 2/5/2/4, 2/52/4
30+
* 그러면 숫자와 숫자 사이 칸막이를 넣을지, 말지의 문제로 귀결
31+
* 2의 (s.length-1)제곱의 경우의 수 발생
32+
* 그 중 안되는 경우를 제외하면 답이 됨.
33+
* */
34+
35+
/**
36+
* @param {string} s
37+
* @return {number}
38+
*/
39+
40+
/**
41+
* NOTE 첫 풀이 -> 잘못된 풀이
42+
* dp를 사용해서 한자리씩, 그리고 다음 자릿수와 함께 두 자리 씩 확인해 경우의 수를 추가하면 된다고 생각했는데,
43+
* 2101과 같은 경우에 동작하지 않음.
44+
*
45+
* */
46+
47+
var numDecodings = function (s) {
48+
let dp = Array(s.length).fill(0);
49+
50+
// 시작 숫자가 0이면 불가능 -> 예외 처리
51+
if (s[0] !== "0") {
52+
dp[0] = 1;
53+
} else {
54+
return 0;
55+
}
56+
57+
for (let i = 0; i < s.length; i++) {
58+
if (i !== s.length - 1 && Number(s[i] + s[i + 1]) <= 26 && s[i] !== "0") {
59+
dp[i + 1] = dp[i] + 1;
60+
} else if (s[i + 1] === "0" || Number(s[i] + s[i + 1]) > 26) {
61+
dp[i + 1] = dp[i];
62+
}
63+
}
64+
return dp[s.length - 1];
65+
};

valid-anagram/naringst.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @param {string} s
3+
* @param {string} t
4+
* @return {boolean}
5+
*/
6+
7+
/**
8+
* Runtime: 68ms, Memory: 54.49MB
9+
* n = s.length > t.length ? s.length : t.length
10+
* Time complexity: O(n)
11+
* Space complexity: O(n)
12+
*
13+
* **/
14+
15+
function arrayToDict(arr) {
16+
const dict = {};
17+
for (let element of arr) {
18+
if (dict[element]) {
19+
dict[element] += 1;
20+
} else {
21+
dict[element] = 1;
22+
}
23+
}
24+
return dict;
25+
}
26+
27+
function isSameDict(dict1, dict2) {
28+
if (Object.keys(dict1).length !== Object.keys(dict2).length) {
29+
return false;
30+
}
31+
32+
for (const elem in dict1) {
33+
if (dict1[elem] !== dict2[elem]) {
34+
return false;
35+
}
36+
}
37+
return true;
38+
}
39+
40+
var isAnagram = function (s, t) {
41+
const sArr = [...s];
42+
const tArr = [...t];
43+
44+
const sDict = arrayToDict(sArr);
45+
const tDict = arrayToDict(tArr);
46+
47+
return isSameDict(sDict, tDict);
48+
};
49+
50+
/**
51+
* 같은 로직인데 53ms 걸린 다른 풀이
52+
*/
53+
54+
var isAnagram = function (s, t) {
55+
if (s.length !== t.length) {
56+
return false;
57+
}
58+
59+
const countA = {};
60+
const countB = {};
61+
62+
for (let i = 0; i < s.length; i++) {
63+
countA[s[i]] = 1 + (countA[s[i]] || 0);
64+
countB[t[i]] = 1 + (countB[t[i]] || 0);
65+
}
66+
67+
for (const key in countA) {
68+
if (countA[key] !== countB[key]) {
69+
return false;
70+
}
71+
}
72+
73+
return true;
74+
};

0 commit comments

Comments
 (0)