-
-
Notifications
You must be signed in to change notification settings - Fork 305
[ZetBe] WEEK 03 solutions #2097
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,30 @@ | ||
| ''' | ||
| 문제: target이 될 때까지 candidates의 수를 더하는 모든 조합을 구하라. | ||
| 풀이: 백트래킹을 이용하여 조합을 구한다. 만약 현재 합이 target과 같다면 결과 리스트에 추가하고, 작다면 후보군을 순회하며 재귀적으로 탐색한다. | ||
| 시간복잡도: O(N^T), N은 후보군의 수, T는 target의 값 | ||
| 최악의 경우, 후보군의 수 N과 target의 값 T에 따라 모든 조합을 탐색해야 하므로 시간복잡도는 O(N^T)이다. | ||
| 공간복잡도: O(T) | ||
| 재귀 호출 스택과 현재 조합을 저장하는 데 최대 T개의 공간이 필요하므로 공간복잡도는 O(T)이다. | ||
| 사용한 자료구조: 리스트 | ||
| 참고로 함수의 호출 깊이는 target/min(candidates)로 제한된다. | ||
| ''' | ||
|
|
||
|
|
||
| class Solution: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
| candidates.sort() | ||
| s, now = [], [] | ||
|
|
||
| def find(start, score): | ||
| if score == target: | ||
| s.append(now[:]) | ||
| elif score < target: | ||
| for i in range(start, len(candidates)): | ||
| n = candidates[i] | ||
| now.append(n) | ||
| find(i, score+n) | ||
| now.pop() | ||
| find(0, 0) | ||
| return s | ||
|
|
||
|
|
|
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. 실제 문자열을 붙이기보다 경우의 수가 될 수 있는 것만 하나하나 체크해서, n번째 인덱스에 있는 글자까지 체크해본 결과 이 정도 경우의 수가 나왔다~ 하는 풀이로군요! 저는 이번 주에 못 푼 문제인데, 재귀를 통해 직접 문자열을 만들어 봄으로써 해결해보려고 했던 기억이 납니다. DP는 정말 생각지도 못한 곳에서 튀어나오네요. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| ''' | ||
| 문제: 숫자로 이루어진 문자열이 주어졌을 때, 이를 알파벳으로 디코딩하는 방법의 수를 구하는 문제(여기서 1은 'A', 2는 'B', ..., 26은 'Z'에 해당). | ||
| 풀이: 동적 계획법을 사용하여 각 위치까지의 디코딩 방법의 수를 계산 | ||
| 1. dp[i]를 문자열의 i번째 문자까지 디코딩하는 방법의 수라고 정의 | ||
| 2. 문자열의 i번째 문자가 '0'인 경우, 이전 문자가 '1' 또는 '2'인 경우에만 유효한 디코딩이 가능하므로 dp[i] = dp[i-2] | ||
| 3. 문자열의 i번째 문자와 이전 문자를 합쳐서 10~26 사이의 숫자가 되는 경우, dp[i] = dp[i-1] + dp[i-2] | ||
| 4. 그 외의 경우에는 dp[i] = dp[i-1] | ||
| 시간복잡도: O(n) | ||
| 문자열을 한 번 순회하며 dp 배열을 채우므로 전체 시간복잡도는 O(n)이다. | ||
| 공간복잡도: O(n) | ||
| dp 배열을 사용하므로 전체 공간복잡도는 O(n)이다. | ||
| 사용한 자료구조: 리스트 | ||
| ''' | ||
|
|
||
|
|
||
| class Solution: | ||
| def numDecodings(self, s: str) -> int: | ||
| string = list(s) | ||
| n = len(string) | ||
| dp = [0 for i in range(n)] | ||
| if string[0] == '0': | ||
| return 0 | ||
| if n == 1: | ||
| return 1 | ||
| if n == 2: | ||
| if 11 <= int(s) <= 19 or 21 <= int(s) <= 26: | ||
| return 2 | ||
| elif int(s) == 10 or int(s) == 20: | ||
| return 1 | ||
| elif '0' in string: | ||
| return 0 | ||
| else: | ||
| return 1 | ||
| dp[0] = 1 | ||
| if string[1] == '0' and 3 <= int(string[0]): | ||
| return 0 | ||
| if 11 <= int(string[0])*10 + int(string[1]) <= 19 or 21 <= int(string[0])*10 + int(string[1]) <= 26: | ||
| dp[1] = 2 | ||
| else: | ||
| dp[1] = 1 | ||
|
|
||
| for i in range(2, n): | ||
| if string[i] == '0' and (3 <= int(string[i-1]) or int(string[i-1]) == 0): | ||
| return 0 | ||
| if 11 <= int(string[i-1])*10 + int(string[i]) <= 19 or 21 <= int(string[i-1])*10 + int(string[i]) <= 26: | ||
| dp[i] = dp[i-2] + dp[i-1] | ||
| elif int(string[i-1])*10 + int(string[i]) == 10 or int(string[i-1])*10 + int(string[i]) == 20: | ||
| dp[i] = dp[i-2] | ||
| else: | ||
| dp[i] += dp[i-1] | ||
|
|
||
| return dp[n-1] | ||
|
|
||
|
|
||
| ''' | ||
| 너무 복잡하게 풀었기 때문에 ai에게 간결한 풀이를 알려달라해서 공유드립니다 | ||
|
|
||
| class Solution: | ||
| def numDecodings(self, s: str) -> int: | ||
| if not s or s[0] == '0': | ||
| return 0 | ||
|
|
||
| n = len(s) | ||
| # dp[i] : s의 앞 i글자를 해석하는 방법의 수 | ||
| dp = [0] * (n + 1) | ||
|
|
||
| # 초기값 설정 (빈 문자열은 1가지 방법, 첫 글자는 위에서 0체크 했으므로 1가지) | ||
| dp[0] = 1 | ||
| dp[1] = 1 | ||
|
|
||
| for i in range(2, n + 1): | ||
| # 1. 한 자리 숫자 해석 (1~9) | ||
| # 현재 숫자(s[i-1])가 '0'이 아니면, 이전 상태(dp[i-1])를 계승 | ||
| if s[i-1] != '0': | ||
| dp[i] += dp[i-1] | ||
|
|
||
| # 2. 두 자리 숫자 해석 (10~26) | ||
| # 이전 숫자와 현재 숫자를 합쳐서 10~26 사이라면, 전전 상태(dp[i-2])를 더함 | ||
| two_digit = int(s[i-2 : i]) | ||
| if 10 <= two_digit <= 26: | ||
| dp[i] += dp[i-2] | ||
|
|
||
| return dp[n] | ||
| ''' | ||
|
|
|
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. 이것도 저는 처음 풀 때 dp인지 몰랐는데, dp 배열을 생성하고 i번째 원소까지 고려했을 때의 최댓값을 저장한다 치면 dp라고 볼 수도 있겠더라고요. for문 1회 순회 방식으로 최적화가 될 수도 있었겠습니다만, 시간복잡도와 공간복잡도가 크게 달라지지는 않으므로 괜찮은 듯 합니다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| ''' | ||
| 문제: 최대 부분 배열의 합을 구하는 문제 | ||
| 풀이: | ||
| 1. 배열의 모든 수가 음수인 경우, 가장 큰 수를 반환 | ||
| 2. 배열의 처음부터 양수가 나올 때까지 인덱스를 이동 | ||
| 3. 양수가 나온 이후부터는 현재 합이 양수인 동안은 계속 더하고, 음수가 되면 다시 양수를 찾음 | ||
| 4. 매 단계마다 최대 합을 갱신 | ||
| 시간복잡도: O(n) | ||
| 배열을 한 번 순회하며 최대 부분 배열의 합을 계산하므로 전체 시간복잡도는 O(n)이다. | ||
| 공간복잡도: O(1) | ||
| 추가적인 공간을 사용하지 않으므로 전체 공간복잡도는 O(1)이다. | ||
| ''' | ||
|
|
||
|
|
||
| class Solution: | ||
| def maxSubArray(self, nums: List[int]) -> int: | ||
| n = len(nums) | ||
| answ = 0 | ||
| if max(nums) <= 0: | ||
| return max(nums) | ||
| i = 0 | ||
| while nums[i] < 0: | ||
| i += 1 | ||
| now = 0 | ||
| while i < n: | ||
| if now > 0 and i < n: | ||
| now += nums[i] | ||
| i += 1 | ||
| else: | ||
| while now <= 0 and i < n: | ||
| now = nums[i] | ||
| i += 1 | ||
| answ = max(answ, now) | ||
|
|
||
| return answ | ||
|
|
|
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. 저는 냅다 bin(n[2:]) 해서 나온 문자열에서 1을 셌습니다만, 사실 지금 풀어주신 이 방법이 정석에 가깝다고 생각합니다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| ''' | ||
| 문제: 정수 n이 주어졌을 때, n의 이진 표현에서 1의 개수를 반환하는 함수를 작성하세요. | ||
| 풀이: 2의 거듭제곱 수들을 미리 계산해두고, n에서 큰 수부터 빼가며 1의 개수를 세는 방식으로 풀이 | ||
| 시간복잡도: O(log n) | ||
| 2의 거듭제곱 수들을 미리 계산하는데 O(log n)이 걸리고, n에서 큰 수부터 빼가며 1의 개수를 세는 데도 O(log n)이 걸리므로 전체 시간복잡도는 O(log n)이다. | ||
| 공간복잡도: O(log n) | ||
| 2의 거듭제곱 수들을 저장하는 리스트를 사용하므로 전체 공간복잡도는 O(log n)이다. | ||
| 사용한 자료구조: 리스트 | ||
| ''' | ||
|
|
||
|
|
||
| class Solution: | ||
| def hammingWeight(self, n: int) -> int: | ||
| b = [] | ||
| now = 1 | ||
| answ = 0 | ||
| for i in range(35): | ||
| b.append(now) | ||
| now *= 2 | ||
|
|
||
| num = n | ||
| for i in range(34, -1, -1): | ||
| if num >= b[i]: | ||
| num -= b[i] | ||
| answ += 1 | ||
| return answ | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| ''' | ||
| 문제: 유효한 팰린드롬, 해당 문자열이 팰린드롬인지 확인하는 문제 | ||
| 풀이: 대소문자 구분 없이 알파벳과 숫자만을 고려하여 팰린드롬인지 확인 | ||
| 시간복잡도: O(n) | ||
| 문자열을 한 번 순회하며 유효한 문자만 추출하고, 다시 한번 순회하며 팰린드롬 여부를 확인하므로 전체 시간복잡도는 O(n)이다. | ||
| 공간복잡도: O(n) | ||
| 유효한 문자를 저장하기 위한 추가 리스트를 사용하므로 전체 공간복잡도는 O(n)이다. | ||
| 사용한 자료구조: 리스트 | ||
| ''' | ||
|
|
||
|
|
||
| class Solution: | ||
| def isPalindrome(self, s: str) -> bool: | ||
| string = [] | ||
| for i in s: | ||
| if 65 <= ord(i) <= 90: | ||
| string.append(i) | ||
| elif 97 <= ord(i) <= 122: | ||
| string.append(chr(ord(i)-32)) | ||
| elif 48 <= ord(i) <= 57: | ||
| string.append(i) | ||
|
|
||
|
|
||
| for i in range(len(string)): | ||
| if string[i] != string[len(string)-1-i]: | ||
| return False | ||
| return True | ||
|
|
||
|
|
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.
저는 두 함수를 분리하고 싶다는 생각 때문에 파라미터가 많이 늘었는데, 파이썬의 특성상 이렇게 그냥 함수 하나 안에서 nested function을 정의해서 하면 그것도 괜찮겠구나 라는 생각도 들었습니다.