diff --git a/course-schedule/uraflower.js b/course-schedule/uraflower.js new file mode 100644 index 000000000..67443b10d --- /dev/null +++ b/course-schedule/uraflower.js @@ -0,0 +1,45 @@ +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +const canFinish = function (numCourses, prerequisites) { + // 강의 간 관계 그래프 생성 + const relation = Array.from({ length: numCourses }).map(() => new Set()); + for (const [current, prev] of prerequisites) { + relation[current].add(prev); + } + + const visiting = new Set(); // 수강할 수 있는지 확인하기 위해 순회중인 강의 + const visited = new Set(); // 수강 가능한 강의 + + function dfs(current) { + if (visiting.has(current)) { + return false; + } + if (visited.has(current)) { + return true; + } + visiting.add(current); + + for (const prev of relation[current]) { + if (visiting[prev] || !dfs(prev)) { + return false; + } + } + + visiting.delete(current); + visited.add(current) + + return true; + } + + // 강의마다 순회 + for (let i = 0; i < numCourses; i++) { + if (!visited[i] && !dfs(i)) { + return false; + } + } + + return true; +}; diff --git a/invert-binary-tree/uraflower.js b/invert-binary-tree/uraflower.js new file mode 100644 index 000000000..03d6fb215 --- /dev/null +++ b/invert-binary-tree/uraflower.js @@ -0,0 +1,26 @@ +/** + * 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 {TreeNode} + */ +const invertTree = function (root) { + if (root !== null) { + invertTree(root.right); + invertTree(root.left); + [root.right, root.left] = [root.left, root.right]; + } + + return root; +}; + +// 시간복잡도: O(n) +// 공간복잡도: O(n) diff --git a/jump-game/uraflower.js b/jump-game/uraflower.js new file mode 100644 index 000000000..e363e80ae --- /dev/null +++ b/jump-game/uraflower.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const canJump = function(nums) { + // 마지막 인덱스에서 첫 인덱스로 거꾸로 돌면서 + // 필요한 점프 횟수를 변수에 저장 + // 만약 인덱스 i의 값이 필요한 점프 횟수를 충족한다면 초기화 + + let need = 1; + let answer = true; + + for (let i = nums.length - 2; i >= 0; i--) { + if (nums[i] >= need) { + need = 1; + answer = true; + } else { + need += 1; + answer = false; + } + } + + return answer; +}; + +// 시간복잡도: O(n) +// 공간복잡도: O(1) diff --git a/merge-k-sorted-lists/uraflower.js b/merge-k-sorted-lists/uraflower.js new file mode 100644 index 000000000..1512bcbde --- /dev/null +++ b/merge-k-sorted-lists/uraflower.js @@ -0,0 +1,45 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +const mergeKLists = function (lists) { + // 각 노드의 val 별 개수를 객체로 나타냄 + const counter = {}; + + for (let list of lists) { + let node = list; + while (node) { + counter[node.val] = (counter[node.val] || 0) + 1; + node = node.next; + } + } + + // 위에서 만든 객체를 오름차순으로 순회하면서 node와 list를 생성 + let head = new ListNode(); + let current = head; + const entries = Object.entries(counter).sort(([val1], [val2]) => Number(val1) - Number(val2)); // val 기준 오름차순 정렬 + + for (let i = 0; i < entries.length; i++) { + const [val, count] = entries[i]; + + for (let j = 0; j < count; j++) { + const node = new ListNode(Number(val)); + current.next = node; + current = current.next; + } + } + + return head.next; +}; + +// 시간복잡도: O(n * log n) (sort에서 n * log n, 순회와 리스트 구성에서는 n) +// 공간복잡도: O(n) + +// 최소힙을 통해 최적화를 할 수 있음 diff --git a/search-in-rotated-sorted-array/uraflower.js b/search-in-rotated-sorted-array/uraflower.js new file mode 100644 index 000000000..eb0f5aa95 --- /dev/null +++ b/search-in-rotated-sorted-array/uraflower.js @@ -0,0 +1,41 @@ +/** + * 주어진 배열에서 타겟의 인덱스를 찾아 반환하는 함수 + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const search = function (nums, target) { + let left = 0; + let right = nums.length; + let mid = Math.floor((left + right) / 2); + + while (left < right) { + mid = Math.floor((left + right) / 2); + + if (nums[mid] === target) break; + + // left부터 mid까지 잘 정렬되어 있는 경우 (=> rotate된 부분은 mid부터 right 사이에 있음) + if (nums[left] < nums[mid]) { + // 정렬된 left부터 mid 사이에 타겟이 있는 경우 + if (nums[left] <= target && target <= nums[mid]) { + right = mid; + } else { + left = mid + 1; + } + } + // mid부터 right까지 잘 정렬되어 있는 경우 (=> rotate된 부분은 left부터 mid 사이에 있음) + else { + // 정렬된 mid부터 right 사이에 타겟이 있는 경우 + if (nums[mid] <= target && target <= nums[right - 1]) { + left = mid; + } else { + right = mid; + } + } + } + + return nums[mid] === target ? mid : -1; +}; + +// O(log n) +// O(1)