-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Jeehay28] WEEK 10 #1010
[Jeehay28] WEEK 10 #1010
Changes from all commits
1665715
9b3c728
be15f0d
e7e1506
62212e2
203ebfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/** | ||
* @param {number} numCourses | ||
* @param {number[][]} prerequisites | ||
* @return {boolean} | ||
*/ | ||
|
||
// ✅ Graph DFS (Depth-First Search) approach | ||
// Time Complexity: O(V + E), where V is the number of courses (numCourses) and E is the number of prerequisites (edges). | ||
// Space Complexity: O(V + E), where V is the number of courses and E is the number of prerequisites. | ||
|
||
var canFinish = function (numCourses, prerequisites) { | ||
// prerequisites = [ | ||
// [1, 0], // Course 1 depends on Course 0 | ||
// [2, 1], // Course 2 depends on Course 1 | ||
// [3, 1], // Course 3 depends on Course 1 | ||
// [3, 2] // Course 3 depends on Course 2 | ||
// ]; | ||
|
||
// graph = { | ||
// 0: [1], // Course 0 is a prerequisite for Course 1 | ||
// 1: [2, 3], // Course 1 is a prerequisite for Courses 2 and 3 | ||
// 2: [3], // Course 2 is a prerequisite for Course 3 | ||
// 3: [] // Course 3 has no prerequisites | ||
// }; | ||
|
||
// Build the graph | ||
const graph = {}; | ||
|
||
// for(let i=0; i<numCourses; i++) { | ||
// graph[i] = [] | ||
// } | ||
|
||
// Fill in the graph with prerequisites | ||
for (const [course, prereq] of prerequisites) { | ||
if (!graph[prereq]) { | ||
graph[prereq] = []; | ||
} | ||
graph[prereq].push(course); | ||
} | ||
|
||
const visited = new Array(numCourses).fill(0); | ||
|
||
const dfs = (course) => { | ||
if (visited[course] === 1) return false; // cycle detected! | ||
if (visited[course] === 2) return true; // already visited | ||
|
||
visited[course] = 1; | ||
|
||
// // Visit all the courses that depend on the current course | ||
for (const nextCourse of graph[course] || []) { | ||
if (!dfs(nextCourse)) { | ||
return false; // cycle detected! | ||
} | ||
} | ||
|
||
visited[course] = 2; // fully visited and return true | ||
return true; | ||
}; | ||
|
||
// Check for each course whether it's possible to finish it | ||
for (let i = 0; i < numCourses; i++) { | ||
if (!dfs(i)) { | ||
return false; // cycle detected! | ||
} | ||
} | ||
|
||
return true; // no cycles | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/** | ||
* 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} | ||
*/ | ||
|
||
// ✔️ Recursive Approach | ||
// Time Complexity: O(N), N = Total number of nodes (each node is processed once) | ||
// Space Complexity: O(H), H = Height of the tree (due to recursion stack depth) | ||
|
||
var invertTree = function (root) { | ||
if (!root) return null; | ||
|
||
[root.left, root.right] = [root.right, root.left]; | ||
|
||
invertTree(root.left); | ||
invertTree(root.right); | ||
|
||
return root; | ||
}; | ||
|
||
/** | ||
* 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} | ||
*/ | ||
|
||
// ✔️ Stack → DFS approach | ||
// Time Complexity: O(N), N = Total number of nodes (each node is processed once) | ||
// Space Complexity: O(H), H = Height of the tree (due to recursion stack depth) | ||
|
||
// var invertTree = function (root) { | ||
// let stack = [root]; | ||
|
||
// while (stack.length > 0) { | ||
// const node = stack.pop(); | ||
// if (!node) continue; | ||
|
||
// [node.left, node.right] = [node.right, node.left]; | ||
// stack.push(node.left); | ||
// stack.push(node.right); | ||
// } | ||
// return root; | ||
// }; | ||
|
||
|
||
/** | ||
* 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} | ||
*/ | ||
|
||
// ✔️ Queue → BFS | ||
// Time Complexity: O(N), N = Total number of nodes (each node is processed once) | ||
// Space Complexity: O(W), W = Maximum width of the tree | ||
// var invertTree = function (root) { | ||
// let queue = [root]; | ||
|
||
// while (queue.length > 0) { | ||
// const node = queue.shift(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
실제 코딩 테스트에서도 JS에는 Queue나 Deque이 없기 때문에 우선은 있다고 치고 작성한 뒤 '이 부분은 추가 구현으로 보완 가능하다'고 언급하는 방식으로도 진행한다고 하더라구요. 이전에 달레님의 피드백 중에 비슷한 내용이 있었어서 공유드려요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아, 그렇군요. 공유 감사합니다. 👍 |
||
// if (!node) continue; | ||
|
||
// [node.left, node.right] = [node.right, node.left]; | ||
// queue.push(node.left); | ||
// queue.push(node.right); | ||
// } | ||
// return root; | ||
// }; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// 🚀 Greedy approach: much more efficient than the recursive approach | ||
// Time Complexity: O(n) | ||
// Space Complexity: O(1), No extra memory used | ||
|
||
/** | ||
* @param {number[]} nums | ||
* @return {boolean} | ||
*/ | ||
var canJump = function (nums) { | ||
// ➡️ The farthest position you can reach from any of the previous indices you have already visited. | ||
let farthest = 0; | ||
|
||
for (let i = 0; i < nums.length; i++) { | ||
// You cannot reach this position even with your farthest jump value. | ||
if (i > farthest) return false; | ||
|
||
// Compare current maximum jump with the previous maximum. | ||
farthest = Math.max(farthest, nums[i] + i); | ||
|
||
// Check if you can reach the last index with the current farthest jump. | ||
if (farthest >= nums.length - 1) return true; | ||
} | ||
return false; | ||
}; | ||
|
||
|
||
/** | ||
* @param {number[]} nums | ||
* @return {boolean} | ||
*/ | ||
|
||
// Time Complexity: O(n) | ||
// Space Complexity: O(n) | ||
var canJump = function (nums) { | ||
let lastIndex = nums.length - 1; | ||
|
||
// Initialize memoization array to track visited indices | ||
let memo = new Array(nums.length).fill(undefined); | ||
|
||
const dfs = (i) => { | ||
// Base case: if we've reached or surpassed the last index, return true | ||
if (i >= lastIndex) return true; | ||
|
||
// If the current index has already been visited, return the stored result | ||
if (memo[i] !== undefined) return memo[i]; | ||
|
||
// Calculate the farthest position that can be reached from the current index | ||
let maxJump = Math.min(nums[i] + i, lastIndex); | ||
|
||
for (let j = i + 1; j <= maxJump; j++) { | ||
if (dfs(j)) { | ||
memo[i] = true; | ||
return true; | ||
} | ||
} | ||
|
||
memo[i] = false; | ||
return false; | ||
}; | ||
|
||
return dfs(0); | ||
}; | ||
|
||
|
||
// 🌀 recursive approach | ||
// ⚠️ Time Complexity: O(2^n) - Exponential due to recursive branching without memoization | ||
// 🔵 Space Complexity: O(n) - Recursive call stack depth | ||
|
||
/** | ||
* Check if you can jump to the last index from the first index. | ||
* @param {number[]} nums - Array where nums[i] is the max jump length from position i. | ||
* @return {boolean} True if you can reach the last index, otherwise false. | ||
*/ | ||
|
||
// var canJump = function (nums) { | ||
// const dfs = (start) => { | ||
// // Base Case: Reached the last index | ||
// if (start === nums.length - 1) { | ||
// return true; | ||
// } | ||
|
||
// // Recursive Case: Try all possible jumps | ||
// for (let i = 1; i <= nums[start]; i++) { | ||
// // Example with nums = [2, 3, 1, 1, 4]: | ||
// // start = 1, nums[1] = 3 (can jump 1, 2, or 3 steps) | ||
// // Possible calls: | ||
// // dfs(1 + 1) -> check from index 2 | ||
// // dfs(1 + 2) -> check from index 3 | ||
// // dfs(1 + 3) -> reached the last index (success) | ||
|
||
// if (dfs(start + i)) { | ||
// return true; | ||
// } | ||
// } | ||
|
||
// return false; // cannot reach the last index | ||
// }; | ||
|
||
// return dfs(0); | ||
// }; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Brute Force (Array Sorting) - Good for smaller cases | ||
// 🕒 Time Complexity: O(N log N), where N is the total number of nodes | ||
// 🗂️ Space Complexity: O(N) | ||
|
||
/** | ||
* 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} | ||
*/ | ||
var mergeKLists = function (lists) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 와우,, 주석이 실시간으로 진화하고 있는것같아요 🫢 |
||
const nums = []; | ||
|
||
// ┌──────────────────────────────────────────────────────────────────┐ | ||
// │ Step 1: Extract values from all linked lists │ | ||
// │ We traverse each linked list and push node values into 'nums'. │ | ||
// │ This flattens the K lists into a single array. │ | ||
// └──────────────────────────────────────────────────────────────────┘ | ||
for (let list of lists) { | ||
while (list) { | ||
nums.push(list.val); | ||
list = list.next; | ||
} | ||
} | ||
|
||
// ┌──────────────────────────────────────────────────────────────────┐ | ||
// │ Step 2: Sort the values │ | ||
// │ JavaScript's default sort is lexicographical, so we use a custom │ | ||
// │ comparator to sort numbers correctly in ascending order. │ | ||
// └──────────────────────────────────────────────────────────────────┘ | ||
nums.sort((a, b) => a - b); | ||
|
||
// ┌──────────────────────────────────────────────────────────────────┐ | ||
// │ Step 3: Create a new sorted linked list │ | ||
// │ Initialize a dummy node, then iterate through the sorted array. │ | ||
// │ For each value, create a new ListNode and append it to the list. │ | ||
// └──────────────────────────────────────────────────────────────────┘ | ||
let dummy = new ListNode(-1); | ||
let current = dummy; | ||
|
||
for (num of nums) { | ||
current.next = new ListNode(num); | ||
current = current.next; | ||
} | ||
|
||
// ┌──────────────────────────────────────────────────────────────────┐ | ||
// │ Step 4: Return the merged list │ | ||
// │ We return dummy.next since dummy is a placeholder. │ | ||
// └──────────────────────────────────────────────────────────────────┘ | ||
return dummy.next; | ||
}; | ||
|
||
/** | ||
* ┌──────────────────────────────────────────────────────────────────┐ | ||
* │ Time & Space Complexity │ | ||
* ├──────────────────────────────────────────────────────────────────┤ | ||
* │ Operation │ Complexity │ | ||
* ├──────────────────────────────────────────────────────────────────┤ | ||
* │ Extracting values │ O(N) - N is the total number of nodes │ | ||
* │ Sorting values │ O(N log N) - JavaScript's sort uses Timsort │ | ||
* │ Building linked list │ O(N) - Iterates through sorted array │ | ||
* ├──────────────────────────────────────────────────────────────────┤ | ||
* │ Overall Time Complexity │ O(N log N) │ | ||
* ├──────────────────────────────────────────────────────────────────┤ | ||
* │ Space Complexity │ O(N) - Storing all node values in array │ | ||
* └──────────────────────────────────────────────────────────────────┘ | ||
*/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/** | ||
* @param {number[]} nums | ||
* @param {number} target | ||
* @return {number} | ||
*/ | ||
|
||
// ✅ Iterative Binary Search for Rotated Sorted Array | ||
// Time Complexity: O(log N) | ||
// Space Complexity: O(1) | ||
var search = function (nums, target) { | ||
let left = 0; | ||
let right = nums.length - 1; | ||
|
||
while (left <= right) { | ||
let pointer = Math.floor((left + right) / 2); | ||
|
||
if (nums[pointer] === target) { | ||
return pointer; | ||
} | ||
|
||
// Check if the left half is sorted | ||
if (nums[left] <= nums[pointer]) { | ||
// Target is in the sorted left half | ||
if (nums[left] <= target && target < nums[pointer]) { | ||
right = pointer - 1; | ||
} else { | ||
// Target is not in the left half, so search in the right half | ||
left = pointer + 1; | ||
} | ||
} else { | ||
// The right half must be sorted | ||
|
||
// Target is in the sorted right half | ||
if (nums[pointer] < target && target <= nums[right]) { | ||
left = pointer + 1; | ||
} else { | ||
// Target is not in the right half, so search in the left half | ||
right = pointer - 1; | ||
} | ||
} | ||
} | ||
|
||
return -1; | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0, 1, 2 를 상수로 뽑아 내면 어떨까 싶어요. 깔끔한 풀이네요!