Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions contains-duplicate/ZetBe.py
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)으로 줄일 수 있다.
'''
Comment on lines +1 to +17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와.. 이렇게 정리하시면서 문제를 푸시는게 되게 도움이 많이 될거 같아요! 👍


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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정렬을 하시고, 비교하면서 판단하는 방법이군요!

저는 집합을 이용해서 크기를 비교하는 방식으로 접근했는데요!
다른 접근법도 생각해볼 수 있어서 좋았던 것 같습니다 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자바스크립트의 Set을 쓰시는 군요! 프로필 살짝 보긴했는데, 저도 프론트엔도 공부하고 있습니다

다만 알고리즘 한정으로는 파이썬이 더 익숙해서 쓰긴하는데, Set은 잊고 있었네요..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 자주 까먹습니다..ㅎ



33 changes: 33 additions & 0 deletions house-robber/ZetBe.py
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]
Copy link
Member

@prgmr99 prgmr99 Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 방향으로 접근하실 수 있다는 점에서 새로운 시각을 배울 수 있었습니다.

dp[i]의 값을 i번째 집을 반드시 털었을 때, 0번째 집부터 i번째 집까지 털 수 있는 최대 금액으로 설정하신 것 같은데요..!

도움이 되실지는 모르겠지만,,, 리뷰를 작성해보겠습니다..!

dp[i]를 i번째 집까지 털었을 때의 최대 금액으로 정의하면 어떨까요?

이렇게 하면 i번째 집에서 선택은 딱 두 가지가 되어요

  1. i번째 집을 턴다 (i-1은 못 텀)
    -> nums[i] + dp[i-2]

  2. i번째 집을 안 턴다 (i-1까지 턴 값)
    -> dp[i-1]

그럼 점화식이 dp[i] = max(nums[i] + dp[i-2], dp[i-1])로 될 것 같습니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반드시 턴다는 것이 아닌 털 수도 있고, 아니면 바로 이전 값을 가져올 수도 있게 하는 것이군요!

이러면 확실히 초반 식이 덜 복잡해지겠습니다

기존 코드는 -3부터니까요

전체 리뷰 감사합니다!

이 pr은 병합할게요!

return max(dp[len(nums)-1], dp[len(nums)-2])

36 changes: 36 additions & 0 deletions longest-consecutive-sequence/ZetBe.py
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

34 changes: 34 additions & 0 deletions top-k-frequent-elements/ZetBe.py
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

되게 간결해보이네요..!!

  • key=lambda x:x[1], 요 코드는 어떤 역할을 하는건가요??
  • a는 정렬한 배열을 나타는 것으로 이해했는데 변수명을 명확하게 해주시면 더 좋을 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

딕셔너리가 키:밸류로 이루어져 있는데, 이를 정렬하기 위해 아이템을 기준으로 정렬한다는 의미입니다!

다만 파이썬이 딕셔너리를 2차원 리스트로 인식하는지, key=lambda x:x[1]로 작성해야 1번째 인덱스인 밸류값을 기준으로 오름차순/내림차순 정렬을 합니다.

아무래도 빈도수를 기준으로 내림차순해야하기 때문에, 빈도수(밸류)가 높은 순으로 해당 빈도수를 가진 키 값을 정답 코드로 작성했습니다.

그리고 a는 임시 리스트로 arr을 더 줄인 변수명이였는데, 시간이 없다고 생각하고 굉장히 직관적으로 작성하다보니 나온 변수명입니다. 나중에 명확하게 작성해보겠습니다.

for i in range(k):
answ.append(a[i][0])
return answ

52 changes: 52 additions & 0 deletions two-sum/ZetBe.py
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O(N)으로 딕셔너리를 활용해 잘 해결하신 것 같아요!
혹시 for 문을 한 번만 사용하는 방식은 어떨까요?

맵을 먼저 다 채우는 대신, 순회하면서
(1) 짝이 있는지 먼저 확인하고 (2) 나를 맵에 등록하는 방식이에요.

이렇게 하면 target == i*2 같은 엣지 케이스를 위한 별도 분기문 없이도 코드가 조금 더 간결해질 수 있을 것 같아서 참고차 의견 드립니다! 🫡

++ 추가로 해당 파일은 하단에 개행문자가 필요없는지 궁금합니다..!
다른 파일들과 달리 없는 것 같아서 확인차 전달드려요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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]

확실히 먼저 저장하기 전에 확인하고 리턴하는게 더 간결해지네요! 다시한번 감사합니다

마지막으로 개행문자가 깃허브에서 있다고 판단한건지 해당 파일에 -표시가 없어서 그냥 내버려 뒀는데, 혹시 모르니까 새로 코드 추가해서 개행문자 추가 후 커밋하겠습니다

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉.. 빠르게 시도해보셨군요! 고생하셨습니다!! 👍

순회하는 배열의 길이나 for문을 돌리는 횟수에 따라서 다르겠지만,
돌리는 횟수가 많아지면 많아질수록 아무래도 시간복잡도에 영향을 미칠 수 밖에 없다고 생각합니다.

그래서 저도 습관처럼 위에 작업해주신 방법대로 적게 돌려보려고 합니다 :)

저도 빠르게 다른 문제들도 풀고 리뷰드리도록 하겠습니다 😊

return answ