diff --git a/binary-tree-level-order-traversal/uraflower.js b/binary-tree-level-order-traversal/uraflower.js new file mode 100644 index 000000000..cc94c1e62 --- /dev/null +++ b/binary-tree-level-order-traversal/uraflower.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 {TreeNode} root + * @return {number[][]} + */ +const levelOrder = function(root) { + if (!root) return []; + + const queue = [[root]]; + const result = []; + + while (queue.length) { + const curNodes = queue.shift(); + const newNodes = []; // 나중에 queue에 넣을 배열로 child node들이 들어감 + const newResult = []; // 나중에 result에 넣을 배열로 node.val이 들어감 + + curNodes.forEach((node) => { + newResult.push(node.val); + if (node.left) newNodes.push(node.left); + if (node.right) newNodes.push(node.right); + }); + + if (newNodes.length) queue.push(newNodes); + result.push(newResult) + } + + return result; +}; + +// 시간복잡도: O(n) +// 공간복잡도: O(n) + +/* +위 풀이는 배열을 4개 사용하고 있음 +아래 풀이는 배열을 줄인 방식 +*/ +const levelOrder = function(root) { + if (!root) return []; + + const queue = [root]; + const result = []; + + while (queue.length) { + const level = []; + + // queue에 있는 노드 다 꺼내기 + for (let i = 0; i < queue.length; i++) { + const node = queue.shift(); + level.push(node.val); + + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + + result.push(level); + } + + return result; +}; diff --git a/counting-bits/uraflower.js b/counting-bits/uraflower.js new file mode 100644 index 000000000..3e5b7bb95 --- /dev/null +++ b/counting-bits/uraflower.js @@ -0,0 +1,45 @@ +/** + * 두 번째 풀이 + * 시간복잡도: O(n) + * 공간복잡도: O(n) + * @param {number} n + * @return {number[]} + */ +const countBits = function (n) { + const arr = [0]; + + for (let i = 1; i < n + 1; i++) { + arr[i] = arr[i >> 1] + (i & 1); + // i >> 1: 최하위 비트를 제외한 값. 이걸 이용해서 이전 인덱스 사용(dp) + // i // 2 (2로 나눈 몫)와 같음. + // i & 1: 최하위 비트 (1 또는 0) + } + + return arr; +}; + +/** + * 첫 번째 풀이 + * 시간복잡도: O(n * log n) + * 공간복잡도: O(n) + * @param {number} n + * @return {number[]} + */ +const countBits = function (n) { + const arr = []; + + for (let i = 0; i < n + 1; i++) { + const bin = i.toString(2); // O(log n) + + let num = 0; + + // O(log n) + for (let char of bin) { + if (char === '1') num++; + } + + arr.push(num); + } + + return arr; +}; diff --git a/house-robber-ii/uraflower.js b/house-robber-ii/uraflower.js new file mode 100644 index 000000000..0a33374a9 --- /dev/null +++ b/house-robber-ii/uraflower.js @@ -0,0 +1,25 @@ +// 최대 금액은 ... +// nums[0]을 터는 경우: rob(nums[2] ~ nums[last - 1]) + nums[0] +// nums[0]을 안 터는 경우: rob(nums[1] ~ nums[last]) +// 따라서 nums[0]을 털지 말지 여부를 기준으로 나누어 계산 + +/** + * @param {number[]} nums + * @return {number} + */ +const rob = function (nums) { + if (nums.length === 1) return nums[0]; + + const dp1 = [nums[0]]; // 첫 집을 터는 경우 최대 금액 + const dp2 = [0]; // 첫 집을 안 터는 경우 최대 금액 + + for (let i = 1; i < nums.length; i++) { + dp1[i] = Math.max(dp1[i - 1], (dp1[i - 2] || 0) + nums[i]); + dp2[i] = Math.max(dp2[i - 1], (dp2[i - 2] || 0) + nums[i]); + } + + return Math.max(dp1[dp1.length - 2], dp2[dp2.length - 1]); +} + +// 시간복잡도: O(n) +// 공간복잡도: O(n) diff --git a/meeting-rooms-ii/uraflower.js b/meeting-rooms-ii/uraflower.js new file mode 100644 index 000000000..220426f08 --- /dev/null +++ b/meeting-rooms-ii/uraflower.js @@ -0,0 +1,24 @@ +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + const starts = intervals.map(i => i[0]).sort((a, b) => a - b); + const ends = intervals.map(i => i[1]).sort((a, b) => a - b); + + let rooms = 0; + let endIdx = 0; + + for (let i = 0; i < starts.length; i++) { + if (starts[i] < ends[endIdx]) { + rooms++; // 새로운 방이 필요 + } else { + endIdx++; // 기존 방 재사용 가능 + } + } + + return rooms; +}; + +// 시간복잡도: O(n * log n) (정렬) +// 공간복잡도: O(n) diff --git a/word-search-ii/uraflower.js b/word-search-ii/uraflower.js new file mode 100644 index 000000000..b5ff9f243 --- /dev/null +++ b/word-search-ii/uraflower.js @@ -0,0 +1,77 @@ +// 모든 word에 대해 +// board를 순회하면서 +// word의 첫 글자가 board의 현 위치 문자와 같다면 dfs +// 이렇게 풀 경우 O(W * m * n * 4^L)만큼 시간이 걸림 (W: words.length, L: word.length) + +// 그래서 모든 word를 트라이로 저장하고 +// board를 한 번만 순회하는 방법을 사용 + +const buildTrie = (words) => { + const root = {}; + + for (const word of words) { + let node = root; + for (const char of word) { + if (!node[char]) node[char] = {}; + node = node[char]; + } + node.word = word; + } + + return root; +} + +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +const findWords = function (board, words) { + const m = board.length; + const n = board[0].length; + const trie = buildTrie(words); + const result = []; + + const dr = [0, 0, 1, -1]; + const dc = [1, -1, 0, 0]; + const visited = Array.from({ length: m }).map(() => Array.from({ length: n }).fill(false)); + + const dfs = (r, c, node, path) => { + const char = board[r][c]; + const nextNode = node[char]; + if (!nextNode) return; + + if (nextNode.word) { + result.push(nextNode.word); + nextNode.word = null; + } + + visited[r][c] = true; + + for (let i = 0; i < 4; i++) { + const nr = r + dr[i]; + const nc = c + dc[i]; + + if (0 <= nr && nr < m && 0 <= nc && nc < n && !visited[nr][nc]) { + dfs(nr, nc, nextNode, path + board[nr][nc]); + } + } + + visited[r][c] = false; + } + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + dfs(i, j, trie, ''); + } + } + + return result; +}; + +// 시간복잡도: O(m * n * 4^L) (L: word.length) +// 공간복잡도: O(W * L + m * n) +// - trie: O(W * L) (W: words.length) +// - vistied: O(m * n) +// - 재귀스택: O(L) +// - result: O(K * L) (K: 찾은 단어 수)