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
13 changes: 13 additions & 0 deletions best-time-to-buy-and-sell-stock/dolphinflow86.py

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.

깔끔하게 잘 해결해 주셨네요!
best time to buy and sell stock, 즉 해당 문제는
뒤에 로마 숫자를 붙혀서 1, 2, 3, 4, 5 총 다섯종류가 있는데요
dp 연습하기에 정말 괜찮은 문제라고 생각해서
2번문제
II는 한번 풀어보시길 추천드려요!

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.

오! 네 문제 추천 감사합니다! 한번 풀어볼게요 👍

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Two Pointers, Greedy, Hash Map / Hash Set
  • 설명: 주어진 코드는 단순히 현재 최소가를 유지하며 가격을 순회하면서 최대 이익을 갱신하는 방식으로 구현되어 있습니다. 한 번의 순회로 최적해를 구하는 그리디 접근이며, 투 포인터의 개념으로 좌우의 값을 관리합니다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(N) O(n)
Space O(1) O(1)

피드백: 한 번의 순회를 통해 현재 가격과 최소 가격을 비교하며 최대 이익을 갱신합니다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 1) Keep track of local minimum and use local minimum to update max profile while interating prices.
# TC: O(N) where N is the length of prices
# SC: O(1)
class Solution:
def maxProfit(self, prices: List[int]) -> int:
min_price = prices[0]
max_profit = 0

for price in prices:
max_profit = max(max_profit, price - min_price)
min_price = min(min_price, price)
Comment on lines +9 to +11

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.

사소하지만 더 최적화 할 수 있는 부분은 min, max 일 거 같아요. 고민해보셔도 좋을 거 같습니다!

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.

같은 의견입니다! min, max가 생각보다 비용이 크더라구요

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.

두분 의견 감사합니다! if문으로 인라인 처리하면 함수 호출 오버헤드 등을 줄일 수 있겠네요.


return max_profit
30 changes: 30 additions & 0 deletions encode-and-decode-strings/dolphinflow86.py

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Greedy, Hash Map / Hash Set, Dynamic Programming, Two Pointers, Sliding Window, Binary Search, Monotonic Stack, Heap / Priority Queue, DFS, BFS, Backtracking, Divide and Conquer, Union Find, Trie, Bit Manipulation
  • 설명: 주어진 코드는 문자열 인코딩/디코딩에서 길이 정보를 이용해 분리하는 방식으로 구성됩니다. 정확한 패턴으로는 문자열 처리 흐름의 순차 탐색(Two Pointers와 직접적 연결)과 길이 마커를 활용한 고정 포맷 파싱이 핵심이며, 전체적으로 특정 자료구조를 활용한 문제풀이보다는 문자열 조작 및 탐색에 가깝습니다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution.encode — Time: O(n) / Space: O(n)
복잡도
Time O(n)
Space O(n)

피드백: 선형 탐색으로 문자열들을 연결하므로 시간/공간 복잡도는 입력 총 길이에 비례합니다.

개선 제안: 현재 구현이 적절해 보입니다.

풀이 2: Solution.decode — Time: O(n) / Space: O(n)
복잡도
Time O(n)
Space O(n)

피드백: 인코딩과 대칭적인 단일 패스 파싱으로 작동합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 1) Prepend each word with its length and a delimiter '%'.
# TC: encode O(N) where N is the len(str), decode O(N) where N is the len(s)
# SC: O(N) for storing the encoded string
class Solution:

def encode(self, strs: list[str]) -> str:
answer = ""
for s in strs:
answer += f"{len(s)}%{s}"
Comment on lines +7 to +9

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.

저도 이번에 공부하면서 배운 내용인데, 아래와 같이 작성하면 최적화가 가능한 것 같습니다.

  1. 리스트 대신 제너레이터 표현식 사용해서 메모리 최적화
  2. 문자열 += 연산으로 매번 새로운 문자열 생성하는대신, join으로 문자열 한번에 합치기
def encode(self, strs: list[str]) -> str:
    return "".join(f"{len(s)}%{s}" for s in strs)

혹은

def encode(self, strs: list[str]) -> str:
    parts = (f"{len(s)}%{s}" for s in strs)
    return "".join(parts)

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.

저도 블로그로 정리하다 join으로 개선하는 부분 발견했는데, 짚어주셔서 감사합니다. 파이썬은 문자열이 immutable이라 조심해야겠더라고요. join이 재너레이터 표현식 방식으로 동작하는것도 잘 알아갑니다! 감사합니다.

return answer

def decode(self, s: str) -> list[str]:
left = 0
right = 0
str_len = len(s)

result = []
while right < str_len:
while s[right] != "%":

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 += 1

num_len = int(s[left:right])
start = right + 1
word = s[start : start + num_len]
result.append(word)

left = start + num_len
right = left

return result
13 changes: 13 additions & 0 deletions group-anagrams/dolphinflow86.py

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Hash Map / Hash Set, Greedy, Divide and Conquer
  • 설명: 문자열의 정렬 결과를 키로 사용해 해시 맵에 그룹화하는 방식으로, 키 생성과 묶음은 해시 맵 기반의 카운트/그룹화 패턴에 해당합니다. 각 문자열을 정렬해 동일한 키를 모으는 전형적인 해시 맵 활용 예시입니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n * k log k)
Space O(n)

피드백: 각 문자열을 정렬하는 비용이 주요 요인이며, 해시 맵으로 묶는 비효율 없이 처리합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

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.

리뷰 누락이 있어서 추가로 남깁니다.

  1. str은 파이썬 클래스와 혼동이 있을 수 있어서 가급적이면 변수명으로 쓰지 않는 것이 좋을 것 같습니다.
  2. 저도 리뷰 받았던 내용인데, sorted의 정렬 대신 다르게 구현하여 시간 복잡도를 개선해보면 좋을 것 같습니다.

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.

c++ 습관이 자꾸 나오네요 ㅎㅎ str은 사용하지 않아야겠습니다. 두번째 방법도 한번 생각해볼게요! 꼼꼼하게 리뷰해주셔서 감사합니다 🙏

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 1) Group words by their sorted form using defaultdict. While iterating the strs, sort each word and append original word to the corresponding list. After then convert dict to 2 dimensional list and return the list.
# TC: O(N*LlogL) where N is length of strs, L is max length of a word.
# SC: O(N*L)

class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
groups = defaultdict(list)

for str in strs:
sorted_str = "".join(sorted(str))
groups[sorted_str].append(str)

return list(groups.values())
53 changes: 53 additions & 0 deletions implement-trie-prefix-tree/dolphinflow86.py

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Trie, Hash Map / Hash Set
  • 설명: 트라이 구현은 Trie 패턴의 대표 예로, 각 노드에 자식 배열을 두고 문자열의 존재 여부를 탐색/삽입한다. 이 문제의 구현은 트라이의 기본 구조와 prefix 검색 동작을 보여준다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 3가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Trie.insert — Time: O(n) / Space: O(n * alphabet)
복잡도
Time O(n)
Space O(n * alphabet)

피드백: Trie 구조를 직접 구현해 삽입/검색/접두사 검색을 제공합니다.

개선 제안: 현재 구현이 적절해 보입니다.

풀이 2: Trie.search — Time: O(n) / Space: O(1)
복잡도
Time O(n)
Space O(1)

피드백: 정확히 동작하도록 구성되어 있습니다.

개선 제안: 현재 구현이 적절해 보입니다.

풀이 3: Trie.startsWith — Time: O(n) / Space: O(1)
복잡도
Time O(n)
Space O(1)

피드백: 접두사 검색 요구를 만족합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 1) Tried to come up with the Trie data structure first and then imlement TrieNode. Key factor here is each TrieNode has children array and is_end to connect to its child nodes and end flag.
# TC: insert, search O(N) where N is len(word), prefix O(L) where L is len(prefix)
# SC: insert O(N) where N is len(word), search/startsWith O(1)
class TrieNode:
def __init__(self):
self.children = [None] * 26
self.is_end = False

class Trie:

def __init__(self):
self.root = TrieNode()

# apple
def insert(self, word: str) -> None:
cur = self.root

for c in word:
idx = ord(c) - ord('a')
if not cur.children[idx]:
cur.children[idx] = TrieNode()
cur = cur.children[idx]

cur.is_end = True

# apple
def search(self, word: str) -> bool:
cur = self.root

for c in word:
idx = ord(c) - ord('a')
if cur.children[idx]: cur = cur.children[idx]
else:
return False

return cur.is_end

def startsWith(self, prefix: str) -> bool:
cur = self.root

for c in prefix:
idx = ord(c) - ord('a')
if cur.children[idx]: cur = cur.children[idx]
else: return False

return True


# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
16 changes: 16 additions & 0 deletions word-break/dolphinflow86.py

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Dynamic Programming, Hash Map / Hash Set
  • 설명: 문자열 부분문제의 해를 기억해 부분문제 결과를 이용하는 DP 패턴과 단어 사전을 빠르게 확인하기 위한 해시 세트 사용이 핵심입니다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(N^3) O(n^2)
Space O(N + L) O(n)

피드백: DP 테이블의 각 위치에서 앞선 위치를 체크해 문제를 부분 문제로 해결합니다.

개선 제안: 현재 구현이 적절해 보입니다.

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.

BFS나 Trie 자료구조 사용한 풀이법도 적용해보면 좋을 것 같습니다!

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.

찾아보니 작년에 BFS로 풀었더라고요? 이번에는 그 방법이 안떠올라서 조금 난감했네요 ㅎㅎ BFS나 Trie 방법도 고려해보겠습니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 1) I couldn't figure it out by myself this time, so I looked into the solution and found the DP approach. Key point here is that when an element of dp is True, use it as a checkpoint to slice the rest of the string.
# TC: O(N^3) where N is len(s)
# SC: O(N + L) where N is len(s), L is total length of characters in wordDict
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
word_set = set(wordDict)
s_len = len(s)
dp = [False] * (s_len + 1)
dp[0] = True

for i in range(1, s_len + 1):
for j in range(i):
if dp[j] and s[j:i] in word_set:
dp[i] = True

return dp[-1]
Loading