Skip to content

Commit 6764df4

Browse files
authored
Merge pull request #986 from Jeehay28/main
[Jeehay28] WEEK 09
2 parents 3f1fab1 + 5176fd8 commit 6764df4

File tree

5 files changed

+336
-0
lines changed

5 files changed

+336
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @param {number[]} nums
3+
* @return {number}
4+
*/
5+
6+
// Binary Search
7+
// Time Complexity: O(log n) (Binary search halving the search space each step)
8+
// Space Complexity: O(1) (No extra space except for a few variables)
9+
var findMin = function (nums) {
10+
// Example Rotations:
11+
// nums = [0,1,2,4,5,6,7]
12+
// [4,5,6,7,0,1,2] -> Rotated 4 times
13+
// [0,1,2,4,5,6,7] -> 7 times rotated
14+
15+
// Initial State:
16+
// [4, 5, 6, 7, 0, 1, 2]
17+
// ↑ ↑
18+
// (left) (right)
19+
//
20+
// Find mid:
21+
// [4, 5, 6, 7, 0, 1, 2]
22+
// ↑ 🎯 ↑
23+
// (left) (mid) (right)
24+
//
25+
// If nums[mid] > nums[right], move left to search in the right half:
26+
// [4, 5, 6, 7, 0, 1, 2]
27+
// ↑ ↑
28+
// (left) (right)
29+
30+
let left = 0;
31+
let right = nums.length - 1;
32+
33+
while (left < right) {
34+
let mid = Math.floor((left + right) / 2);
35+
36+
if (nums[mid] > nums[right]) {
37+
// Minimum must be in the right half
38+
// Need to update left to search in the right half
39+
left = mid + 1;
40+
} else {
41+
// Minimum is in the left half (including mid)
42+
// Need to update right to search in the left half
43+
right = mid;
44+
}
45+
}
46+
47+
return nums[left];
48+
};
49+

linked-list-cycle/Jeehay28.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Definition for singly-linked list.
3+
* function ListNode(val) {
4+
* this.val = val;
5+
* this.next = null;
6+
* }
7+
*/
8+
9+
/**
10+
* @param {ListNode} head
11+
* @return {boolean}
12+
*/
13+
14+
// Time Complexity: O(n)
15+
// Space Complexity: O(1)
16+
17+
// - 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.
18+
// - If there is no cycle, the fast pointer reaches the end in O(N) steps.
19+
// - Only two pointers (slow and fast) are used, which require O(1) extra space.
20+
// - No additional data structures (like arrays or hash sets) are used.
21+
22+
var hasCycle = function (head) {
23+
// If there is a cycle in the linked list, Floyd's Tortoise and Hare algorithm guarantees
24+
// that the fast and slow pointers will eventually meet.
25+
let fast = head;
26+
let slow = head;
27+
28+
while (fast && fast.next) {
29+
slow = slow.next; // Move slow pointer one step.
30+
fast = fast.next.next; // Move fast pointer two steps.
31+
32+
if (slow === fast) {
33+
return true; // Cycle detected.
34+
}
35+
}
36+
37+
return false;
38+
};
39+

maximum-product-subarray/Jeehay28.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @param {number[]} nums
3+
* @return {number}
4+
*/
5+
6+
// ✅ DP approach
7+
// Time Complexity: O(n)
8+
// Space Complexity: O(1)
9+
var maxProduct = function (nums) {
10+
// Track the minimum and maximum product ending at the current position
11+
// Consider three possibilities for each element:
12+
// 1. Current number
13+
// 2. Previous min product * current number (to handle negative numbers)
14+
// 3. Previous max product * current number (to handle negative numbers)
15+
16+
let maxProduct = nums[0];
17+
let previousMinProduct = 1;
18+
let previousMaxProduct = 1;
19+
20+
for (const current of nums) {
21+
const temp1 = previousMinProduct * current;
22+
const temp2 = previousMaxProduct * current;
23+
24+
// Update min and max product
25+
previousMinProduct = Math.min(current, temp1, temp2);
26+
previousMaxProduct = Math.max(current, temp1, temp2);
27+
28+
// Update maxProduct
29+
maxProduct = Math.max(maxProduct, previousMaxProduct);
30+
}
31+
32+
return maxProduct;
33+
};
34+
35+
// 🤔 more efficient than the previous one, but there might be a further optimization
36+
// using dynamic programming approach to reduce the complexity to O(n)
37+
// Time Complexity: O(n^2)
38+
// Space Complexity: O(1)
39+
40+
// var maxProduct = function (nums) {
41+
// let max = nums[0];
42+
43+
// for (let s = 0; s < nums.length; s++) {
44+
// let temp = 1;
45+
// for (let e = s; e < nums.length; e++) {
46+
// temp *= nums[e];
47+
// max = Math.max(max, temp);
48+
// }
49+
// }
50+
// return max;
51+
// };
52+
53+
// 😱 Time Limit Exceeded!
54+
// Time Complexity: O(n^3)
55+
// Space Complexity: O(1)
56+
// var maxProduct = function (nums) {
57+
// let max = nums[0];
58+
59+
// for (let s = 0; s < nums.length; s++) {
60+
// for (let e = s; e < nums.length; e++) {
61+
// let temp = 1;
62+
63+
// for (let i = s; i <= e; i++) {
64+
// temp *= nums[i];
65+
// }
66+
67+
// max = Math.max(max, temp);
68+
// }
69+
// }
70+
71+
// return max;
72+
// };
73+
74+

minimum-window-substring/Jeehay28.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @param {string} s
3+
* @param {string} t
4+
* @return {string}
5+
*/
6+
7+
// 🚀 sliding window + two pointer approach
8+
9+
// 🕒 Time Complexity: O(n), where n is the length of s
10+
// The inner while loop shrinks the window from the left side but never exceeds the total number of characters in s
11+
12+
// 🗂 Space Complexity: O(m) (or worst case O(n)), where n is the length of t
13+
14+
var minWindow = function (s, t) {
15+
// early return for the critical edge case
16+
if (s.length < t.length) {
17+
return "";
18+
}
19+
20+
let windowCnt = new Map();
21+
let charCnt = new Map();
22+
let minStart = 0;
23+
let minEnd = s.length; // set this to an out-of-bounds value initially
24+
25+
let formed = 0;
26+
let left = 0;
27+
28+
// initialize charCount
29+
// 🔢 t = "ABC", charCount = { A: 1, B: 1, C: 1 }
30+
for (const ch of t) {
31+
charCnt.set(ch, (charCnt.get(ch) || 0) + 1);
32+
}
33+
34+
// expand the windowCnt
35+
for (let right = 0; right < s.length; right++) {
36+
const char = s[right];
37+
38+
windowCnt.set(char, (windowCnt.get(char) || 0) + 1);
39+
40+
if (charCnt.has(char) && charCnt.get(char) === windowCnt.get(char)) {
41+
formed += 1;
42+
}
43+
44+
// shrink the window by moving the left pointer
45+
while (formed === charCnt.size) {
46+
if (right - left < minEnd - minStart) {
47+
minStart = left;
48+
minEnd = right;
49+
}
50+
51+
const char = s[left];
52+
windowCnt.set(char, windowCnt.get(char) - 1);
53+
54+
if (charCnt.has(char) && windowCnt.get(char) < charCnt.get(char)) {
55+
formed -= 1;
56+
}
57+
left += 1;
58+
}
59+
}
60+
61+
return minEnd === s.length ? "" : s.slice(minStart, minEnd + 1);
62+
};
63+
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* @param {number[][]} heights
3+
* @return {number[][]}
4+
*/
5+
6+
// ✅ Time Complexity: O(m * n)
7+
// ✅ Space Complexity: O(m * n)
8+
9+
var pacificAtlantic = function (heights) {
10+
const m = heights.length;
11+
const n = heights[0].length;
12+
13+
// ❌ Array(m).fill(Array(n).fill(false)) → Incorrect (all rows share the same array)
14+
const pacific = Array.from({ length: m }, () => Array(n).fill(false));
15+
const atlantic = Array.from({ length: m }, () => Array(n).fill(false));
16+
17+
// four possible movement directions: down, up, right, left
18+
const directions = [
19+
[1, 0], // ⬇️
20+
[-1, 0], // ⬆️
21+
[0, 1], // ➡️
22+
[0, -1], // ⬅️
23+
];
24+
25+
/**
26+
* Depth-First Search (DFS) to mark reachable cells
27+
* @param {number} row - current row index
28+
* @param {number} col - current column index
29+
* @param {boolean[][]} visited - visited cells
30+
* @param {number} prevHeight - previously visited cell's height
31+
*/
32+
33+
const dfs = (row, col, visited, prevHeight) => {
34+
// No search needed:
35+
// 1) Out of bounds
36+
// 2) already visited
37+
// 3) current height < previous height
38+
if (
39+
row < 0 ||
40+
row >= m ||
41+
col < 0 ||
42+
col >= n ||
43+
visited[row][col] ||
44+
heights[row][col] < prevHeight
45+
) {
46+
return;
47+
}
48+
49+
// mark current cell as visited
50+
visited[row][col] = true;
51+
52+
// visit all four possible directions
53+
for (const [dr, dc] of directions) {
54+
dfs(row + dr, col + dc, visited, heights[row][col]);
55+
}
56+
};
57+
58+
// start dfs from each border
59+
for (let i = 0; i < m; i++) {
60+
dfs(i, 0, pacific, heights[i][0]); // left border(Pacific ocean)
61+
dfs(i, n - 1, atlantic, heights[i][n - 1]); // right border(Atlantic ocean)
62+
}
63+
64+
for (let j = 0; j < n; j++) {
65+
dfs(0, j, pacific, heights[0][j]); // top border(Pacific ocean)
66+
dfs(m - 1, j, atlantic, heights[m - 1][j]); // bottom border(Atlantic ocean)
67+
}
68+
69+
let result = [];
70+
71+
for (let r = 0; r < m; r++) {
72+
for (let c = 0; c < n; c++) {
73+
if (pacific[r][c] && atlantic[r][c]) {
74+
result.push([r, c]);
75+
}
76+
}
77+
}
78+
return result;
79+
};
80+
81+
// Example test
82+
const heights = [
83+
[1, 2, 2, 3, 5],
84+
[3, 2, 3, 4, 4],
85+
[2, 4, 5, 3, 1],
86+
[6, 7, 1, 4, 5],
87+
[5, 1, 1, 2, 4],
88+
];
89+
90+
const expected = [
91+
[0, 4],
92+
[1, 3],
93+
[1, 4],
94+
[2, 2],
95+
[3, 0],
96+
[3, 1],
97+
[4, 0],
98+
];
99+
100+
const output = pacificAtlantic(heights);
101+
102+
if (JSON.stringify(output.sort()) === JSON.stringify(expected.sort())) {
103+
console.log("✅ Accepted\n");
104+
} else {
105+
console.log("❌ Not Accepted\n");
106+
}
107+
108+
console.log("Input:", heights, "\n");
109+
console.log("Output:", output, "\n");
110+
console.log("Expected:", expected);
111+

0 commit comments

Comments
 (0)