diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/seona926.js b/construct-binary-tree-from-preorder-and-inorder-traversal/seona926.js new file mode 100644 index 000000000..18716a000 --- /dev/null +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/seona926.js @@ -0,0 +1,66 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ +let buildTree = function (preorder, inorder) { + if (preorder.length === 0 || inorder.length === 0) { + return null; + } + + // 중위 순회의 값과 인덱스를 매핑하는 Map 생성 + const inorderIndexMap = new Map(); + inorder.forEach((value, index) => { + inorderIndexMap.set(value, index); + }); + + // 재귀적 트리 구성 함수 + function build(preStart, preEnd, inStart, inEnd) { + if (preStart > preEnd || inStart > inEnd) { + return null; + } + + // 전위순회 배열에서 루트 노드를 얻기 + const rootVal = preorder[preStart]; + const root = new TreeNode(rootVal); + + // 중위순회 배열에서 루트 노드의 인덱스 찾기 + const rootIndexInInorder = inorderIndexMap.get(rootVal); + + // 왼쪽 서브트리 크기 계산 + const leftSize = rootIndexInInorder - inStart; + + // 재귀적으로 왼쪽과 오른쪽 서브트리를 생성 + root.left = build( + preStart + 1, + preStart + leftSize, + inStart, + rootIndexInInorder - 1 + ); + root.right = build( + preStart + leftSize + 1, + preEnd, + rootIndexInInorder + 1, + inEnd + ); + + return root; + } + + return build(0, preorder.length - 1, 0, inorder.length - 1); +}; + +/* + 1. 시간복잡도: O(n) + - 트리의 모든 노드를 한 번씩 처리해야함 + 2. 공간복잡도: O(n) + - map 저장공간, 재귀호출 스택, 트리노드 저장공간 -> O(n) +*/ diff --git a/contains-duplicate/seona926.js b/contains-duplicate/seona926.js new file mode 100644 index 000000000..2721c3e59 --- /dev/null +++ b/contains-duplicate/seona926.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +let containsDuplicate = function (nums) { + let counts = {}; + + return nums.some((num) => { + if (counts[num] === undefined) { + counts[num] = 1; + return false; + } else { + return true; + } + }); +}; diff --git a/counting-bits/seona926.js b/counting-bits/seona926.js new file mode 100644 index 000000000..e2f6c18ee --- /dev/null +++ b/counting-bits/seona926.js @@ -0,0 +1,30 @@ +/** + * @param {number} n + * @return {number[]} + */ +let countBits = function (n) { + let result = []; + + for (let i = 0; i <= n; i++) { + let binaryString = i.toString(2); + + let count = 0; + for (let item of binaryString) { + if (item === "1") { + count++; + } + } + + result.push(count); + } + + return result; +}; + +/* + 1. 시간복잡도 : O(nlogn) + - 이진수 변환, 이진수 중 1의 개수를 세는 루프의 시간 복잡도: O(log i) + - 작업이 총 n번 일어남 + 2. 공간복잡도 : O(n) + - result 배열의 공간 복잡도가 O(n) +*/ diff --git a/decode-ways/seona926.js b/decode-ways/seona926.js new file mode 100644 index 000000000..57928d894 --- /dev/null +++ b/decode-ways/seona926.js @@ -0,0 +1,43 @@ +/** + * @param {string} s + * @return {number} + */ +let numDecodings = function (s) { + // 입력받은 숫자가 decode될 수 있는 가짓수를 리턴하기 + const n = s.length; + if (n === 0) return 0; + + // dp[i]는 s[0...i-1]까지의 부분 문자열이 해석될 수 있는 방법의 수를 저장 + const dp = new Array(n + 1).fill(0); + + // 빈 문자열은 하나의 방법으로 해석될 수 있음 (아무것도 선택하지 않는 방법) + dp[0] = 1; + + // 첫 글자가 '0'이 아니라면, 한 가지 방법으로 해석될 수 있음 + dp[1] = s[0] === "0" ? 0 : 1; + + for (let i = 2; i <= n; i++) { + const oneDigit = parseInt(s.slice(i - 1, i)); // 마지막 한 글자 + const twoDigits = parseInt(s.slice(i - 2, i)); // 마지막 두 글자 + + // 한 글자가 유효하다면, 그 글자를 포함하는 모든 방법을 추가 + if (oneDigit >= 1 && oneDigit <= 9) { + dp[i] += dp[i - 1]; + } + + // 두 글자가 유효하다면, 그 두 글자를 포함하는 모든 방법을 추가 + if (twoDigits >= 10 && twoDigits <= 26) { + dp[i] += dp[i - 2]; + } + } + + return dp[n]; +}; + +/* + 1. 시간복잡도 : O(n) + - 반복문의 시간복잡도 + 2. 공간복잡도 : O(n) + - dp 배열의 공간 복잡도 +*/ + diff --git a/number-of-1-bits/seona926.js b/number-of-1-bits/seona926.js new file mode 100644 index 000000000..a3def9ccf --- /dev/null +++ b/number-of-1-bits/seona926.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @return {number} + */ +let hammingWeight = function (n) { + let count = 0; + let sum = n; + + while (sum > 0) { + // n에서 가장 오른쪽 비트가 1인 경우 count 증가 + if (sum % 2 === 1) { + count++; + } + // sum을 2로 나누어서 다음 비트를 확인 + sum = Math.floor(sum / 2); + } + + return count; +}; diff --git a/valid-anagram/seona926.js b/valid-anagram/seona926.js new file mode 100644 index 000000000..01638dc15 --- /dev/null +++ b/valid-anagram/seona926.js @@ -0,0 +1,41 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +let isAnagram = function (s, t) { + let cntObj = {}; + + s.split("").forEach((item) => { + if (cntObj[item]) { + ++cntObj[item]; + } else { + cntObj[item] = 1; + } + }); + + for (let item of t) { + if (cntObj[item] === undefined || cntObj[item] < 1) { + return false; + } else { + --cntObj[item]; + } + } + + for (let count of Object.values(cntObj)) { + if (count > 0) { + return false; + } + } + + return true; +}; + +/* + 1. 시간복잡도 : O(n) + 각 반복문의 시간복잡도가 모두 O(n) + + 2. 공간복잡도 : O(n) + 주어진 문자열인 s와 t갯수만큼 공간을 차지함 +*/ +