diff --git a/alien-dictionary/soobing.ts b/alien-dictionary/soobing.ts new file mode 100644 index 000000000..841569ce9 --- /dev/null +++ b/alien-dictionary/soobing.ts @@ -0,0 +1,68 @@ +/** + * 문제 설명 + * - 주어진 단어들을 활용하여 알파벳 순서를 찾는 문제 + * + * 아이디어 + * 1) 위상정렬 (👀 다음에 다시풀어보기) - Kahn's Algorithm + * - 어렵다... + */ +function alienOrder(words: string[]): string { + const graph: Map> = new Map(); + const inDegree: Map = new Map(); // 간선의 갯수(첫 시작이 무엇인지 판단하기 위함) + + // 단어들에 나오는 모든 문자를 정리 및 초기화 + for (const word of words) { + for (const char of word) { + if (!graph.has(char)) { + graph.set(char, new Set()); + inDegree.set(char, 0); + } + } + } + + // 단어들을 비교해서 알파벳 간의 우선 순서(그래프의 간선) 추출 + for (let i = 0; i < words.length - 1; i++) { + const w1 = words[i]; + const w2 = words[i + 1]; + const minLen = Math.min(w1.length, w2.length); + + let foundDiff = false; + + for (let j = 0; j < minLen; j++) { + const c1 = w1[j]; + const c2 = w2[j]; + if (c1 !== c2) { + if (!graph.get(c1)!.has(c2)) { + graph.get(c1)!.add(c2); + inDegree.set(c2, inDegree.get(c2)! + 1); + } + foundDiff = true; + break; + } + } + + // 사전순이 아닌 경우 빈문자열 리턴(If the order is invalid, return an empty string.) + if (!foundDiff && w1.length > w2.length) return ""; + } + + // BFS 위상정렬 시작 + const queue: string[] = []; + for (const [char, degree] of inDegree.entries()) { + if (degree === 0) queue.push(char); + } + + const result: string[] = []; + while (queue.length > 0) { + const current = queue.shift()!; + result.push(current); + + for (const neighbor of graph.get(current)!) { + inDegree.set(neighbor, inDegree.get(neighbor)! - 1); + if (inDegree.get(neighbor) === 0) { + queue.push(neighbor); + } + } + } + + return result.length === inDegree.size ? result.join("") : ""; +} diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/soobing.ts b/construct-binary-tree-from-preorder-and-inorder-traversal/soobing.ts new file mode 100644 index 000000000..9583a6176 --- /dev/null +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/soobing.ts @@ -0,0 +1,43 @@ +/** + * 문제 설명 + * - preorder(전위순회), inorder(중위순회) 배열을 통해 이진트리를 복원한다 + * + * + * 아이디어 + * 1) preorder 배열의 요소는 루트 노드이다, 이를 기준으로 inorder 배열을 좌우로 나눈다. + * 2) 좌우로 나눈 inorder 배열의 길이를 통해 preorder 배열의 좌우 서브트리를 구한다. + * 3) 이를 재귀적으로 반복한다. + */ + +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; + } +} + +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + if (preorder.length === 0 || inorder.length === 0) return 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 rootValue = preorder[preorderIndex++]; + const root = new TreeNode(rootValue); + const index = inorderIndexMap.get(rootValue)!; + + root.left = helper(left, index - 1); + root.right = helper(index + 1, right); + + return root; + }; + + return helper(0, inorder.length - 1); +} diff --git a/longest-palindromic-substring/soobing.ts b/longest-palindromic-substring/soobing.ts new file mode 100644 index 000000000..15bcb3990 --- /dev/null +++ b/longest-palindromic-substring/soobing.ts @@ -0,0 +1,31 @@ +/** + * 문제 설명 + * - 주어진 문자열에서 가장긴 palindromic substring을 찾는 문제 + * + * 아이디어 + * 1) palindrom을 찾는 법(중심 확장법) + 홀수ver, 짝수ver 두 가지 경우를 모두 확인 + * - two pointer 기법을 이용하여 확장하면서 가장 긴 palindromic substring을 찾는다. + */ +function longestPalindrome(s: string): string { + let maxLength = 0; + let start = 0; + + const expand = (l: number, r: number) => { + while (l >= 0 && r < s.length && s[l] === s[r]) { + const currentLength = r - l + 1; + if (currentLength > maxLength) { + maxLength = currentLength; + start = l; + } + l--; + r++; + } + }; + + for (let i = 0; i < s.length; i++) { + expand(i, i); + expand(i, i + 1); + } + + return s.slice(start, start + maxLength); +} diff --git a/rotate-image/soobing.ts b/rotate-image/soobing.ts new file mode 100644 index 000000000..7ef7fdaf1 --- /dev/null +++ b/rotate-image/soobing.ts @@ -0,0 +1,25 @@ +/** + * 문제 설명 + * - 2차원 배열을 90도 in-place로 회전하기 + * + * 아이디어 + * 1) 대각선 이동 + 좌우 이동 + * + */ +/** + Do not return anything, modify matrix in-place instead. + */ +function rotate(matrix: number[][]): void { + const n = matrix.length; + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + const temp = matrix[i][j]; + matrix[i][j] = matrix[j][i]; + matrix[j][i] = temp; + } + } + + for (let i = 0; i < n; i++) { + matrix[i].reverse(); + } +} diff --git a/subtree-of-another-tree/soobing.ts b/subtree-of-another-tree/soobing.ts new file mode 100644 index 000000000..43d3eeeea --- /dev/null +++ b/subtree-of-another-tree/soobing.ts @@ -0,0 +1,33 @@ +/** + * 문제 설명 + * - 두 개의 이진트리 중, subTree가 존재하는지 확인하는 문제 + * + * 아이디어 + * 1) DFS + isSameTree 체크 + */ +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; + } +} + +function isSameTree(tree1: TreeNode | null, tree2: TreeNode | null) { + if ((tree1 && !tree2) || (!tree1 && tree2)) return false; + if (tree1 === null && tree2 === null) return true; + if (tree1?.val !== tree2?.val) return false; + return ( + isSameTree(tree1?.left ?? null, tree2?.left ?? null) && + isSameTree(tree1?.right ?? null, tree2?.right ?? null) + ); +} + +function isSubtree(root: TreeNode | null, subRoot: TreeNode | null): boolean { + if (!root) return false; + if (isSameTree(root, subRoot)) return true; + return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot); +}