Skip to content
Merged
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
40 changes: 40 additions & 0 deletions container-with-most-water/okyungjin.py
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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

사소하지만 right - leftwidth의 개념이고 아래서 반복되는 거 같아, 따로 빼도 괜찮을 것 같아요.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

의견 감사합니다!

left += 1
else:
area = height[right] * (right - left)
right -= 1

if area > max_area:
max_area = area

return max_area
106 changes: 106 additions & 0 deletions design-add-and-search-words-data-structure/okyungjin.py
Comment thread
okyungjin marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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)
25 changes: 25 additions & 0 deletions longest-increasing-subsequence/okyungjin.py
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)으로 최적화 필요
30 changes: 30 additions & 0 deletions valid-parentheses/okyungjin.py
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 = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이 케이스가 성공하는 경우가 없을 것 같아요.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

이 케이스가 성공하는 경우가 없을 것 같아요.

오 그렇네요 감사합니다. 다음 문제 풀때 수정해두겠습니다🙏

else:
stack.append(char)

return len(stack) == 0
Loading