Skip to content
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

[강희찬] WEEK 9 Solution #519

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions find-minimum-in-rotated-sorted-array/HC-kang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* https://leetcode.com/problems/find-minimum-in-rotated-sorted-array
* T.C. O(log n)
* S.C. O(1)
*/
function findMin(nums: number[]): number {
let left = 0;
let right = nums.length - 1;
let mid = (left + right) >> 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mid 값 구하는데 (left + right) / 2만 생각했는데, 이렇게 하면 비트 연산으로 더 효율적이겠네요..! 하나 배웠습니다 :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// 2 보다 우아하네요. mid에 대해 첨언드리자면 정수형 변수의 크기가 가변적이지 않은 언어의 경우 left + (right - left) // 2 같은 방식으로 mid를 계산해서 overflow를 방지하는 방식도 있습니다.


while (left < right) {
if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
mid = (left + right) >> 1;
}
return nums[left];
}
42 changes: 42 additions & 0 deletions linked-list-cycle/HC-kang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
class ListNode {
val: number;
next: ListNode | null;
constructor(val?: number, next?: ListNode | null) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
}

/**
* https://leetcode.com/problems/linked-list-cycle
* T.C. O(n)
* S.C. O(n)
*/
function hasCycle(head: ListNode | null): boolean {
const SET = new Set<ListNode>();
while (head) {
if (SET.has(head)) return true;
SET.add(head);
head = head.next
}
return false;
Comment on lines +15 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast와 slow만 사용하는걸 생각헀는데, 창의적인 답인것 같아요!

};

/**
* T.C. O(n)
* S.C. O(1)
*/
function hasCycle(head: ListNode | null): boolean {
let fast = head;
let slow = head;

while (fast && fast.next) {
fast = fast.next.next;
slow = slow!.next;

if (fast === slow) {
return true;
}
}
return false;
};
93 changes: 93 additions & 0 deletions maximum-subarray/HC-kang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* https://leetcode.com/problems/maximum-subarray
* Kadane's Algorithm
* T.C. O(n)
* S.C. O(1)
*/
function maxSubArray(nums: number[]): number {
let maxSum = nums[0];

for (let i = 1; i < nums.length; i++) {
nums[i] = Math.max(nums[i], nums[i] + nums[i - 1]);
maxSum = Math.max(maxSum, nums[i]);
}

return maxSum;
Comment on lines +7 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

성능만 따지자면 세개의 답중 가장 느리고 공간 효율도 안좋지만, 가독성 측면에서 봤을때는 너무 좋은것 같아요. 개인적으로 이 코드가 제일 마음에 들어요 :)

}

/**
* Divide and Conquer version
* T.C. O(n log n)
* S.C. O(log n) - call stack
*/
function maxSubArray(nums: number[]): number {
function maxSubArrayHelper(
nums: number[],
left: number,
right: number
): number {
if (left === right) return nums[left];

const mid = (left + right) >> 1;
const leftMax = maxSubArrayHelper(nums, left, mid);
const rightMax = maxSubArrayHelper(nums, mid + 1, right);
let leftSum = -Infinity;
let rightSum = -Infinity;
let sum = 0;

for (let i = mid; i >= left; i--) {
sum += nums[i];
leftSum = Math.max(leftSum, sum);
}

sum = 0;
for (let i = mid + 1; i <= right; i++) {
sum += nums[i];
rightSum = Math.max(rightSum, sum);
}

return Math.max(leftMax, rightMax, leftSum + rightSum);
}

return maxSubArrayHelper(nums, 0, nums.length - 1);
}

/**
* Iterative version
* T.C. O(n log n)
* S.C. O(log n) - call stack
*/
function maxSubArray(nums: number[]): number {
const stack = [[0, nums.length - 1]];
let maxSum = nums[0];

while (stack.length) {
const [left, right] = stack.pop()!;
if (left === right) {
maxSum = Math.max(maxSum, nums[left]);
continue;
}

const mid = (left + right) >> 1;
stack.push([left, mid], [mid + 1, right]);

let leftSum = -Infinity;
let rightSum = -Infinity;
let sum = 0;

for (let i = mid; i >= left; i--) {
sum += nums[i];
leftSum = Math.max(leftSum, sum);
}

sum = 0;
for (let i = mid + 1; i <= right; i++) {
sum += nums[i];
rightSum = Math.max(rightSum, sum);
}

maxSum = Math.max(maxSum, leftSum + rightSum);
}

return maxSum;
}
44 changes: 44 additions & 0 deletions minimum-window-substring/HC-kang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* https://leetcode.com/problems/minimum-window-substring
* T.C. O(s + t)
* S.C. O(t)
*/
function minWindow(s: string, t: string): string {
let minLow = 0;
let minHigh = s.length;

const counts: Record<string, number> = {};
for (const c of t) {
counts[c] = (counts[c] || 0) + 1;
}

let included = 0;

let low = 0;
for (let high = 0; high < s.length; high++) {
if (counts[s[high]]) {
if (counts[s[high]] > 0) {
included++;
}
counts[s[high]]--;
}

while (included === t.length) {
if (high - low < minHigh - minLow) {
minLow = low;
minHigh = high;
}

if (counts[s[low]]) {
counts[s[low]]++;
if (counts[s[low]] > 0) {
included--;
}
}

low++;
}
}

return minHigh === s.length ? '' : s.substring(minLow, minHigh + 1);
}
115 changes: 115 additions & 0 deletions pacific-atlantic-water-flow/HC-kang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* https://leetcode.com/problems/pacific-atlantic-water-flow
* T.C. O((m * n)^2)
* S.C. O(m * n)
*/
function pacificAtlantic(heights: number[][]): number[][] {
const dir = [
[0, 1],
[0, -1],
[1, 0],
[-1, 0],
];

function pacificDfs(row: number, col: number, visited: Set<string>) {
const key = `${row},${col}`;
if (visited.has(key)) return;
visited.add(key);

if (row === 0 || col === 0) {
// left or top
return true;
}

for (let [r, c] of dir) {
if (row + r < 0 || row + r >= heights.length) continue;
if (col + c < 0 || col + c >= heights[0].length) continue;
if (heights[row][col] < heights[row + r][col + c]) continue;
if (pacificDfs(row + r, col + c, visited)) return true;
}
return false;
}

function atlanticDfs(row: number, col: number, visited: Set<string>) {
const key = `${row},${col}`;
if (visited.has(key)) return;
visited.add(key);

if (row === heights.length - 1 || col === heights[0].length - 1) {
// right or bottom
return true;
}

for (let [r, c] of dir) {
if (row + r < 0 || row + r >= heights.length) continue;
if (col + c < 0 || col + c >= heights[0].length) continue;
if (heights[row][col] < heights[row + r][col + c]) continue;
if (atlanticDfs(row + r, col + c, visited)) return true;
}
return false;
}

const result: number[][] = [];
for (let i = 0; i < heights.length; i++) {
for (let j = 0; j < heights[0].length; j++) {
if (
pacificDfs(i, j, new Set<string>()) &&
atlanticDfs(i, j, new Set<string>())
) {
result.push([i, j]);
}
}
}

return result;
}

/**
* T.C. O(m * n)
* S.C. O(m * n)
Comment on lines +68 to +69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

시간 복잡도를 ^2이나 줄이시는 과정이 눈에 보여서 좋은것 같아요 :)
희찬의 경우에는 pacific, atlantic에서 공통 좌표를 가지고 있으면 추가해주는 식으로 하셨는데, 전 각각 boolean 타입의 배열을 만들어서, 둘다 true면 추가해주는 식으로 헀어요. 큰 차이는 없지만 제 풀이 코드도 확인해주시면 재미있으실것 같습니다 👍

*/
function pacificAtlantic(heights: number[][]): number[][] {
const pacific: Set<string> = new Set();
const atlantic: Set<string> = new Set();

const dir = [
[0, 1],
[0, -1],
[1, 0],
[-1, 0],
];

function dfs(row: number, col: number, visited: Set<string>) {
const key = `${row},${col}`;
if (visited.has(key)) return;
visited.add(key);

for (let [r, c] of dir) {
if (row + r < 0 || row + r >= heights.length) continue;
if (col + c < 0 || col + c >= heights[0].length) continue;
if (heights[row][col] > heights[row + r][col + c]) continue;
dfs(row + r, col + c, visited);
}
}

for (let i = 0; i < heights.length; i++) {
dfs(i, 0, pacific);
dfs(i, heights[0].length - 1, atlantic);
}

for (let i = 0; i < heights[0].length; i++) {
dfs(0, i, pacific);
dfs(heights.length - 1, i, atlantic);
}

const result: number[][] = [];

for (const p of pacific) {
if (atlantic.has(p)) {
const [row, col] = p.split(',').map(Number);
result.push([row, col]);
}
}

return result;
}