diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/Yjason-K.ts b/construct-binary-tree-from-preorder-and-inorder-traversal/Yjason-K.ts new file mode 100644 index 000000000..eaea76e76 --- /dev/null +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/Yjason-K.ts @@ -0,0 +1,58 @@ +// class TreeNode { +// val: number +// left: TreeNode | null +// right: TreeNode | null +// constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { +// this.val = (val===undefined ? 0 : val) +// this.left = (left===undefined ? null : left) +// this.right = (right===undefined ? null : right) +// } +// } + +/** + * 전위 순회(preorder)와 중위 순회(inorder) 배열을 이용해 이진 트리를 재구성하는 함수. + * + * @param {number[]} preorder - 트리의 전위 순회 배열 (루트 → 왼쪽 → 오른쪽 순서). + * @param {number[]} inorder - 트리의 중위 순회 배열 (왼쪽 → 루트 → 오른쪽 순서). + * @returns {TreeNode | null} - 재구성된 이진 트리의 루트 노드, 만약 트리가 비어있다면 null. + * + * 시간 복잡도: O(n) + * - 각 노드를 한 번씩 처리함. + * + * 공간 복잡도: O(n) + * - 재귀 호출 스택과 중위 순회 값-인덱스 해시맵 저장 공간 포함. + */ +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + // 중위 순회 배열의 각 값과 해당 인덱스를 저장 + const inorderIndexMap = new Map(); + inorder.forEach((value, index) => inorderIndexMap.set(value, index)); + + // 처리할 노드의 인덱스를 추적 + let preorderIndex = 0; + + // 재귀적으로 서브트리를 재구성하는 함수 + const helper = (left: number, right: number): TreeNode | null => { + // 현재 서브트리의 범위가 유효하지 않은 경우 + if (left > right) return null; + + // 전위 순회 배열에서 현재 노드 값을 가져와 루트로 사용하고 인덱스 증가 + const rootVal = preorder[preorderIndex++]; + // 새로운 TreeNode 객체 생성 + const root = new TreeNode(rootVal); + + // 해시맵에서 현재 루트 값의 인덱스를 찾아 중위 순회 배열 내에서의 위치 확인 + const rootIndex = inorderIndexMap.get(rootVal)!; + + // 중위 순회 배열에서 왼쪽 서브트리 범위 (left ~ rootIndex - 1)를 재귀 호출로 구성 + root.left = helper(left, rootIndex - 1); + // 중위 순회 배열에서 오른쪽 서브트리 범위 (rootIndex + 1 ~ right)를 재귀 호출로 구성 + root.right = helper(rootIndex + 1, right); + + // 현재 서브트리의 루트 노드를 반환 + return root; + }; + + // 전체 트리를 재구성하기 위해 중위 순회 배열의 전체 범위(0 ~ inorder.length - 1)를 헬퍼 함수에 전달 + return helper(0, inorder.length - 1); +} + diff --git a/rotate-image/Yjason-K.ts b/rotate-image/Yjason-K.ts new file mode 100644 index 000000000..5616b4f56 --- /dev/null +++ b/rotate-image/Yjason-K.ts @@ -0,0 +1,27 @@ +/** + * 주어진 정사각형 행렬을 90도 회전시키는 함수 + * + * @param {number[][]} matrix - 2차원 배열로 표현된 정사각형 행렬. + * + * 시간 복잡도: O(n^2) + * - n * n 행렬, 모든 요소를 한 번씩 방문. + * + * 공간 복잡도: O(1) + * - 추가적인 공간 사용 X + */ +function rotate(matrix: number[][]): void { + // 행렬의 크기 n (정사각형 행렬이므로 행과 열의 수는 동일) + const n = matrix.length; + + // 행렬의 대각선을 기준으로 좌표 (i, j)와 (j, i)의 요소를 교환. + for (let i = 0; i < n; i++) { + // j는 i부터 시작하여 중복 교환을 방지 + for (let j = i; j < n; j++) { + // 배열 구조 분해 할당을 이용하여 두 요소를 스왑 + [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]]; + } + // 각 행을 반전 + matrix[i].reverse(); + } +} + diff --git a/subtree-of-another-tree/Yjason-K.ts b/subtree-of-another-tree/Yjason-K.ts new file mode 100644 index 000000000..d6e65f438 --- /dev/null +++ b/subtree-of-another-tree/Yjason-K.ts @@ -0,0 +1,51 @@ +/** + * Definition for a binary tree node. + * class TreeNode { + * val: number + * left: TreeNode | null + * right: TreeNode | null + * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * } + */ + + +/** + * subTree가 root의 포함되는지 확인하는 함수 + * + * @param {TreeNode | null} root - 주어진 트리 + * @param {TreeNode | null} subRoot - 포함되는지 확인할 트리 + * @returns {boolean} - subRoot가 root에 포함되는지 여부 + * + * 시간 복잡도: O(n * m) + * - `isSameTree`는 두 트리가 동일한지 확인하는데 O(m) 시간이 걸림 (`m`: subRoot의 노드 수). + * - `isSubtree`는 `root`의 각 노드에서 `isSameTree`를 호출할 수 있음 (`n`: root의 노드 수). + * - 따라서 최악의 경우 O(n * m). + * + * 공간 복잡도: O(n) + * - 재귀 호출에 따른 call stack 사용 + */ +function isSubtree(root: TreeNode | null, subRoot: TreeNode | null): boolean { + if (!subRoot) return true; + if (!root) return false; + + const isSameTree = (treeA: TreeNode | null, treeB: TreeNode | null ): boolean => { + // 두 트리 모두 null 인 경우 true + if (!treeA && !treeB) return true; + // 하나만 null 인 경우 false + if (!treeA || !treeB) return false; + // val이 다른 경우 false + if (treeA.val !== treeB.val) return false; + return isSameTree(treeA.left, treeB.left) && isSameTree(treeA.right, treeB.right) + } + + // 현재 노드에서 subRoot가 시작되는 트리인지 확인 + if (isSameTree(root, subRoot)) return true; + + // 왼쪽, 오른쪽 하위 트에 subRoot가 포함되는지 확인 + return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot) +}; +