-
-
Notifications
You must be signed in to change notification settings - Fork 362
[okyungjin] WEEK 02 solutions #2683
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
bbf0f2a
3e04e11
91141ca
dfd817b
5105a32
a3585d3
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,63 @@ | ||
| # [문제 링크] | ||
| # https://leetcode.com/problems/3sum/ | ||
|
|
||
| # [요구사항] | ||
| # - nums 배열이 주어지고, nums[i] + nums[j] + nums[k] 를 더했을 때 0이 는 숫자 3개의 배열을 반환한다. | ||
| # - 결과 집합은 1개 이상임 | ||
| # - 정답에 중복이 있으면 안 된다! | ||
| # - `3 <= nums.length <= 3000` | ||
|
|
||
| # [접근법] | ||
| # 1. 포인터를 3개 선언하고, 하나를 고정한 채로 2Sum으로 나머지 해를 찾는다. | ||
| # 2. 중복 제거를 위해 포인터를 좌우로 움직여줘야 한다. | ||
|
|
||
| # 시간 복잡도: O(N^2) | ||
| # 공간 복잡도: O(N) | ||
|
|
||
| class Solution: | ||
| def threeSum(self, nums: list[int]) -> list[list[int]]: | ||
| size = len(nums) | ||
| answer = [] | ||
|
|
||
| # 포인터를 사용하기 위해 배열을 정렬한다 | ||
| nums.sort() | ||
|
|
||
| # 포인터 3개 중 하나를 고정한다. | ||
| for i in range(size - 2): | ||
| # 중복 제거 | ||
| if i > 0 and nums[i] == nums[i - 1]: | ||
| continue | ||
|
|
||
| # 나머지 두 개의 포인터를 left, right라 한다. 양 끝을 할당 | ||
| left = i + 1 | ||
| right = size - 1 | ||
|
|
||
| while left < right: | ||
| total = nums[i] + nums[left] + nums[right] | ||
|
|
||
| # 합이 0보다 작으면 더 큰 숫자를 더해줘야 하므로 left를 우측으로 이동 | ||
| if total < 0: | ||
| left += 1 | ||
|
|
||
| # 합이 0보다 크면 더 작은 숫자를 더해줘야 하므로 right을 좌측으로 이동 | ||
| elif total > 0: | ||
| right -= 1 | ||
|
|
||
| # 숫자 3개가 합쳐서 0인 경우 (해를 찾음) | ||
| else: | ||
| # 정답에 추가하고 | ||
| answer.append([nums[i], nums[left], nums[right]]) | ||
|
|
||
| # 포인터를 안쪽으로 한칸 이동한다. | ||
| left += 1 | ||
| right -= 1 | ||
|
|
||
| # left 중복 제거를 위해 이동 | ||
| while left < right and nums[left] == nums[left - 1]: | ||
| left += 1 | ||
|
|
||
| # right 중복 제거를 위해 이동 | ||
| while left < right and nums[right] == nums[right + 1]: | ||
| right -= 1 | ||
|
|
||
| return answer |
|
okyungjin marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||||||
| # 시간 복잡도: O(N) | ||||||||||
| # 공간 복잡도: O(1) | ||||||||||
|
|
||||||||||
| # [요구사항] | ||||||||||
| # 1. 계단의 개수 n이 주어진다. | ||||||||||
| # 2. 계단은 1칸 또는 2칸 올라갈 수 있다. | ||||||||||
| # 3. 마지막 칸에 도달할 수 있는 경우의 수를 반환한다. | ||||||||||
|
|
||||||||||
| # [접근법] | ||||||||||
| # 1. 계단에 올라올 수 있는 경우의 수는 전전칸까지의 경우의 수 (prev2) + 전칸까지의 경우의 수 (prev1) 를 더한 값이다. | ||||||||||
| class Solution: | ||||||||||
| def climbStairs(self, n: int) -> int: | ||||||||||
| if n <= 2: | ||||||||||
| return n | ||||||||||
|
|
||||||||||
| prev2 = 1 # 전전칸 까지의 경우의 수 | ||||||||||
| prev1 = 2 # 전칸 까지의 경우의 수 | ||||||||||
|
|
||||||||||
| for _ in range(2, 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. 개인적으로는 3번째 계단에서 시작하는 거면, 3이라고 명시하는 걸 더 선호해서요. 이렇게도 쓸 수 있을 것 같아요.
Suggested change
|
||||||||||
| curr = prev2 + prev1 # 현재 계단 | ||||||||||
| prev2 = prev1 | ||||||||||
| prev1 = curr | ||||||||||
|
Comment on lines
+20
to
+22
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.
Suggested change
파이썬이니까 동시 할당을 활용하는 방법도 있을 것 같아요.
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. 감사합니다! 개인적으로 curr로 작성해주는게 가독성이 더 좋다고 생각해서 풀어서 작성했습니다. |
||||||||||
|
|
||||||||||
| return prev1 | ||||||||||
|
okyungjin marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # [요구사항] | ||
| # 정수배열 nums가 주어진다. | ||
| # answer[i]는 nums[i]를 제외한 나머지 숫자의 곱이다. | ||
| # answer 배열을 반환한다. | ||
| # 단, 나눗셈 없이 O(N)으로 알고리즘을 작성해야한다. | ||
|
|
||
| # [접근법] | ||
| # 처음에는 조합(combinations)으로 모든 경우를 구하려 했지만 | ||
| # 시간 복잡도가 O(N²) 이상이 되어 시간 초과가 발생했습니다. | ||
|
|
||
| # (고민해보다가 AI의 도움을 받아 힌트를 얻었습니다.) | ||
| # 각 위치에서 왼쪽 누적 곱(prefix)과 오른쪽 누적 곱(suffix)을 각각 구해 곱하는 방식으로 풀었습니다. | ||
|
|
||
| # 예시) | ||
| # nums = [1, 2, 3, 4] | ||
| # prefix = [1, 1, 2, 6] -> 각 위치의 왼쪽 원소들의 곱 | ||
| # suffix를 뒤에서부터 누적하면서 answer에 곱해줍니다. | ||
| # 최종 answer 배열 [24, 12, 8, 6] | ||
|
|
||
| # 시간 복잡도 : O(N) | ||
| # 공간 복잡도 : O(1) (정답 배열 제외) | ||
| from typing import List | ||
|
|
||
| class Solution: | ||
| def productExceptSelf(self, nums: List[int]) -> List[int]: | ||
| size = len(nums) | ||
|
|
||
| answer = [] | ||
|
|
||
| prefix = 1 | ||
| for i in range(size): | ||
| answer.append(prefix) | ||
| prefix *= nums[i] | ||
|
|
||
| suffix = 1 | ||
| for j in reversed(range(size)): | ||
| answer[j] *= suffix | ||
| suffix *= nums[j] | ||
|
|
||
| return answer | ||
|
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. 시간이 얼마 안 남아서 남은 것들 후딱 풀겠습니다. 늦은 시간인데도 확인해주셔서 감사해요ㅠㅠ! |
||
|
|
||
| print(Solution().productExceptSelf([1,2,3,4])) | ||
| print(Solution().productExceptSelf([2,5,3,7])) | ||
|
okyungjin marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,41 @@ | ||||||||||||||||||||||||||||||
| # https://leetcode.com/problems/valid-anagram/description/ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # [요구사항] | ||||||||||||||||||||||||||||||
| # 문자열 두 개가 주어졌을 때 애너그램이 맞는지 아닌지를 반환하는 문제 | ||||||||||||||||||||||||||||||
| # 애너그램이란? 하나의 단어나 구에 들어 있는 글자들을 모두, 각각 정확히 한 번씩만 사용해서 순서를 바꾸어 만든 다른 단어나 구를 의미한다. | ||||||||||||||||||||||||||||||
| # 두 문자열이 애너그램이면 True, 아니면 False 반환 | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # [접근법] | ||||||||||||||||||||||||||||||
| # 1. 길이가 다르면 애너그램이 아니므로 바로 False를 반환한다. | ||||||||||||||||||||||||||||||
| # 2. s의 문자 개수를 센 뒤, t를 순회하며 하나씩 차감한다. | ||||||||||||||||||||||||||||||
| # 3. 없는 문자이거나 개수가 부족한 문자를 만나면 False를 반환한다. | ||||||||||||||||||||||||||||||
| # 4. 모든 문자를 정상적으로 처리하면 True를 반환한다. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Time: O(N) | ||||||||||||||||||||||||||||||
| # Space: O(N) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| from collections import Counter | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class Solution01: | ||||||||||||||||||||||||||||||
| def isAnagram(self, s: str, t: str) -> bool: | ||||||||||||||||||||||||||||||
| if len(s) != len(t): | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| counter = Counter(s) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| for char in t: | ||||||||||||||||||||||||||||||
| if counter[char] >= 1: | ||||||||||||||||||||||||||||||
| counter[char] -= 1 | ||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||
|
Comment on lines
+21
to
+32
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.
Suggested change
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. @dahyeong-yun 오오 이런 방법도 있네요. 파이썬은 == 으로 비교하면 참조가 아니라 값으로 비교하는 특성이 있군요. 감사합니다 ㅎㅎ!! |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class Solution: | ||||||||||||||||||||||||||||||
| def isAnagram(self, s: str, t: str) -> bool: | ||||||||||||||||||||||||||||||
| if len(s) != len(t): | ||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # 파이썬은 == 로 값을 비교한다. | ||||||||||||||||||||||||||||||
| # 참조로 비교하려면 is 사용 | ||||||||||||||||||||||||||||||
| return Counter(s) == Counter(t) | ||||||||||||||||||||||||||||||
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.
🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 정렬로 정렬된 배열에서 두 포인터를 움직이며 모든 해를 탐색한다. 중복 제거 로직이 포함되어 있다.
개선 제안: 현재 구현이 충분히 효율적이며, 필요 시 초기 i 반복에서 nums[i]가 양수인 경우의 조기에 종료하는 등의 미세 최적화를 고려할 수 있다.
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.
결과는 공간 복잡도에 포함시키지 않나보네요