-
-
Notifications
You must be signed in to change notification settings - Fork 305
[ZetBe] Week 01 Solutions #1986
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
d232c4e
29ab473
d9c84e7
2e36ae9
b63c248
74858ea
25e9a07
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,29 @@ | ||
| ''' | ||
| 문제: 배열의 중복을 찾는 문제 | ||
| 풀이: 정렬 후 인접한 원소끼리 비교하여 중복 여부 확인 중복이 없다면 False 반환 | ||
|
|
||
| 시간복잡도: O(n log n) | ||
| sort()의 시간복잡도는 O(n log n)이고, for문은 O(n)이므로, | ||
| 전체 시간복잡도는 O(n log n) | ||
|
|
||
| 공간복잡도: O(1) | ||
| nums.sort()는 제자리 정렬이므로, 추가적인 공간을 사용하지 않는다. | ||
| 또한 num 변수를 하나만 사용하므로, 전체 공간복잡도는 O(1) | ||
|
|
||
| 사용한 자료구조: 리스트 | ||
|
|
||
| 만약 파이썬의 딕테이션과 같이 조회 시 O(1)인 자료구조를 사용한다면, | ||
| 시간복잡도를 O(n)으로 줄일 수 있다. | ||
| ''' | ||
|
|
||
| class Solution: | ||
| def containsDuplicate(self, nums: List[int]) -> bool: | ||
| nums.sort() | ||
| num = nums[0] | ||
| for i in range(1, len(nums)): | ||
| if num == nums[i]: | ||
| return True | ||
| num = nums[i] | ||
| return False | ||
|
Comment on lines
+20
to
+27
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. 자바스크립트의 Set을 쓰시는 군요! 프로필 살짝 보긴했는데, 저도 프론트엔도 공부하고 있습니다 다만 알고리즘 한정으로는 파이썬이 더 익숙해서 쓰긴하는데, Set은 잊고 있었네요..
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. 저도 자주 까먹습니다..ㅎ |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| ''' | ||
| 문제: 연속한 집이 아닌 집을 털 때 얻을 수 있는 최대 금액을 구하는 문제 | ||
| 풀이: 다이나믹 프로그래밍 | ||
| 초기 값 설정 후, | ||
| dp[i] = max(dp[i-2], dp[i-3]) + nums[i] 점화식 설정 | ||
| 한집, 혹은 두집을 건너서 털었을 경우, 둘 중 가장 큰값을 고름 | ||
|
|
||
| 시간복잡도: O(n) | ||
| 점점 순차적으로 dp 배열을 채워나가므로 O(n) | ||
| 공간복잡도: O(n) | ||
| dp 배열을 하나 생성하므로 O(n) | ||
|
|
||
| 사용한 자료구조: 리스트 | ||
|
|
||
| ''' | ||
|
|
||
|
|
||
| class Solution: | ||
| def rob(self, nums: List[int]) -> int: | ||
| dp = [0 for i in range(len(nums))] | ||
| if len(nums) == 1: | ||
| return nums[0] | ||
| elif len(nums) == 2: | ||
| return max(nums[0], nums[1]) | ||
| elif len(nums) == 3: | ||
| return max(nums[0], nums[1], nums[0]+nums[2]) | ||
|
|
||
| dp[0], dp[1], dp[2] = nums[0], nums[1], nums[0]+nums[2] | ||
|
|
||
| for i in range(3, len(nums)): | ||
| dp[i] = max(dp[i-2], dp[i-3]) + nums[i] | ||
|
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. 이런 방향으로 접근하실 수 있다는 점에서 새로운 시각을 배울 수 있었습니다. dp[i]의 값을 도움이 되실지는 모르겠지만,,, 리뷰를 작성해보겠습니다..! dp[i]를 이렇게 하면 i번째 집에서 선택은 딱 두 가지가 되어요
그럼 점화식이 dp[i] = max(nums[i] + dp[i-2], dp[i-1])로 될 것 같습니다.
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. 반드시 턴다는 것이 아닌 털 수도 있고, 아니면 바로 이전 값을 가져올 수도 있게 하는 것이군요! 이러면 확실히 초반 식이 덜 복잡해지겠습니다 기존 코드는 -3부터니까요 전체 리뷰 감사합니다! 이 pr은 병합할게요! |
||
| return max(dp[len(nums)-1], dp[len(nums)-2]) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| ''' | ||
| 문제: 배열에서 가장 긴 연속된 수열의 길이를 찾는 문제 | ||
| 풀이: 딕셔너리의 키값을 기준으로 정렬 후, 연속된 수열의 길이를 계산 | ||
| (중복된 값은 딕셔너리로 제거 후 처리) | ||
|
|
||
| 시간복잡도: O(k log k + N) (k는 딕셔너리의 키 개수, N은 nums의 길이) | ||
| 공간복잡도: O(N) (공간의 크기는 nums의 길이에 비례) | ||
|
|
||
| 사용한 자료구조: 딕셔너리, 리스트 | ||
| ''' | ||
|
|
||
|
|
||
| class Solution: | ||
| def longestConsecutive(self, nums: List[int]) -> int: | ||
| d = {} | ||
| answ = 1 | ||
| if len(nums) > 0: | ||
| for i in nums: | ||
| if i not in d: | ||
| d[i] = 0 | ||
|
|
||
| a = sorted(d.keys()) | ||
| now = a[0] | ||
| an = 1 | ||
| for i in range(1, len(a)): | ||
| t = a[i] | ||
| if now+1 == t: | ||
| an += 1 | ||
| else: | ||
| an = 1 | ||
| now = a[i] | ||
| answ = max(answ, an) | ||
|
|
||
| return answ | ||
| return 0 | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| ''' | ||
| 문제: Top K Frequent Elements | ||
| nums 배열에서 가장 자주 등장하는 k개의 요소를 반환하라. | ||
| 풀이: 딕셔너리를 이용하여 각 숫자의 등장 빈도를 저장한 후, | ||
| 빈도수를 기준으로 정렬하여 상위 k개의 숫자를 반환한다. | ||
|
|
||
| 시간복잡도: O(k log k + n) (n은 nums의 길이, k는 반환할 요소의 개수) | ||
| 최악의 경우, O(n log n)이 될 수 있지만, k가 작을 때는 O(k log k + n)이 더 적합하다. | ||
| 공간복잡도: O(n) | ||
| 딕셔너리에 각 숫자의 빈도를 저장하는데 O(n)의 공간이 필요하므로 전체 공간복잡도는 O(n) | ||
|
|
||
| 사용한 자료구조: 딕셔너리, 리스트 | ||
| ''' | ||
|
|
||
|
|
||
|
|
||
| import heapq | ||
|
|
||
| class Solution: | ||
| def topKFrequent(self, nums: List[int], k: int) -> List[int]: | ||
| arr = {} | ||
| answ = [] | ||
| a = [] | ||
| for i in nums: | ||
| if i in arr: | ||
| arr[i] += 1 | ||
| else: | ||
| arr[i] = 1 | ||
|
|
||
| a = sorted(arr.items(), key=lambda x:x[1], reverse=True) | ||
|
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. 딕셔너리가 다만 파이썬이 딕셔너리를 2차원 리스트로 인식하는지, 아무래도 빈도수를 기준으로 내림차순해야하기 때문에, 빈도수(밸류)가 높은 순으로 해당 빈도수를 가진 키 값을 정답 코드로 작성했습니다. 그리고 |
||
| for i in range(k): | ||
| answ.append(a[i][0]) | ||
| return answ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| ''' | ||
| 문제: 배열 중에서 두 수를 더해서 타겟 넘버가 되는 인덱스를 반환하라 | ||
| 한 인덱스를 두번 사용할 수 없으며, 답은 하나만 존재한다. | ||
| 풀이: 딕셔너리를 이용하여 각 숫자의 인덱스를 저장한 후, | ||
| 타겟 넘버에서 각 숫자를 뺀 값이 딕셔너리에 있는지 확인 | ||
| 그리고 그 숫자가 두 번 이상 등장하는지 확인 | ||
| (절반으로 나누어 떨어지는 경우 고려) | ||
|
|
||
| 시간복잡도: O(n) | ||
| 딕셔너리에 각 숫자를 저장하는데 O(n), 겹치지 않은 수를 탐색하는데 최악의 경우 O(n) | ||
| 각 숫자에 대해 타겟 넘버에서 뺀 값이 딕셔너리에 있는지 확인하는데 O(1)이므로, 전체 시간복잡도는 O(n) | ||
|
|
||
| 공간복잡도: O(n) | ||
| 딕셔너리에 각 숫자를 저장하는데 O(n)의 공간이 필요하므로 전체 공간복잡도는 O(n) | ||
|
|
||
| 사용한 자료구조: 딕셔너리 | ||
|
|
||
| 일반 리스트를 사용하여 탐색할 경우, 시간복잡도가 O(n^2)이 될 수 있다. | ||
| 최악의 경우, n*(n-1)/2번의 탐색이 필요한데, 이는 결국 O(n^2)이다. | ||
| ''' | ||
|
|
||
| # 추가로 코드리뷰를 통해 가독성 개선한 코드 | ||
| ''' | ||
| for i in range(len(nums)): | ||
| if target - nums[i] in d: | ||
| return [d[target-nums[i]][0], i] | ||
| if nums[i] not in d: | ||
| d[nums[i]] = [i] | ||
|
|
||
| else: | ||
|
|
||
| d[nums[i]] += [i] | ||
| ''' | ||
|
|
||
| class Solution: | ||
| def twoSum(self, nums: List[int], target: int) -> List[int]: | ||
| answ = [] | ||
| d = {} | ||
| for i in range(len(nums)): | ||
| if nums[i] not in d: | ||
| d[nums[i]] = [i] | ||
| else: | ||
| d[nums[i]] += [i] | ||
| print(d) | ||
| for i in d.keys(): | ||
| if target-i in d and len(d[target-i]) == 1 and target != i*2: | ||
| answ = [d[target-i][0], d[i][0]] | ||
| return answ | ||
| if target-i in d and len(d[target-i]) >= 2 and target == i*2: | ||
| answ = [d[target-i][0], d[i][1]] | ||
|
Comment on lines
+39
to
+50
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. O(N)으로 딕셔너리를 활용해 잘 해결하신 것 같아요! 맵을 먼저 다 채우는 대신, 순회하면서 이렇게 하면 target == i*2 같은 엣지 케이스를 위한 별도 분기문 없이도 코드가 조금 더 간결해질 수 있을 것 같아서 참고차 의견 드립니다! 🫡 ++ 추가로 해당 파일은 하단에 개행문자가 필요없는지 궁금합니다..!
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. 이게 예전에 알고리즘 수업을 듣다가 문득 for문을 여러 번 돌려도 상수배니까 상관없나..?라는 생각이 들어서 일단 수행시간에 문제가 없다면 그냥 제 관점에서 나름대로 역할을 분리하여 작성하곤 했는데, 그냥 for문 안에 붙여도 되겠구나 싶네요 공유해주셔서 감사합니다! 코드는 그래서 이렇게 바꿔봤습니다. 이 코드도 정답으로 나옵니다. for i in range(len(nums)):
if target - nums[i] in d:
return [d[target-nums[i]][0], i]
if nums[i] not in d:
d[nums[i]] = [i]
else:
d[nums[i]] += [i]확실히 먼저 저장하기 전에 확인하고 리턴하는게 더 간결해지네요! 다시한번 감사합니다 마지막으로 개행문자가 깃허브에서 있다고 판단한건지 해당 파일에 -표시가 없어서 그냥 내버려 뒀는데, 혹시 모르니까 새로 코드 추가해서 개행문자 추가 후 커밋하겠습니다
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. 헉.. 빠르게 시도해보셨군요! 고생하셨습니다!! 👍 순회하는 배열의 길이나 for문을 돌리는 횟수에 따라서 다르겠지만, 그래서 저도 습관처럼 위에 작업해주신 방법대로 적게 돌려보려고 합니다 :) 저도 빠르게 다른 문제들도 풀고 리뷰드리도록 하겠습니다 😊 |
||
| return answ | ||
|
|
||
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.
와.. 이렇게 정리하시면서 문제를 푸시는게 되게 도움이 많이 될거 같아요! 👍