-
-
Notifications
You must be signed in to change notification settings - Fork 336
[liza0525] WEEK 08 Solutions #2566
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
f321976
9be1187
e793bf4
bbc338e
775b2af
c8b2d2a
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,46 @@ | ||
| from typing import Optional | ||
|
|
||
| # 7기 풀이 | ||
| # 시간 복잡도: O(V + E) | ||
| # - 모든 노드의 수와 모든 엣지의 수만큼 탐방하므로 그만큼의 시간이 걸림(V: 노드 수, E: 엣지 수) | ||
| # 공간 복잡도: O(V) | ||
| # - memo에 모든 노드를 복사해서 추가(V: 노드의 갯수) | ||
| class Solution: | ||
| def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: | ||
| memo = {} | ||
|
|
||
| def copy_graph(node): | ||
| if not node: | ||
| # 더이상 복사할 노드가 없다면 None을 return | ||
| return None | ||
|
|
||
| if node.val in memo: | ||
| # node의 값이 memo에 있다면 memo에 있는 값을 return | ||
| return memo[node.val] | ||
|
|
||
| # Node의 복사를 위해 새 노드 생성 및 node.val 값을 초기값으로 입력 | ||
| res_node = Node(node.val) | ||
| memo[node.val] = res_node # memo에 새로만든 객체를 value로 하여 저장(key는 node.val 값으로) | ||
|
|
||
| # neighbors도 복사, 이 때 copy_graph를 재귀로 호출하여 모든 neighbors들을 복사하도록 한다. | ||
| res_node.neighbors = [ | ||
| copy_graph(neighbor) for neighbor in node.neighbors | ||
| ] | ||
|
|
||
| # res_node를 return | ||
| return res_node | ||
|
|
||
| return copy_graph(node)# 다음과 같이 파이썬의 built-in 함수인 deepcopy를 사용하면 바로 문제가 풀리기도 했다. | ||
|
|
||
|
|
||
| # 정리 목적 | ||
| # 다음과 같이 파이썬의 built-in 함수인 deepcopy를 사용하면 바로 문제가 풀리기도 했다. | ||
| # 실제 deepcopy 구현이 memo를 이용하며 | ||
| # copier의 deepcopy를 호출하여 재귀와 비슷하게 구현했다는 것을 확인할 수 있었다 | ||
| # ref: https://github.com/python/cpython/blob/main/Lib/copy.py | ||
| from copy import deepcopy | ||
|
|
||
|
|
||
| class Solution: | ||
| def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: | ||
| return deepcopy(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 @@ | ||
| # 7기 풀이 | ||
| # 시간 복잡도: O(n * m) | ||
| # - text1의 길이 n과 text2의 길이 m만큼 순회하며 계산함 | ||
| # 공간 복잡도: O(n * m) | ||
| # - text1의 길이 n과 text2의 길이 m만큼의 2차 배열을 만들어 DP 계산을 하기 때문 | ||
| class Solution: | ||
| def longestCommonSubsequence(self, text1: str, text2: str) -> int: | ||
| dp = [ | ||
| [0 for _ in range(len(text2) + 1)] | ||
| for _ in range(len(text1) + 1) | ||
| ] | ||
|
|
||
| for i in range(1, len(text1) + 1): | ||
| for j in range(1, len(text2) + 1): | ||
| if text1[i - 1] == text2[j - 1]: | ||
| # text1의 i번째 문자와 text2의 j번째 문자가 같다면 | ||
| # 이 문자는 공통 subsequence에 포함될 수 있으므로 | ||
| # 두 문자를 제외한 나머지(dp[i-1][j-1])에 1을 더한 값이 현재의 LCS 길이가 된다 | ||
| dp[i][j] = dp[i - 1][j - 1] + 1 | ||
| else: | ||
| # 같지 않다면 둘 중 하나를 제외했을 때의 LCS 중 더 큰 값을 가져온다 | ||
| # dp[i][j-1]: text2의 j번째 문자를 제외한 경우 | ||
| # dp[i-1][j]: text1의 i번째 문자를 제외한 경우 | ||
| dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) | ||
|
|
||
| return dp[-1][-1] |
|
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,32 @@ | ||
| from collections import defaultdict | ||
|
|
||
|
|
||
| # 7기 풀이 | ||
| # 시간 복잡도: O(n) | ||
| # - right는 매 루프마다 전진하고 left도 최대 n번 전진하므로 합쳐서 O(n) | ||
| # 공간 복잡도: O(1) | ||
| # - s에 있는 문자들의 개수만큼 공간 복잡도가 늘어나겠지만 모두 대문자인 알파벳만이 key로 들어오므로 최대 26개 | ||
| class Solution: | ||
| # 기본 아이디어: 슬라이딩 윈도우를 사용하면서 | ||
| # 윈도우 내에 가장 많이 있는 문자의 개수와 k값을 더한 값이 윈도우를 초과하는지 아닌지를 확인 | ||
| def characterReplacement(self, s: str, k: int) -> int: | ||
| left = 0 # 윈도우 왼쪽 인덱스 값 | ||
| max_len = 0 # 문제의 답(변경 시 가장 긴 substring 길이) | ||
| char_dict = defaultdict(int) # 윈도우 내의 각 문자들 개수를 확인하기 위한 dict | ||
| max_char_cnt = 0 # 윈도우 내에 가장 많은 문자의 개수 그 자체(dict의 value() 메서드를 매번 호출하지 않게 하기 위함) | ||
|
|
||
| for right in range(len(s)): # 윈도우 오른쪽 인덱스 값 | ||
| char_dict[s[right]] += 1 # 오른쪽 인덱스에 해당하는 문자(예: A)에 대한 개수를 하나 올림 | ||
| max_char_cnt = max(max_char_cnt, char_dict[s[right]]) # 현재 윈도우에서 가장 많은 문자의 개수를 업데이트 | ||
|
|
||
| if max_char_cnt + k >= right - left + 1: | ||
| # 가장 많은 문자열 사이에 있는 다른 문자들의 개수가 k보다 작으면 변경 가능 | ||
| # -> 윈도우 내에서 가장 긴 repeating substring을 만들 수 있음 | ||
| max_len = max(max_len, right - left + 1) | ||
| else: | ||
| # 만들 수 없는 경우에는 기존 left의 문자를 char_dict로부터 하나 줄이고 | ||
| # left를 하나 옮긴다(새로운 윈도우를 만든다는 의미) | ||
| char_dict[s[left]] -= 1 | ||
| left += 1 | ||
|
|
||
| return max_len |
|
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,32 @@ | ||
| # 7기 풀이 | ||
| # 시간 복잡도: O(n ** 2) | ||
| # - for문으로 문자의 중심을 탐색 * while문으로 양쪽으로 뻗어나가며 문자열 탐색 | ||
| # 공간 복잡도: O(1) | ||
| # - 변수 몇 개만 사용 | ||
| class Solution: | ||
| # 해당 문제의 기본 아이디어: 중심 확장법을 이용하여 펠린드롬 찾기 | ||
| def countSubstrings(self, s: str) -> int: | ||
| res = 0 | ||
|
|
||
| # 펠린드롬의 길이가 짝수일 수도 홀수일 수도 있기 때문에 | ||
| # 2 * len(s)를 돌고 나눈 수 몫을 이용해서 중심을 먼저 잡는다 | ||
| for idx in range(2 * len(s) - 1): | ||
| # 펠린드롬 길이가 짝수일 때는 left와 right의 값이 1 차이나지만 | ||
| # 홀수일 때는 left == right 이다. | ||
| left = idx // 2 | ||
| right = (idx + 1) // 2 | ||
| delta = 0 | ||
|
|
||
| while ( | ||
| 0 <= left - delta # 왼쪽으로 확장했을 때의 index와 | ||
| and right + delta < len(s) # 오른쪽으로 확장했을 때의 index가 모두 s길이 범위 내에 있어야 함 | ||
| ): | ||
| if s[left - delta] == s[right + delta]: # 두 개가 같은 경우에는 펠린드롬 | ||
| res += 1 # 결과 값을 하나 추가하고 | ||
| delta += 1 # 확장을 위한 값을 1 올려준다 | ||
| else: | ||
| # 확장했을 때의 양 쪽 문자가 다른 경우에는 펠린드롬이 아니므로 break하고 | ||
| # 다음 루프에서 새로운 중심을 잡은 후 다시 펠린드롬을 찾는다. | ||
| break | ||
|
|
||
| return res |
|
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,25 @@ | ||
| # 7기 풀이 | ||
| # 시간 복잡도: O(1) | ||
| # - 해당 문제는 조건 자체가 32자릿수로 되어 있어 최대 32번까지만 계산 | ||
| # 공간 복잡도: O(1) | ||
| # - result, idx와 같은 변수만 사용 | ||
| class Solution: | ||
| def reverseBits(self, n: int) -> int: | ||
| result = 0 | ||
| idx = 0 # 자릿수 계산을 위한 앵커 | ||
|
|
||
| while n > 0: # n이 0이 되기 전까지 돌린다. | ||
| remainder = n % 2 # 수를 2로 나눴을 때의 나머지가 해당 자리수에서의 2진수 값 (0 or 1) | ||
| quotient = n // 2 # 몫은 다음 루프의 피젯수로 | ||
|
|
||
| if remainder: | ||
| # 나머지가 있는 경우에는 해당 2진수 자리수에 값이 있다. | ||
| # reversed한 값을 계산해야 하기 때문에 32 - idx - 1의 자릿수로 변환 | ||
| # (문제 조건 상 32자릿수가 기준) | ||
| # 변환한 후 result에 값을 더해준다. | ||
| result += 2 ** (32 - idx - 1) | ||
|
|
||
| n = quotient | ||
| idx += 1 # 자릿수를 하나 올린다 | ||
|
|
||
| return result |
|
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. 해당 문제는 7주차 문제였습니다! 저번주에 누락해서 못올려서 같이 올립니다 ㅠㅠ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # 7기 풀이 | ||
| # 시간 복잡도: O(m * n) | ||
| # - matrix 크기 만큼 시간 복잡도가 듦 | ||
| # 공간 복잡도: O(m + n) | ||
| # - 가로, 세로에서 각각 대상 인덱스를 저장 | ||
| class Solution: | ||
| def setZeroes(self, matrix: List[List[int]]) -> None: | ||
| """ | ||
| Do not return anything, modify matrix in-place instead. | ||
| """ | ||
| len_i = len(matrix) | ||
| len_j = len(matrix[0]) | ||
|
|
||
| # 0이 발견된 행/열 인덱스를 각각 저장하는 set | ||
| target_i_set, target_j_set = set(), set() | ||
|
|
||
| for i in range(len_i): | ||
| for j in range(len_j): | ||
| if matrix[i][j] != 0: | ||
| continue | ||
|
|
||
| # matrix[i][j]가 0인 경우에는 인덱스를 저장한다. | ||
| target_i_set.add(i) | ||
| target_j_set.add(j) | ||
|
|
||
|
|
||
| for i in range(len_i): | ||
| for j in range(len_j): | ||
| if matrix[i][j] == 0: | ||
| continue | ||
| if i in target_i_set or j in target_j_set: | ||
| # i, j 인덱스가 set에 있는 경우에는 0으로 변경한다. | ||
| matrix[i][j] = 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.
🏷️ 알고리즘 패턴 분석