-
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
[mallayon] Week 6 #899
Merged
Merged
[mallayon] Week 6 #899
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
32fc22f
add solution : 20. Valid Parentheses
mmyeon 17451c3
add solution : 211. Design Add and Search Words Data Structure
mmyeon d08bcbe
add solution : 11. Container With Most Water
mmyeon 7d0ddc9
add solution : 300. Longest Increasing Subsequence
mmyeon 7c5d157
add solution : 54. Spiral Matrix
mmyeon 17ec148
update time and space complexity
mmyeon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
*@link https://leetcode.com/problems/container-with-most-water/description/ | ||
* | ||
* 접근 방법 : | ||
* - 가장 많은 물의 양을 구하기 위해서 투 포인터 사용 | ||
* - 한 높이가 낮으면 다른 높이가 아무리 높아도 의미가 없어서, 작은 높이를 가진 포인터 이동하며 계산 | ||
* - 양 끝에서 포인터 이동할 때마다 최대값 갱신 | ||
* | ||
* 시간복잡도 : O(n) | ||
* - 두 포인터가 배열 양 끝에서 1번씩 이동하므로 | ||
* | ||
* 공간복잡도 : O(1) | ||
* - 포인터(left,right)와 최대값 변수만 사용 | ||
*/ | ||
function maxArea(height: number[]): number { | ||
let left = 0, | ||
right = height.length - 1, | ||
maxWater = 0; | ||
|
||
while (left < right) { | ||
const width = right - left; | ||
const minHeight = Math.min(height[left], height[right]); | ||
maxWater = Math.max(maxWater, width * minHeight); | ||
|
||
if (height[left] < height[right]) { | ||
left++; | ||
} else { | ||
right--; | ||
} | ||
} | ||
|
||
return maxWater; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/** | ||
*@link https://leetcode.com/problems/design-add-and-search-words-data-structure/ | ||
* | ||
* 접근 방법 : | ||
* - set 활용하는 방법 | ||
* - 단어 추가할 때는 set에 저장하고, 단어 찾을 때마다 cache목록에서 값 가져오기. | ||
* - 단어 추가하면 이전 캐시는 사용하지 못하니까 클리어 해주기 | ||
* - 이전 값 활용한다는 장점이 있지만 단어 추가시 다시 캐시 만들어야하는 비효율 존재 | ||
* | ||
* 시간복잡도 : O(n * k) | ||
* - n은 set에 추가된 단어 길이, k는 각 단어 평균 길이 | ||
* - this.set 단어 순회 => O(n) | ||
* - replaceAll, filter => O(k) | ||
* | ||
* 공간복잡도 : O(n * k) | ||
* - n은 패턴의 개수, k는 패턴에 매칭되는 평균 단어 수 | ||
*/ | ||
class WordDictionary { | ||
set: Set<string>; | ||
cache: Map<string, string[]>; | ||
constructor() { | ||
this.set = new Set(); | ||
this.cache = new Map(); | ||
} | ||
|
||
addWord(word: string): void { | ||
this.set.add(word); | ||
// 새로운 단어가 추가 시 캐시 클리어 | ||
this.cache.clear(); | ||
} | ||
|
||
search(word: string): boolean { | ||
// 캐시에 값이 존재하면 즉시 리턴 | ||
if (this.cache.has(word)) return this.cache.get(word)!.length > 0; | ||
|
||
// 정규표현식 패턴 생성 | ||
const pattern = new RegExp(`^${word.replaceAll(".", "[a-z]")}$`); | ||
const matches = [...this.set].filter((item) => pattern.test(item)); | ||
|
||
// 검색 결과 캐시에 저장 | ||
this.cache.set(word, matches); | ||
|
||
return matches.length > 0; | ||
} | ||
} | ||
|
||
/** | ||
* Your WordDictionary object will be instantiated and called as such: | ||
* var obj = new WordDictionary() | ||
* obj.addWord(word) | ||
* var param_2 = obj.search(word) | ||
*/ | ||
|
||
// 시간 복잡도 개선하기 위해서 Trie 자료 구조 사용 | ||
class TrieNode { | ||
children: Map<string, TrieNode>; | ||
isEndOfWord: boolean; | ||
|
||
constructor() { | ||
this.children = new Map(); | ||
this.isEndOfWord = false; | ||
} | ||
} | ||
|
||
/* | ||
* 접근 방법 : | ||
* - 각 문자 저장하고 검색하기 위해서 Trie 구조 사용 | ||
* - 와일드카드(.)가 포함된 단어는 모든 자식 노드 탐색하기 위해서 재귀적으로 확인 | ||
* | ||
* 시간복잡도 : O(n * k) | ||
* - n : 단어 개수, m : 단어 평균 길이 => addWord의 복잡도 : O(n * m) | ||
* - c : 자식노드 개수, d : 와일드카드 개수, m : 단어 길이 => search의 복잡도 : O(c^d * m) | ||
* - 와일드 카드 있는 경우 각 노드 별 모든 자식 노드를 탐색해야 한다. | ||
* | ||
* 공간복잡도 : O(n * k) | ||
* - n은 패턴의 개수, k는 패턴에 매칭되는 평균 단어 수 | ||
*/ | ||
class WordDictionary { | ||
root: TrieNode; | ||
constructor() { | ||
this.root = new TrieNode(); | ||
} | ||
|
||
addWord(word: string): void { | ||
let currentNode = this.root; | ||
|
||
for (const letter of word) { | ||
if (!currentNode.children.has(letter)) | ||
currentNode.children.set(letter, new TrieNode()); | ||
currentNode = currentNode.children.get(letter)!; | ||
} | ||
|
||
currentNode.isEndOfWord = true; | ||
} | ||
|
||
search(word: string): boolean { | ||
const dfs = (currentNode: TrieNode, index: number): boolean => { | ||
if (index === word.length) return currentNode.isEndOfWord; | ||
|
||
const char = word[index]; | ||
// 와일드 카드인 경우 모든 자식 노드 순회한다 | ||
if (char === ".") { | ||
// 모든 자식 노드 순회 | ||
for (const key of currentNode.children.keys()) { | ||
if (dfs(currentNode.children.get(key)!, index + 1)) return true; | ||
} | ||
return false; | ||
} else { | ||
if (!currentNode.children.has(char)) return false; | ||
return dfs(currentNode.children.get(char)!, index + 1); | ||
} | ||
}; | ||
|
||
return dfs(this.root, 0); | ||
} | ||
} | ||
|
||
/** | ||
* Your WordDictionary object will be instantiated and called as such: | ||
* var obj = new WordDictionary() | ||
* obj.addWord(word) | ||
* var param_2 = obj.search(word) | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* | ||
* @link https://leetcode.com/problems/longest-increasing-subsequence/description/ | ||
* | ||
* 접근 방법 : dp 사용 | ||
* - dp[i]에 i번째 요소 포함한 LIS 길이 저장 | ||
* - 현재 값이 이전값보다 큰 경우, 이전값 순회하면서 LIS 업데이트하기 | ||
* | ||
* 시간복잡도 : O(n^2) | ||
* - 각 nums 순회하면서 이전값 비교하기 위해 순회하니까 O(n^2) | ||
* | ||
* 공간복잡도 : O(n) | ||
* - nums 길이만큼 dp 배열 생성하니까 O(n) | ||
*/ | ||
|
||
function lengthOfLIS(nums: number[]): number { | ||
const dp = Array(nums.length).fill(1); | ||
|
||
for (let i = 1; i < nums.length; i++) { | ||
for (let j = 0; j < i; j++) { | ||
if (nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1); | ||
} | ||
} | ||
|
||
return Math.max(...dp); | ||
} | ||
|
||
/** | ||
* | ||
* 접근 방법 : 이진 탐색 사용 | ||
* - num 삽입할 인덱스 찾기 위해서 이진 탐색 사용 | ||
* - nums 배열 순회하면서 각 num의 위치 찾기 | ||
* - 위치가 배열 내에 존재하면 기존 값을 대체하고, 위치가 배열 길이보다 크면 배열에 추가 | ||
* | ||
* 시간복잡도 : O(nlogn) | ||
* - nums 배열의 각 요소에 대해 이진 탐색 O(nlogn) | ||
* | ||
* 공간복잡도 : O(n) | ||
* - arr의 최대 크기가 nums 길이만큼 필요 | ||
*/ | ||
|
||
function lengthOfLIS(nums: number[]): number { | ||
const arr: number[] = []; | ||
|
||
nums.forEach((num) => { | ||
let left = 0, | ||
right = arr.length; | ||
// num 삽입할 위치를 이진 탐색으로 찾음 | ||
while (left < right) { | ||
const mid = Math.floor((left + right) / 2); | ||
|
||
if (arr[mid] < num) { | ||
left = mid + 1; | ||
} else right = mid; | ||
} | ||
|
||
// 기존 값 대체 | ||
if (left < arr.length) arr[left] = num; | ||
// 새로운 값 추가 | ||
else arr.push(num); | ||
}); | ||
|
||
return arr.length; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/** | ||
* @link https://leetcode.com/problems/spiral-matrix/description/ | ||
* | ||
* 접근 방법 : | ||
* - right -> bottom -> left -> top 순서로 진행하면서 경계 업데이트 처리 | ||
* | ||
* 시간복잡도 : O(n) | ||
* - n은 행렬의 모든 숫자로, 모든 숫자를 한 번씩 방문하므로 O(n) | ||
* | ||
* 공간복잡도 : O(n) | ||
* - 모든 숫자를 저장하기 위해서 배열 사용하므로 O(n) | ||
*/ | ||
|
||
function spiralOrder(matrix: number[][]): number[] { | ||
const result: number[] = []; | ||
// 경계 설정 | ||
let top = 0, | ||
bottom = matrix.length - 1, | ||
left = 0, | ||
right = matrix[0].length - 1; | ||
|
||
const moveRight = () => { | ||
for (let i = left; i <= right; i++) { | ||
result.push(matrix[top][i]); | ||
} | ||
top++; | ||
}; | ||
|
||
const moveDown = () => { | ||
for (let i = top; i <= bottom; i++) { | ||
result.push(matrix[i][right]); | ||
} | ||
right--; | ||
}; | ||
|
||
const moveLeft = () => { | ||
for (let i = right; i >= left; i--) { | ||
result.push(matrix[bottom][i]); | ||
} | ||
bottom--; | ||
}; | ||
|
||
const moveUp = () => { | ||
for (let i = bottom; i >= top; i--) { | ||
result.push(matrix[i][left]); | ||
} | ||
left++; | ||
}; | ||
|
||
while (top <= bottom && left <= right) { | ||
moveRight(); | ||
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. 정말 깔끔하네요 👍 |
||
moveDown(); | ||
|
||
if (top <= bottom) moveLeft(); | ||
if (left <= right) moveUp(); | ||
} | ||
|
||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
*@link https://leetcode.com/problems/valid-parentheses/description/ | ||
* | ||
* 접근 방법 : | ||
* - 닫힌 괄호 나왔을 때 열린 괄호의 마지막 값과 짝이 맞는지 찾아야되니까 stack 사용 | ||
* | ||
* 시간복잡도 : O(n) | ||
* - 문자열 순회하면서 괄호체크하니까 O(n) | ||
* | ||
* 공간복잡도 : O(k) | ||
* - pairs 객체 고정된 크기로 저장 O(1) | ||
* - k는 열린 괄호 개수, stack에 전체 문자열 중 k만큼만 담기니까 O(k) | ||
*/ | ||
|
||
function isValid(s: string): boolean { | ||
const pairs: Record<string, string> = { | ||
")": "(", | ||
"}": "{", | ||
"]": "[", | ||
}; | ||
const stack: string[] = []; | ||
|
||
for (const char of s) { | ||
// 닫는 괄호 나온 경우 처리 | ||
if (pairs[char]) { | ||
// 짝이 맞지 않는 경우 | ||
if (stack[stack.length - 1] !== pairs[char]) return false; | ||
|
||
// 짝이 맞는 경우 | ||
stack.pop(); | ||
} else { | ||
// 열린 괄호는 바로 stack에 저장 | ||
stack.push(char); | ||
} | ||
} | ||
|
||
return stack.length === 0; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
감사합니다 👍 리뷰할 때 문제 보기 너무 좋아요!