-
-
Notifications
You must be signed in to change notification settings - Fork 361
[okyungjin] WEEK 03 Solutions #2711
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
f9fd527
5f1817f
2d4fff1
bb613eb
f16fb02
d2f8a5f
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,73 @@ | ||
| # https://leetcode.com/problems/combination-sum/ | ||
|
|
||
| # [접근] | ||
| # 처음에는 1부터 target 까지 결과를 저장하는 dp를 떠올렸다. 이 문제는 조합의 개수를 구하는게 아니라 전체 후보군을 구하는 문제이기 때문에 dfs로 백트래킹하도록 접근법을 바꿨다. | ||
|
|
||
| class Solution_01: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
| result = [] | ||
| size = len(candidates) | ||
|
|
||
| # start_idx: 탐색 시작 인덱스 | ||
| # total: 현재까지의 합 | ||
| # combination: 선택된 숫자들 배열 | ||
| def dfs(start_idx: int, total: int, combination: List[int]) -> None: | ||
| # 합이 target과 같으면 정답 배열에 추가하고 종료 | ||
| if total == target: | ||
| result.append(combination) | ||
| return | ||
|
|
||
| # 합이 target 넘었으면 종료 | ||
| if total > target: | ||
| return | ||
|
|
||
| # 숫자를 여러번 사용할 수 있으므로 반복문을 start_idx 부터 시작한다. | ||
| for i in range(start_idx, size): | ||
| num = candidates[i] | ||
| dfs( | ||
| i, | ||
| total + num, # num 을 더한 합으로 호출 | ||
| combination + [num]) # 얕은 복사된 combination을 인자로 넘긴다. | ||
|
|
||
| dfs(0, 0, []) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| # 위 풀이와 거의 유사하다. | ||
| # 백트래킹시에 배열이 매번 깊은 복사되는 비효율이 있어서 result 배열에 담을 때만 복사하도록 했다. | ||
| class Solution: | ||
| def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: | ||
|
Comment on lines
+37
to
+40
Member
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. 얕은 복사라고 적어야 하는데 깊은 복사라고 잘못 적었습니다. |
||
| result = [] | ||
| size = len(candidates) | ||
|
|
||
| # start_idx: 탐색 시작 인덱스 | ||
| # total: 현재까지의 합 | ||
| # combination: 선택된 숫자들 배열 | ||
| def dfs(start_idx: int, total: int, combination: List[int]) -> None: | ||
| # result | ||
| if total == target: | ||
| # combination을 얕은 복사 후 추가한다 | ||
| result.append(combination.copy()) | ||
| return | ||
|
|
||
| # 합이 target 넘었으면 종료 | ||
| if total > target: | ||
| return | ||
|
|
||
| # 숫자를 여러번 사용할 수 있으므로 반복문을 start_idx 부터 시작한다. | ||
| for i in range(start_idx, size): | ||
| num = candidates[i] | ||
|
|
||
| # 반환 전 num 추가 | ||
| # -> 정답 찾으면 result에 추가할 때 combination 얕은 복사 필요 | ||
| combination.append(num) | ||
|
|
||
| dfs(i, total + num, combination) | ||
|
|
||
| # 반환 후에 num 제거 | ||
| combination.pop() | ||
|
|
||
| dfs(0, 0, []) | ||
|
|
||
| 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. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 비트를 하나씩 확인하며 1의 개수를 누적합니다. 간단하고 직관적입니다. 개선 제안: 현 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # https://leetcode.com/problems/number-of-1-bits/description/ | ||
|
|
||
| # n을 2진법으로 변환했을 때 1의 개수를 세는 문제이다. | ||
| # `n & 1` 연산을 통해 마지막 비트가 1인지 검사해서 count를 증가시킨다. | ||
| # 확인한 비트를 `n >> 1` 으로 한자리 버린다. | ||
|
|
||
| class Solution: | ||
| def hammingWeight(self, n: int) -> int: | ||
| count = 0 | ||
|
|
||
| while n: | ||
| # `n & 1` 연산을 통해 마지막 비트가 1인지 검사해서 count를 증가시킨다. | ||
|
|
||
| # 1011 | ||
| # & 0001 | ||
| # ------ | ||
| # 0001 -> 결과 1이 된다 | ||
| count += n & 1 | ||
|
|
||
| # 비트 한자리 이동한다 (1011 -> 0101) | ||
| n = n >> 1 | ||
|
|
||
| return count |
|
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,85 @@ | ||
| # [문제] | ||
| # https://leetcode.com/problems/valid-palindrome/description/ | ||
|
|
||
| # [요구사항] | ||
| # 주어진 문자열이 팰린드롬인지 판별하는 함수를 작성한다. | ||
| # 팰린드롬이란? | ||
| # 1. 대문자가 있다면 소문자로 변환한다 | ||
| # 2. 알파벳 or 숫자가 아니라면 제거한다. | ||
| # 3. 앞뒤로 읽었을 때 동일한 문자여야 한다. | ||
|
|
||
| # [접근법] | ||
| # - 문자열 전체를 공백 제거 & 소문자로 변환하지 않고, 투 포인터를 통해 lazy하게 연산한다. | ||
| # - 문자열 양 끝에 포인터를 선언하고, alphanumeric인 경우 소문자로 변환 후 두 문자를 비교한다. 다르면 False 리턴 | ||
| # - alphanumeric이 아니면 alphanumeric 문자가 나올 때까지 이동한다. | ||
|
|
||
| # [복잡도] | ||
| # 시간 복잡도: O(N) | ||
| # 공간 복잡도: O(1) | ||
| class SolutionA: | ||
| def isPalindrome(self, s: str) -> bool: | ||
|
|
||
| # 문자열 양 끝 포인터 선언 | ||
| left = 0 | ||
| right = len(s) - 1 | ||
|
|
||
| while left < right: | ||
| # alphanumeric 이 나올 때까지 왼쪽 포인터를 우측으로 이동 | ||
| while left < right and not isAlphaNumeric(s[left]): | ||
| left += 1 | ||
|
|
||
| # alphanumeric 이 나올 때까지 오른쪽 포인터를 좌측으로 이동 | ||
| while left < right and not isAlphaNumeric(s[right]): | ||
| right -= 1 | ||
|
|
||
| # 소문자로 변환해서 비교 | ||
| if s[left].lower() != s[right].lower(): | ||
| return False | ||
|
|
||
| left += 1 | ||
| right -= 1 | ||
|
|
||
| return True | ||
|
|
||
| # 문자가 alphanumeric인지 판별하는 함수 | ||
| # A ~ Z 혹은 a ~ z 혹은 0 ~ 9 이면 True를 반환 | ||
| def isAlphaNumeric(ch: str) -> bool: | ||
| return ( | ||
| ord('A') <= ord(ch) <= ord('Z') | ||
| or ord('a') <= ord(ch) <= ord('z') | ||
| or ord('0') <= ord(ch) <= ord('9') | ||
| ) | ||
|
|
||
|
|
||
| # SolutuionB: SoulutionA와 같은 로직인데 `isalnum` 내장함수 사용 | ||
| # isAlphaNumeric 함수를 직접 구현하고 찾아보니 파이썬 내장함수가 있었다. | ||
|
|
||
| # [복잡도] | ||
| # 시간 복잡도: O(N) | ||
| # 공간 복잡도: O(1) | ||
| class Solution: | ||
| def isPalindrome(self, s: str) -> bool: | ||
| # 문자열 양 끝 포인터 선언 | ||
| left = 0 | ||
| right = len(s) - 1 | ||
|
|
||
| while left < right: | ||
| # alphanumeric 이 나올 때까지 왼쪽 포인터를 우측으로 이동 | ||
| while left < right and not s[left].isalnum(): | ||
| left += 1 | ||
|
|
||
| # alphanumeric 이 나올 때까지 오른쪽 포인터를 좌측으로 이동 | ||
| while left < right and not s[right].isalnum(): | ||
| right -= 1 | ||
|
|
||
| # 소문자로 변환해서 비교 | ||
| if s[left].lower() != s[right].lower(): | ||
| return False | ||
|
|
||
| left += 1 | ||
| right -= 1 | ||
|
|
||
| return True | ||
|
|
||
|
|
||
| print(Solution().isPalindrome('A man, a plan, a canal: Panama')) |
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.
🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
풀이 1:
Solution_01.combinationSum— Time: O(n^k) / Space: O(k)피드백: 백트래킹으로 모든 가능한 조합을 탐색하고, 중복 조합 생성을 방지하기 위해 시작 인덱스를 고정했습니다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 2:
Solution.combinationSum— Time: O(n^k) / Space: O(k)피드백: 두 번째 구현은 매 재귀에서 불필요한 리스트 복사를 줄여 메모리 사용을 개선합니다.
개선 제안: 현재 구현이 적절해 보입니다.