-
-
Notifications
You must be signed in to change notification settings - Fork 362
[okyungjin] WEEK 06 Solutions #2781
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
247b03d
040fa6c
e764d8b
6663c82
a28a02a
0ff54c4
a41de3a
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,40 @@ | ||
| """ | ||
| 문제: | ||
| - 담을 수 있는 최대 물의 양(최대 면적)을 구한다. | ||
| - i번째 수직선은 height[i] 높이를 가진다. | ||
| - x축과 선택한 두 수직선이 담는 물의 양이 최대가 되도록한다. | ||
|
|
||
| 접근법: | ||
| 1. 좌측, 우측 포인터 `left`, `right`를 선언하여 기둥을 움직인다. | ||
| 2. 좌우 기둥의 높이를 비교해서 높이가 낮은 기둥의 x좌표를 한칸 안쪽으로 움직인다. | ||
| 포인터를 바깥쪽에서 안쪽으로 이동할 때 가로의 길이가 줄어든다. | ||
| 따라서 낮은 기둥을 버려야 `max_area`를 갱신할 수 있는 가능성이 생긴다. | ||
| 3. 두 포인터가 만나거나 좌우가 역전되면 탐색을 종료한다. | ||
|
|
||
| 복잡도: | ||
| 시간 복잡도: O(n) | ||
| 공간 복잡도: O(1) | ||
|
|
||
| 실패했던 접근법: | ||
| 1. 2중 for: TLE | ||
| 2. 가장 높은 기둥을 고정축으로 하고 나머지 하나의 기둥을 찾도록: [1,2,1] 입력에서 실패 | ||
| """ | ||
| class Solution: | ||
| def maxArea(self, height: List[int]) -> int: | ||
| left = 0 | ||
| right = len(height) - 1 | ||
|
|
||
| max_area = 0 | ||
|
|
||
| while left < right: | ||
| if height[left] < height[right]: | ||
| area = height[left] * (right - left) | ||
| left += 1 | ||
| else: | ||
| area = height[right] * (right - left) | ||
| right -= 1 | ||
|
|
||
| if area > max_area: | ||
| max_area = area | ||
|
|
||
| return max_area | ||
|
okyungjin marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| """ | ||
|
Contributor
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. 저는 트라이 문제는 다 skip 했는데, 직관적으로 접근하신 부분에서 트라이의 필요성을 역체감 할 수 있어서 좋았습니다! |
||
| solution1: 직관적인 풀이 (PASS인데 엄청 느리다) | ||
| Runetime: 5438ms, Beats 5.00% | ||
| Memory: 26.74MB, Beats 99.60% | ||
| 접근법: | ||
| addWord: `word_set`에 단어를 삽입한다. | ||
| search: 와일드카드(`.`)은 a-z로 변환해서 데카르트 곱을 통해 가능한 모든 문자열의 조합인 `candidates`를 만든다. `candidates`를 순회하며 `word_set`에 단어가 있는지 확인한다. | ||
| """ | ||
| import string | ||
| import itertools | ||
|
|
||
| class WordDictionary: | ||
| def __init__(self): | ||
| self.word_set = set() | ||
|
|
||
| """ | ||
| L: `word`의 길이 | ||
| N: `word_set`에 저장된 단어의 개수 | ||
| Time: O(L), set.add() 메서드는 문자열 전체를 순회하며 해시 값을 계산해야 하므로 | ||
| Space: O(N*L) | ||
| """ | ||
| def addWord(self, word: str) -> None: | ||
| self.word_set.add(word) | ||
|
|
||
| """ | ||
| L: `word`의 길이 | ||
| Time: O(L) | ||
| Space: O(L) | ||
| """ | ||
| def search(self, word: str) -> bool: | ||
| candidates = [] | ||
|
|
||
| """Example: | ||
| word: "bad", candidates: ['b', 'a', 'd'] | ||
| word: ".ad", candidates: ['abcdefghijklmnopqrstuvwxyz', 'a', 'd'] | ||
| word: "b..", candidates: ['b', 'abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'] | ||
| """ | ||
| for c in word: | ||
| if c == '.': | ||
| candidates.append(string.ascii_lowercase) | ||
| else: | ||
| candidates.append(c) | ||
|
|
||
| # 데카르트 곱으로 가능한 조합 생성힌다 | ||
| for p in itertools.product(*candidates): | ||
| if ''.join(p) in self.word_set: | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
| """ | ||
| Solution2: Trie 자료구조 활용 | ||
| """ | ||
| class Trie: | ||
| def __init__(self): | ||
| self.children: dict[str, Trie] = {} | ||
| self.is_end = False | ||
|
|
||
|
|
||
| def addWord(self, word: str) -> None: | ||
| curr = self | ||
|
|
||
| for char in word: | ||
| if char not in curr.children: | ||
| curr.children[char] = Trie() | ||
| curr = curr.children[char] | ||
|
|
||
| curr.is_end = True | ||
|
|
||
|
|
||
| def search(self, word: str) -> bool: | ||
| def _dfs(node: Trie, idx) -> bool: | ||
| if idx == len(word): | ||
| return node.is_end | ||
|
|
||
| char = word[idx] | ||
|
|
||
| if char == '.': | ||
| return any( | ||
| _dfs(child, idx + 1) | ||
| for child in node.children.values()) | ||
|
|
||
| if char not in node.children: | ||
| return False | ||
|
|
||
|
|
||
| return _dfs(node.children[char], idx + 1) | ||
|
|
||
| return _dfs(self, 0) | ||
|
|
||
|
|
||
| class WordDictionary: | ||
| def __init__(self): | ||
| self.wordDict = Trie() | ||
|
|
||
|
|
||
| def addWord(self, word: str) -> None: | ||
| self.wordDict.addWord(word) | ||
|
|
||
|
|
||
| def search(self, word: str) -> bool: | ||
| return self.wordDict.search(word) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| """ | ||
| https://leetcode.com/problems/longest-increasing-subsequence/ | ||
|
|
||
| 정수 배열 nums가 주어졌을 때, 가장 긴 증가하는 부분수열(연속하지 않아도 됨)의 길이를 구한다. | ||
|
|
||
| 1. `dp[i]`: `nums[i]`로 끝나는 증가 부분수열 중 최장 길이 | ||
| 2. 모든 i에 대해, i보다 앞에 있고 값이 더 작은 j들의 dp[j] 중 최댓값 + 1을 dp[i]에 저장한다. | ||
| 3. 답은 dp 배열 전체의 최댓값이다. | ||
|
|
||
| Time: O(n^2) | ||
| Space: O(n) | ||
| """ | ||
| class Solution: | ||
| def lengthOfLIS(self, nums: List[int]) -> int: | ||
| n = len(nums) | ||
| dp = [1] * n | ||
|
|
||
| for i in range(1, n): | ||
| for j in range(i): | ||
| if nums[j] < nums[i] and dp[i] < dp[j] + 1: | ||
| dp[i] = dp[j] + 1 | ||
|
|
||
| return max(dp) | ||
|
|
||
| # TODO: O(n log n)으로 최적화 필요 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| """ | ||
| 복잡도: | ||
| n: `s`의 길이 | ||
| 시간 복잡도: O(n) | ||
| 공간 복잡도: O(n) | ||
| """ | ||
| class Solution: | ||
| def isValid(self, s: str) -> bool: | ||
| # 괄호 개수가 짝수인 경우는 항상 실패 | ||
| if len(s) % 2: | ||
| return False | ||
|
|
||
| brackets = { | ||
|
Contributor
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. 미리 dictionary 를 만드니, 아래에서 깔끔하게 접근할 수 있네요 👍🏼 |
||
| ')' : '(', | ||
| '}' : '{', | ||
| ']' : '[' | ||
| } | ||
|
|
||
| stack = [] | ||
|
|
||
| for char in s: | ||
| if char in brackets: # 닫히는 괄호인지 | ||
| if stack and stack[-1] == brackets[char]: | ||
| stack.pop() | ||
| else: | ||
| stack.append(char) | ||
|
Contributor
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. 이 케이스가 성공하는 경우가 없을 것 같아요.
Contributor
Author
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.
오 그렇네요 감사합니다. 다음 문제 풀때 수정해두겠습니다🙏 |
||
| else: | ||
| stack.append(char) | ||
|
|
||
| return len(stack) == 0 | ||
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.
사소하지만
right - left가width의 개념이고 아래서 반복되는 거 같아, 따로 빼도 괜찮을 것 같아요.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.
의견 감사합니다!