-
-
Notifications
You must be signed in to change notification settings - Fork 195
[soobing] WEEK09 Solutions #1525
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
Changes from all commits
5441051
c4f616e
67e7fac
c683a1c
61a6b72
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,52 @@ | ||
/** | ||
* 문제 설명 | ||
* - 링크드리스트 내에 cycle이 존재하는지 확인하는 문제 | ||
* | ||
* 아이디어 | ||
* - 링크드리스트를 끝까지 순회하면서 방문한 노드를 저장하고, 방문한 노드가 존재하면 cycle이 존재하는 것으로 판단 | ||
* - 시간복잡도: O(n), 공간복잡도 O(n) | ||
* | ||
*/ | ||
|
||
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; | ||
} | ||
} | ||
|
||
function hasCycle(head: ListNode | null): boolean { | ||
const visited = new Set<ListNode>(); | ||
|
||
while (head) { | ||
if (visited.has(head)) { | ||
return true; | ||
} else { | ||
visited.add(head); | ||
head = head.next; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* 공간복잡도 O(1) 로도 풀 수 있음. | ||
*/ | ||
|
||
// function hasCycle(head: ListNode | null): boolean { | ||
// let slow = head; | ||
// let fast = head; | ||
|
||
// while (fast && fast.next) { | ||
// slow = slow!.next; | ||
// fast = fast.next.next!; | ||
|
||
// if (slow === fast) { | ||
// return true; | ||
// } | ||
// } | ||
|
||
// return false; | ||
// } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* 문제 설명 | ||
* - 배열에서 연속된 부분 배열의 곱이 가장 큰 값을 찾는 문제 | ||
* | ||
* 아이디어 | ||
* - 1) 브루트포스 O(n^2) | ||
* - 2) DP 최적화 O(n) | ||
* - 매 index마다, 현재까지 max 곱, min 곱을 찾고 최대값을 갱신 | ||
*/ | ||
function maxProduct(nums: number[]): number { | ||
let maxSoFar = nums[0]; | ||
let max = nums[0]; | ||
let min = nums[0]; | ||
|
||
for (let i = 1; i < nums.length; i++) { | ||
const candidate = [nums[i], max * nums[i], min * nums[i]]; | ||
max = Math.max(...candidate); | ||
min = Math.min(...candidate); | ||
maxSoFar = Math.max(maxSoFar, max); | ||
} | ||
return maxSoFar; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/** | ||
* 문제 설명 | ||
* - 주어진 문자열 s에서 주어진 문자열 t의 모든 문자를 포함하는 최소 윈도우를 찾는 문제 | ||
* | ||
* 아이디어 | ||
* - 슬라이딩 윈도우 + 해시맵(need, window)을 이용하여 풀이한다. | ||
* - 오른쪽 포인터를 먼저 이동하고, 이미 모두 포함되어 있는 경우 왼쪽 포인터를 이동하여 최소 윈도우를 찾는다. | ||
* | ||
*/ | ||
function minWindow(s: string, t: string): string { | ||
if (t.length > s.length) return ""; | ||
|
||
const need = new Map<string, number>(); | ||
const window = new Map<string, number>(); | ||
|
||
for (const char of t) { | ||
need.set(char, (need.get(char) || 0) + 1); | ||
} | ||
|
||
let have = 0; | ||
let needSize = need.size; | ||
let res = [-1, -1]; | ||
let resLen = Infinity; | ||
|
||
let left = 0; | ||
|
||
for (let right = 0; right < s.length; right++) { | ||
const c = s[right]; | ||
window.set(c, (window.get(c) || 0) + 1); | ||
|
||
if (need.has(c) && window.get(c) === need.get(c)) { | ||
have++; | ||
} | ||
|
||
while (have === needSize) { | ||
const currentResLen = right - left + 1; | ||
if (currentResLen < resLen) { | ||
res = [left, right]; | ||
resLen = currentResLen; | ||
} | ||
|
||
const lChar = s[left]; | ||
window.set(lChar, window.get(lChar)! - 1); | ||
|
||
if (need.has(lChar) && window.get(lChar)! < need.get(lChar)!) { | ||
have--; | ||
} | ||
left++; | ||
} | ||
} | ||
|
||
const [start, end] = res; | ||
return resLen === Infinity ? "" : s.slice(start, end + 1); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* 문제 설명 | ||
* - 비가 내렸을 때, 태평양과 대서양 모두로 물이 흐를 수 있는 지점을 찾아 반환하는 문제입니다. | ||
* 아이디어 | ||
* 1) BFS/DFS | ||
* - 각 바다에서 역방향으로 물이 도달할 수 있는 셀을 탐색한 후, 두 바다 모두에 도달 가능한 셀의 교집합 구하기 | ||
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. 안녕하세요! 저는 모든 셀에 대해서 양 바다로 모두 닿을 수 있는지 여부를 판단하려고 모든 셀 * 2 번씩 dfs 를 돌렸었는데 (어떤 부분을 보고 이렇게 접근해볼 수도 있겠다.. 라는 식의 느낌입니다 🤣 뭔가 콕찝어서 설명을 못하겠네요ㅠ) +) 알고리즘 문제를 풀이하실 때 풀이 아이디어를 떠올리시는 포인트? 같은것도 만약 있으시다면 알려주시면 감사히 배워가겠습니다! |
||
* | ||
*/ | ||
|
||
function pacificAtlantic(heights: number[][]): number[][] { | ||
const m = heights.length; | ||
const n = heights[0].length; | ||
|
||
const pacific = Array.from({ length: m }, () => Array(n).fill(false)); | ||
const atlantic = Array.from({ length: m }, () => Array(n).fill(false)); | ||
|
||
const directions = [ | ||
[1, 0], | ||
[-1, 0], | ||
[0, 1], | ||
[0, -1], | ||
]; | ||
|
||
function dfs(r: number, c: number, visited: boolean[][], prevHeight: number) { | ||
if ( | ||
r < 0 || | ||
c < 0 || | ||
r >= m || | ||
c >= n || | ||
visited[r][c] || | ||
heights[r][c] < prevHeight | ||
) | ||
return; | ||
|
||
visited[r][c] = true; | ||
|
||
for (const [dr, dc] of directions) { | ||
dfs(r + dr, c + dc, visited, heights[r][c]); | ||
} | ||
} | ||
|
||
// 태평양 DFS | ||
for (let i = 0; i < m; i++) { | ||
dfs(i, 0, pacific, heights[i][0]); // 왼쪽 | ||
dfs(i, n - 1, atlantic, heights[i][n - 1]); // 오른쪽 | ||
} | ||
|
||
for (let j = 0; j < n; j++) { | ||
dfs(0, j, pacific, heights[0][j]); // 위쪽 | ||
dfs(m - 1, j, atlantic, heights[m - 1][j]); // 아래쪽 | ||
} | ||
|
||
const result: number[][] = []; | ||
|
||
for (let i = 0; i < m; i++) { | ||
for (let j = 0; j < n; j++) { | ||
if (pacific[i][j] && atlantic[i][j]) { | ||
result.push([i, j]); | ||
} | ||
} | ||
} | ||
|
||
return result; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/** | ||
* 문제 설명 | ||
* - 두 정수의 합을 반환하는 문제 (비트 연산을 통해서) | ||
* | ||
* 아이디어 | ||
* - 반올림은 AND(&) + 왼쪽 shift 1, 덧셈은 XOR(^) 연산을 통해서 한다. | ||
* - 반올림이 0이 될 때까지 반복한다. ⭐️ | ||
*/ | ||
function getSum(a: number, b: number): number { | ||
while (b !== 0) { | ||
const carry = (a & b) << 1; | ||
a = a ^ b; | ||
b = carry; | ||
} | ||
return a; | ||
} |
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.
모든 경우를 한 번에 고려하는 깔끔한 접근입니다 👍
초기에 빈 배열 예외처리가 있으면 더 좋을것 같아요!