-
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 09 #986
[Jeehay28] WEEK 09 #986
Changes from all commits
979a991
0201345
634c44e
de0fb83
5176fd8
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,49 @@ | ||
/** | ||
* @param {number[]} nums | ||
* @return {number} | ||
*/ | ||
|
||
// Binary Search | ||
// Time Complexity: O(log n) (Binary search halving the search space each step) | ||
// Space Complexity: O(1) (No extra space except for a few variables) | ||
var findMin = function (nums) { | ||
// Example Rotations: | ||
// nums = [0,1,2,4,5,6,7] | ||
// [4,5,6,7,0,1,2] -> Rotated 4 times | ||
// [0,1,2,4,5,6,7] -> 7 times rotated | ||
|
||
// Initial State: | ||
// [4, 5, 6, 7, 0, 1, 2] | ||
// ↑ ↑ | ||
// (left) (right) | ||
// | ||
// Find mid: | ||
// [4, 5, 6, 7, 0, 1, 2] | ||
// ↑ 🎯 ↑ | ||
// (left) (mid) (right) | ||
// | ||
// If nums[mid] > nums[right], move left to search in the right half: | ||
// [4, 5, 6, 7, 0, 1, 2] | ||
// ↑ ↑ | ||
// (left) (right) | ||
|
||
let left = 0; | ||
let right = nums.length - 1; | ||
|
||
while (left < right) { | ||
let mid = Math.floor((left + right) / 2); | ||
|
||
if (nums[mid] > nums[right]) { | ||
// Minimum must be in the right half | ||
// Need to update left to search in the right half | ||
left = mid + 1; | ||
} else { | ||
// Minimum is in the left half (including mid) | ||
// Need to update right to search in the left half | ||
right = mid; | ||
} | ||
} | ||
|
||
return nums[left]; | ||
}; | ||
|
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. LinkedList 의 특성을 정석적으로 활용하신것 같습니다! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
* Definition for singly-linked list. | ||
* function ListNode(val) { | ||
* this.val = val; | ||
* this.next = null; | ||
* } | ||
*/ | ||
|
||
/** | ||
* @param {ListNode} head | ||
* @return {boolean} | ||
*/ | ||
|
||
// Time Complexity: O(n) | ||
// Space Complexity: O(1) | ||
|
||
// - In the worst case, we might traverse the entire linked list, but because the fast pointer moves at twice the speed of the slow pointer, they will meet within O(N) steps if a cycle exists. | ||
// - If there is no cycle, the fast pointer reaches the end in O(N) steps. | ||
// - Only two pointers (slow and fast) are used, which require O(1) extra space. | ||
// - No additional data structures (like arrays or hash sets) are used. | ||
|
||
var hasCycle = function (head) { | ||
// If there is a cycle in the linked list, Floyd's Tortoise and Hare algorithm guarantees | ||
// that the fast and slow pointers will eventually meet. | ||
let fast = head; | ||
let slow = head; | ||
|
||
while (fast && fast.next) { | ||
slow = slow.next; // Move slow pointer one step. | ||
fast = fast.next.next; // Move fast pointer two steps. | ||
|
||
if (slow === fast) { | ||
return true; // Cycle detected. | ||
} | ||
} | ||
|
||
return false; | ||
}; | ||
|
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. 해당 문제는 DP 로 풀어야 해서 3중 for-loop를 사용하면 시간초과가 되죠! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/** | ||
* @param {number[]} nums | ||
* @return {number} | ||
*/ | ||
|
||
// ✅ DP approach | ||
// Time Complexity: O(n) | ||
// Space Complexity: O(1) | ||
var maxProduct = function (nums) { | ||
// Track the minimum and maximum product ending at the current position | ||
// Consider three possibilities for each element: | ||
// 1. Current number | ||
// 2. Previous min product * current number (to handle negative numbers) | ||
// 3. Previous max product * current number (to handle negative numbers) | ||
|
||
let maxProduct = nums[0]; | ||
let previousMinProduct = 1; | ||
let previousMaxProduct = 1; | ||
|
||
for (const current of nums) { | ||
const temp1 = previousMinProduct * current; | ||
const temp2 = previousMaxProduct * current; | ||
|
||
// Update min and max product | ||
previousMinProduct = Math.min(current, temp1, temp2); | ||
previousMaxProduct = Math.max(current, temp1, temp2); | ||
|
||
// Update maxProduct | ||
maxProduct = Math.max(maxProduct, previousMaxProduct); | ||
} | ||
|
||
return maxProduct; | ||
}; | ||
|
||
// 🤔 more efficient than the previous one, but there might be a further optimization | ||
// using dynamic programming approach to reduce the complexity to O(n) | ||
// Time Complexity: O(n^2) | ||
// Space Complexity: O(1) | ||
|
||
// var maxProduct = function (nums) { | ||
// let max = nums[0]; | ||
|
||
// for (let s = 0; s < nums.length; s++) { | ||
// let temp = 1; | ||
// for (let e = s; e < nums.length; e++) { | ||
// temp *= nums[e]; | ||
// max = Math.max(max, temp); | ||
// } | ||
// } | ||
// return max; | ||
// }; | ||
|
||
// 😱 Time Limit Exceeded! | ||
// Time Complexity: O(n^3) | ||
// Space Complexity: O(1) | ||
// var maxProduct = function (nums) { | ||
// let max = nums[0]; | ||
|
||
// for (let s = 0; s < nums.length; s++) { | ||
// for (let e = s; e < nums.length; e++) { | ||
// let temp = 1; | ||
|
||
// for (let i = s; i <= e; i++) { | ||
// temp *= nums[i]; | ||
// } | ||
|
||
// max = Math.max(max, temp); | ||
// } | ||
// } | ||
|
||
// return max; | ||
// }; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* @param {string} s | ||
* @param {string} t | ||
* @return {string} | ||
*/ | ||
|
||
// 🚀 sliding window + two pointer approach | ||
|
||
// 🕒 Time Complexity: O(n), where n is the length of s | ||
// The inner while loop shrinks the window from the left side but never exceeds the total number of characters in s | ||
|
||
// 🗂 Space Complexity: O(m) (or worst case O(n)), where n is the length of t | ||
|
||
var minWindow = function (s, t) { | ||
// early return for the critical edge case | ||
if (s.length < t.length) { | ||
return ""; | ||
} | ||
|
||
let windowCnt = new Map(); | ||
let charCnt = new Map(); | ||
let minStart = 0; | ||
let minEnd = s.length; // set this to an out-of-bounds value initially | ||
|
||
let formed = 0; | ||
let left = 0; | ||
|
||
// initialize charCount | ||
// 🔢 t = "ABC", charCount = { A: 1, B: 1, C: 1 } | ||
for (const ch of t) { | ||
charCnt.set(ch, (charCnt.get(ch) || 0) + 1); | ||
} | ||
|
||
// expand the windowCnt | ||
for (let right = 0; right < s.length; right++) { | ||
const char = s[right]; | ||
|
||
windowCnt.set(char, (windowCnt.get(char) || 0) + 1); | ||
|
||
if (charCnt.has(char) && charCnt.get(char) === windowCnt.get(char)) { | ||
formed += 1; | ||
} | ||
|
||
// shrink the window by moving the left pointer | ||
while (formed === charCnt.size) { | ||
if (right - left < minEnd - minStart) { | ||
minStart = left; | ||
minEnd = right; | ||
} | ||
|
||
const char = s[left]; | ||
windowCnt.set(char, windowCnt.get(char) - 1); | ||
|
||
if (charCnt.has(char) && windowCnt.get(char) < charCnt.get(char)) { | ||
formed -= 1; | ||
} | ||
left += 1; | ||
} | ||
} | ||
|
||
return minEnd === s.length ? "" : s.slice(minStart, minEnd + 1); | ||
}; | ||
|
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. 모든 변수와 함수들이 직관적으로 정리가 매우 잘 된것 같습니다. 엄청 교과서적으로 풀이 해 주신것 같아요 대단하십니다..! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/** | ||
* @param {number[][]} heights | ||
* @return {number[][]} | ||
*/ | ||
|
||
// ✅ Time Complexity: O(m * n) | ||
// ✅ Space Complexity: O(m * n) | ||
|
||
var pacificAtlantic = function (heights) { | ||
const m = heights.length; | ||
const n = heights[0].length; | ||
|
||
// ❌ Array(m).fill(Array(n).fill(false)) → Incorrect (all rows share the same array) | ||
const pacific = Array.from({ length: m }, () => Array(n).fill(false)); | ||
const atlantic = Array.from({ length: m }, () => Array(n).fill(false)); | ||
|
||
// four possible movement directions: down, up, right, left | ||
const directions = [ | ||
[1, 0], // ⬇️ | ||
[-1, 0], // ⬆️ | ||
[0, 1], // ➡️ | ||
[0, -1], // ⬅️ | ||
]; | ||
|
||
/** | ||
* Depth-First Search (DFS) to mark reachable cells | ||
* @param {number} row - current row index | ||
* @param {number} col - current column index | ||
* @param {boolean[][]} visited - visited cells | ||
* @param {number} prevHeight - previously visited cell's height | ||
*/ | ||
|
||
const dfs = (row, col, visited, prevHeight) => { | ||
// No search needed: | ||
// 1) Out of bounds | ||
// 2) already visited | ||
// 3) current height < previous height | ||
if ( | ||
row < 0 || | ||
row >= m || | ||
col < 0 || | ||
col >= n || | ||
visited[row][col] || | ||
heights[row][col] < prevHeight | ||
) { | ||
return; | ||
} | ||
|
||
// mark current cell as visited | ||
visited[row][col] = true; | ||
|
||
// visit all four possible directions | ||
for (const [dr, dc] of directions) { | ||
dfs(row + dr, col + dc, visited, heights[row][col]); | ||
} | ||
}; | ||
|
||
// start dfs from each border | ||
for (let i = 0; i < m; i++) { | ||
dfs(i, 0, pacific, heights[i][0]); // left border(Pacific ocean) | ||
dfs(i, n - 1, atlantic, heights[i][n - 1]); // right border(Atlantic ocean) | ||
} | ||
|
||
for (let j = 0; j < n; j++) { | ||
dfs(0, j, pacific, heights[0][j]); // top border(Pacific ocean) | ||
dfs(m - 1, j, atlantic, heights[m - 1][j]); // bottom border(Atlantic ocean) | ||
} | ||
|
||
let result = []; | ||
|
||
for (let r = 0; r < m; r++) { | ||
for (let c = 0; c < n; c++) { | ||
if (pacific[r][c] && atlantic[r][c]) { | ||
result.push([r, c]); | ||
} | ||
} | ||
} | ||
return result; | ||
}; | ||
|
||
// Example test | ||
const heights = [ | ||
[1, 2, 2, 3, 5], | ||
[3, 2, 3, 4, 4], | ||
[2, 4, 5, 3, 1], | ||
[6, 7, 1, 4, 5], | ||
[5, 1, 1, 2, 4], | ||
]; | ||
|
||
const expected = [ | ||
[0, 4], | ||
[1, 3], | ||
[1, 4], | ||
[2, 2], | ||
[3, 0], | ||
[3, 1], | ||
[4, 0], | ||
]; | ||
|
||
const output = pacificAtlantic(heights); | ||
|
||
if (JSON.stringify(output.sort()) === JSON.stringify(expected.sort())) { | ||
console.log("✅ Accepted\n"); | ||
} else { | ||
console.log("❌ Not Accepted\n"); | ||
} | ||
|
||
console.log("Input:", heights, "\n"); | ||
console.log("Output:", output, "\n"); | ||
console.log("Expected:", expected); | ||
|
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.
binary search 알고리즘을 잘 사용하신것 같아요 :)