-
-
Notifications
You must be signed in to change notification settings - Fork 362
[ICE0208] WEEK 05 Solutions #2774
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
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,31 @@ | ||
| class Solution { | ||
| /** | ||
| * 오늘 주식을 판매한다고 가정하면, | ||
| * 이전 날짜 중 가장 낮은 가격에 구매했을 때 최대 이익을 얻을 수 있다. | ||
| * 배열을 순회하면서 최저 가격과 최대 이익을 계속 갱신한다. | ||
| * | ||
| * 시간 복잡도: O(n) | ||
| * 공간 복잡도: O(1) | ||
|
Comment on lines
+2
to
+8
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. 주석도 설명이 아주 잘되어있고, 코드도 정말 깔끔하네요. 수고하셨습니다!! |
||
| */ | ||
| public int maxProfit(int[] prices) { | ||
| // 현재까지 확인한 날짜 중 가장 낮은 주가 | ||
| int minPrice = prices[0]; | ||
|
|
||
| // 현재까지 얻을 수 있는 최대 이익 | ||
| int maxProfit = 0; | ||
|
|
||
| // 첫 번째 가격은 minPrice로 사용했으므로 두 번째 가격부터 확인한다. | ||
| for (int i = 1; i < prices.length; i++) { | ||
| int currentPrice = prices[i]; | ||
| int currentProfit = currentPrice - minPrice; | ||
|
|
||
| // 이전 최저가에 구매하고 현재 가격에 판매했을 때의 이익을 비교한다. | ||
| maxProfit = Math.max(maxProfit, currentProfit); | ||
|
|
||
| // 이후 날짜의 계산을 위해 지금까지의 최저가를 갱신한다. | ||
| minPrice = Math.min(minPrice, currentPrice); | ||
| } | ||
|
|
||
| return maxProfit; | ||
| } | ||
| } | ||
|
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. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
풀이 1:
|
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(n) |
피드백: 모든 문자열 길이의 합 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,49 @@ | ||
| from typing import List | ||
|
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. 파이썬 3.9+ 부터는 선언을 안해도 list[str]을 쓸 수 있다고 합니다!
Member
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. 앗 그렇군요 |
||
|
|
||
|
|
||
| class Solution: | ||
|
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. 어떤 문제는 자바로 푸시고, 어떤 문제는 파이썬으로 푸셨네요. 같이 연습을 하시는 이유가 따로 있나요??
Member
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. 원래 알고리즘 문제 풀이는 파이썬으로만 했는데, 최근 스프링 백엔드 쪽을 공부하고 있어서 자바와 좀 더 친해지고자 이번 알고리즘 문제는 자바로 풀고 있습니다...만! 이번 주는 시간이 없어 벼락치기로 문제를 풀다 보니 어쩔 수 없이 파이썬으로 빠르게 풀고 제출했습니다. ㅎㅎ |
||
| """ | ||
| 각 문자열을 '문자열 길이#문자열' 형식으로 인코딩한다. | ||
|
|
||
| 예: | ||
| ["Hello", "World", ""] | ||
| -> "5#Hello5#World0#" | ||
|
|
||
| 시간 복잡도: O(n) | ||
| 공간 복잡도: O(n) | ||
|
|
||
| n은 모든 문자열 길이의 합이다. | ||
| """ | ||
|
|
||
| def encode(self, strs: List[str]) -> str: | ||
| encoded = [] | ||
|
|
||
| for word in strs: | ||
| encoded.append(f"{len(word)}#{word}") | ||
|
|
||
| return "".join(encoded) | ||
|
|
||
| def decode(self, encoded_string: str) -> List[str]: | ||
| decoded = [] | ||
| index = 0 | ||
|
|
||
| while index < len(encoded_string): | ||
| delimiter_index = index | ||
|
|
||
| # 문자열 길이와 실제 문자열을 나누는 '#'을 찾는다. | ||
| while encoded_string[delimiter_index] != "#": | ||
| delimiter_index += 1 | ||
|
|
||
| word_length = int( | ||
| encoded_string[index:delimiter_index] | ||
| ) | ||
|
|
||
| word_start = delimiter_index + 1 | ||
| word_end = word_start + word_length | ||
|
|
||
| decoded.append(encoded_string[word_start:word_end]) | ||
|
|
||
| # 다음 문자열의 길이가 시작되는 위치로 이동한다. | ||
| index = word_end | ||
|
|
||
| return decoded | ||
|
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. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 모든 문자열을 한 번씩 처리하고 빈도 배열을 키로 사용한다. 개선 제안: 현재 구현이 적절해 보입니다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| class Solution { | ||
| /** | ||
| * 각 문자열의 알파벳 등장 횟수를 키로 사용해 | ||
| * 같은 애너그램끼리 그룹화한다. | ||
| * | ||
| * 시간 복잡도: O(S) | ||
| * 공간 복잡도: O(n) | ||
| * | ||
| * S: 모든 문자열 길이의 합 | ||
| * n: 문자열의 개수 | ||
| */ | ||
| public List<List<String>> groupAnagrams(String[] strs) { | ||
| Map<String, List<String>> groups = new HashMap<>(); | ||
|
|
||
| for (String word : strs) { | ||
| int[] frequency = new int[26]; | ||
|
|
||
| // 알파벳별 등장 횟수를 계산한다. | ||
| for (int i = 0; i < word.length(); i++) { | ||
|
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. 저는 문자열 정렬로 해결 했는데, 빈도 배열이면 시간복잡도 상 더 유리하겠네요! |
||
| frequency[word.charAt(i) - 'a']++; | ||
| } | ||
|
|
||
| // 빈도 배열을 같은 내용끼리 비교할 수 있는 키로 변환한다. | ||
| String key = Arrays.toString(frequency); | ||
|
|
||
| // 같은 키를 가진 문자열을 동일한 그룹에 추가한다. | ||
| groups.computeIfAbsent(key, ignored -> new ArrayList<>()) | ||
|
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. 코드 수를 줄일 수 있어서 좋네요. 배워갑니다! |
||
| .add(word); | ||
| } | ||
|
|
||
| return new ArrayList<>(groups.values()); | ||
| } | ||
| } | ||
|
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. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
풀이 1:
|
| 복잡도 | |
|---|---|
| Time | O(m) |
| Space | O(m) |
피드백: 새 단어를 추가할 때 길이 m에 비례하는 시간과 공간을 사용한다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 2: Trie.search — Time: O(m) / Space: O(1)
| 복잡도 | |
|---|---|
| Time | O(m) |
| Space | O(1) |
피드백: 경로 탐색과 끝 단어 여부 확인으로 판단한다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 3: Trie.startsWith — Time: O(m) / Space: O(1)
| 복잡도 | |
|---|---|
| Time | O(m) |
| Space | O(1) |
피드백: 접두사 여부는 경로 존재 여부로 충분하다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| class TrieNode: | ||
| def __init__(self): | ||
| # 다음 문자로 연결되는 자식 노드 | ||
| self.children = {} | ||
|
|
||
| # 현재 노드에서 하나의 완성된 단어가 끝나는지 표시 | ||
| self.is_end_of_word = False | ||
|
|
||
|
|
||
| class Trie: | ||
| def __init__(self): | ||
| # 모든 단어 탐색이 시작되는 최상위 노드 | ||
| self.root = TrieNode() | ||
|
|
||
| def insert(self, word: str) -> None: | ||
| current_node = self.root | ||
|
|
||
| # 단어의 각 문자를 따라가며 경로를 생성한다. | ||
| for char in word: | ||
| if char not in current_node.children: | ||
| current_node.children[char] = TrieNode() | ||
|
|
||
| current_node = current_node.children[char] | ||
|
|
||
| # 마지막 노드에 단어의 끝임을 표시한다. | ||
| current_node.is_end_of_word = True | ||
|
|
||
| def search(self, word: str) -> bool: | ||
| last_node = self._find_last_node(word) | ||
|
|
||
| # 경로가 존재하고, 마지막 노드에서 단어가 끝나야 한다. | ||
| return ( | ||
| last_node is not None | ||
| and last_node.is_end_of_word | ||
| ) | ||
|
|
||
| def startsWith(self, prefix: str) -> bool: | ||
| # 접두사는 해당 경로가 존재하기만 하면 된다. | ||
| return self._find_last_node(prefix) is not None | ||
|
|
||
| def _find_last_node(self, text: str): | ||
| current_node = self.root | ||
|
|
||
| # 문자열의 각 문자를 따라 마지막 노드까지 이동한다. | ||
| for char in text: | ||
| if char not in current_node.children: | ||
| return None | ||
|
|
||
| current_node = current_node.children[char] | ||
|
|
||
| return current_node |
|
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. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 동일 부분문제 재사용으로 중복 계산을 제거한다. 개선 제안: 현재 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| from functools import cache | ||
|
|
||
|
|
||
| class Solution: | ||
| def wordBreak(self, s: str, wordDict: List[str]) -> bool: | ||
| word_set = set(wordDict) | ||
|
|
||
| @cache | ||
|
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. 굉장히 편리한 기능이네요. 중복이 바로 처리 되네요 👍🏼
Member
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. 맞아요! 메모이제이션을 자동으로 처리해줘서 알고리즘 문제 풀이할 때 유용하더라고요 |
||
| def finding(start): | ||
| # 문자열 끝까지 단어들로 나누는 데 성공한 경우 | ||
| if start == len(s): | ||
| return True | ||
|
|
||
| # start부터 시작하는 모든 부분 문자열을 확인한다. | ||
| for end in range(start + 1, len(s) + 1): | ||
| current_word = s[start:end] | ||
|
|
||
| # 현재 단어가 사전에 있고, | ||
| # 나머지 문자열도 나눌 수 있다면 바로 종료한다. | ||
| if current_word in word_set and finding(end): | ||
| return True | ||
|
|
||
| # 어떤 방식으로도 나눌 수 없는 경우 | ||
| return False | ||
|
|
||
| return finding(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.
🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 최저가와 누적 이익을 유지하며 한 번의 순회로 최댓값을 구한다.
개선 제안: 현재 구현이 적절해 보입니다.