-
-
Notifications
You must be signed in to change notification settings - Fork 195
[Jeehay28] Week 08 Solutions #1493
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
base: main
Are you sure you want to change the base?
Changes from all commits
0fa4bbc
4b08997
5556875
bfed15c
70055ee
e4973c8
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,67 @@ | ||
class _Node { | ||
val: number; | ||
neighbors: _Node[]; | ||
|
||
constructor(val?: number, neighbors?: _Node[]) { | ||
this.val = val === undefined ? 0 : val; | ||
this.neighbors = neighbors === undefined ? [] : neighbors; | ||
} | ||
} | ||
|
||
// TC: O(V + E), where V is the number of vertices and E is the number of edges | ||
// SC: O(V + E) | ||
function cloneGraph(node: _Node | null): _Node | null { | ||
// 1: [2, 4] | ||
// 2: [1, 3] | ||
// 3: [2, 4] | ||
// 4: [1, 3] | ||
|
||
const clones = new Map<_Node, _Node>(); | ||
// original Node: cloned Node | ||
|
||
if (!node) return null; | ||
|
||
const dfs = (node: _Node) => { | ||
if (clones.has(node)) { | ||
return clones.get(node); | ||
} | ||
|
||
const clone = new _Node(node.val); | ||
clones.set(node, clone); | ||
|
||
for (const nei of node.neighbors) { | ||
clone.neighbors.push(dfs(nei)!); | ||
} | ||
|
||
return clone; | ||
}; | ||
|
||
return dfs(node)!; | ||
} | ||
|
||
|
||
// TC: O(V + E) | ||
// SC: O(V + E) | ||
// function cloneGraph(node: _Node | null): _Node | null { | ||
// if (!node) return null; | ||
|
||
// const clone: _Node = new _Node(node.val); | ||
// const clones = new Map<_Node, _Node>(); | ||
// clones.set(node, clone); | ||
// const queue: _Node[] = [node]; // BFS -> use queue | ||
|
||
// while (queue.length > 0) { | ||
// const node = queue.shift()!; | ||
// for (const nei of node.neighbors) { | ||
// if (!clones.has(nei)) { | ||
// clones.set(nei, new _Node(nei.val)); | ||
// queue.push(nei); | ||
// } | ||
// clones.get(node)!.neighbors.push(clones.get(nei)!); | ||
// } | ||
// } | ||
|
||
// return clone; | ||
// } | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// TC: O(m * n) | ||
// SC: O(m * n) | ||
function longestCommonSubsequence(text1: string, text2: string): number { | ||
const memo = new Map<string, number>(); | ||
|
||
const dfs = (i: number, j: number) => { | ||
const key = `${i}-${j}`; | ||
|
||
if (memo.has(key)) return memo.get(key); | ||
|
||
if (i === text1.length || j === text2.length) { | ||
// "" | ||
memo.set(key, 0); | ||
} else if (text1[i] === text2[j]) { | ||
memo.set(key, 1 + dfs(i + 1, j + 1)!); | ||
} else { | ||
memo.set(key, Math.max(dfs(i + 1, j)!, dfs(i, j + 1)!)); | ||
} | ||
|
||
return memo.get(key); | ||
}; | ||
|
||
return dfs(0, 0)!; | ||
} | ||
|
||
|
||
// TC: O(m * n) | ||
// SC: O(m * n) | ||
// function longestCommonSubsequence(text1: string, text2: string): number { | ||
// const m = text1.length + 1; | ||
// const n = text2.length + 1; | ||
|
||
// const dp: number[][] = Array.from({ length: m }, () => Array(n).fill(0)); | ||
|
||
// for (let i = 1; i < m; i++) { | ||
// for (let j = 1; j < n; j++) { | ||
// // Note: text1[i - 1] and text2[j - 1] because dp uses 1-based indexing, | ||
// // while the strings use 0-based indexing | ||
// if (text1[i - 1] === text2[j - 1]) { | ||
// dp[i][j] = 1 + dp[i - 1][j - 1]; | ||
// } else { | ||
// dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); | ||
// } | ||
// } | ||
// } | ||
|
||
// return dp[m - 1][n - 1]; | ||
// } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// TC: O(n) | ||
// SC: O(1) | ||
function characterReplacement(s: string, k: number): number { | ||
const freqMap = new Map<string, number>(); | ||
let left = 0; | ||
let maxFreqCnt = 0; | ||
let result = 0; | ||
|
||
for (let right = 0; right < s.length; right++) { | ||
const ch = s[right]; | ||
freqMap.set(ch, (freqMap.get(ch)! | 0) + 1); | ||
maxFreqCnt = Math.max(maxFreqCnt, freqMap.get(ch)!); | ||
|
||
while (right - left + 1 - maxFreqCnt > k) { | ||
// Shrink the sliding window by moving the left pointer to the right. | ||
// As we move left, decrease the frequency count of the character being excluded from the window. | ||
const ch = s[left]; | ||
freqMap.set(ch, freqMap.get(ch)! - 1); | ||
left++; | ||
} | ||
|
||
result = Math.max(result, right - left + 1); | ||
} | ||
|
||
return result; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// TC: O(n^2) | ||
// SC: O(1) | ||
function countSubstrings(s: string): number { | ||
// Treat each index as the center of potential palindromic substrings | ||
let cnt = 0; | ||
|
||
for (let i = 0; i < s.length; i++) { | ||
let start = i; | ||
let end = i; | ||
|
||
// Check for odd-length palindromes centered at i | ||
while (start >= 0 && end < s.length && s[start] === s[end]) { | ||
cnt++; | ||
start--; // <---- | ||
end++; // -----> | ||
} | ||
|
||
// Check for even-length palindromes centered between i and i + 1 | ||
start = i; | ||
end = i + 1; | ||
|
||
while (start >= 0 && end < s.length && s[start] === s[end]) { | ||
cnt++; | ||
start--; | ||
end++; | ||
} | ||
} | ||
|
||
return cnt; | ||
} | ||
|
||
// TC: O(n^2) | ||
// SC: O(n^2) | ||
/* | ||
function countSubstrings(s: string): number { | ||
// dp[(start, end)] = s[start] === s[end] && dp[(start + 1, end - 1)] | ||
|
||
// A new starting character + an existing palindromic substring + a new ending character | ||
// start dp[(start + 1, end - 1)] end | ||
|
||
const dp = new Map<string, boolean>(); | ||
|
||
for (let end = 0; end < s.length; end++) { | ||
// start ranges from end down to 0 | ||
for (let start = end; start >= 0; start--) { | ||
const key = `${start}-${end}`; | ||
if (start === end) { | ||
// "a" | ||
dp.set(key, true); | ||
} else if (start + 1 === end) { | ||
// "aa" | ||
dp.set(key, s[start] === s[end]); | ||
} else { | ||
const prevKey = `${start + 1}-${end - 1}`; | ||
dp.set(key, s[start] === s[end] && dp.get(prevKey) === true); | ||
} | ||
} | ||
} | ||
|
||
let cnt = 0; | ||
|
||
for (const [key, value] of dp.entries()) { | ||
if (value) { | ||
cnt++; | ||
} | ||
} | ||
|
||
return cnt; | ||
} | ||
*/ | ||
|
||
// TC: O(n^3) | ||
// SC: O(1) | ||
// function countSubstrings(s: string): number { | ||
// const isPalindromic = (left: number, right: number) => { | ||
// while (left < right) { | ||
// if (s[left] !== s[right]) return false; | ||
|
||
// left++; | ||
// right--; | ||
// } | ||
|
||
// return true; | ||
// }; | ||
|
||
// let cnt = 0; | ||
|
||
// for (let i = 0; i < s.length; i++) { | ||
// for (let j = i; j < s.length; j++) { | ||
// if (isPalindromic(i, j)) { | ||
// cnt++; | ||
// } | ||
// } | ||
// } | ||
|
||
// return cnt; | ||
// } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// TC: O(1) | ||
// SC: O(1) | ||
function reverseBits(n: number): number { | ||
let stack: number[] = []; | ||
|
||
while (stack.length < 32) { | ||
stack.push(n % 2); | ||
n = Math.floor(n / 2); | ||
} | ||
|
||
let output: number = 0; | ||
let scale: number = 1; | ||
|
||
while (stack.length > 0) { | ||
output += stack.pop()! * scale; | ||
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.
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. 네, 설명 감사합니다! 타입스크립트가 정적 타입 체크 기반이라는 걸 잘 몰랐을 때는, 런타임에선 항상 안전하다고 생각해서 !만 써서 넘겼던 것 같아요. 이제는 좀 더 안전하게 처리해보겠습니다. 😊 |
||
scale *= 2; | ||
} | ||
|
||
return output; | ||
} | ||
|
||
// TC: O(1) | ||
// SC: O(1) | ||
/* | ||
function reverseBits(n: number): number { | ||
let result = 0; | ||
|
||
for (let i = 0; i < 32; i++) { | ||
let bit = n & 1; | ||
result = (result << 1) | bit; | ||
n = n >>> 1; | ||
} | ||
|
||
return result >>> 0; | ||
} | ||
*/ | ||
|
||
/* | ||
n & 1 | ||
- get last bit | ||
- equivalent to n % 2 for non-negative integer | ||
|
||
n << 1 | ||
- left shift (multiply by 2) | ||
|
||
n >>> 1 | ||
- Unsigned right shift (divide by 2) | ||
- ignores sign | ||
|
||
n >>> 0 | ||
- no shift, just cast to unsigned | ||
|
||
const signed = -1; // Binary: 11111111111111111111111111111111 | ||
const unsigned = signed >>> 0; // 4294967295 | ||
|
||
JavaScript/TypeScript only has one number type — a 64-bit float. itwise operations use 32-bit signed integers. | ||
To return a 32-bit unsigned integer, use >>> 0 on the result. | ||
|
||
🔧 Bitwise Operations in JavaScript — Summary | ||
1. Bitwise operations in JavaScript (&, |, ^, ~, <<, >>, >>>) are always performed on 32-bit signed integers. | ||
|
||
2. Internally: | ||
- JavaScript converts your number into a 32-bit signed integer | ||
- Performs the bitwise operation | ||
- Then converts it back into a regular 64-bit number (JavaScript's only number type) | ||
|
||
3. If you need the result as a 32-bit unsigned integer (like for LeetCode problems dealing with uint32): | ||
- Use >>> 0 at the end of your result | ||
- This forces the result to be treated as an unsigned 32-bit integer | ||
*/ | ||
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. 자바스크립트의 비트 연산 특성과 32비트 정수 변환 과정을 자세히 설명한 점이 좋았어요! 👍 |
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.
Map에서 값을 가져올 때 항상 존재한다고 가정하는
!
보다,옵셔널 체이닝
+nullish coalescing
사용이 안전할 것 같아요 :)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.
아, 그렇군요. 알려주셔서 감사합니다.