Skip to content

[taurus09318976] WEEK 01 solutions #1193

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

Merged
merged 6 commits into from
Apr 5, 2025
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
22 changes: 22 additions & 0 deletions contains-duplicate/taurus09318976.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#이 문제는 정수 배열이 주어졌을 대, 배열에 중복 값이 있으면 true, 모든 요소가 고유하면, false를 반환

class Solution:
def containsDuplicate(self, nums: List[int]):
#빈 집합 생성
array = set()

#배열의 각 요소를 순회하며, 현재 요소가 이미 집합에 있는지 확인.
#있다면, 중복 값이 있으므로, True를 반환
#없다면, 현재 요소를 집합에 추가
#Example 1의 경우 :
#1 -> 집합에 추가 / 2 -> 집합에 추가
#3 -> 집합에 추가 / 1 -> 이미 집합에 있으므로 True 반환
for i in range(len(nums)):
if nums[i] in array:
return True
array.add(nums[i])

#모든 요소를 검사한 후에도 중복이 발견되지 않았다면, False를 반환
return False

#이 코드는 시간 복잡도 O(n)과 공간 복잡도 O(n)으로 문제를 효율적으로 해결함
39 changes: 39 additions & 0 deletions house-robber/taurus09318976.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#이 문제의 제약조건 : 1) 인접한 집은 방문할 수 없음, 2)각 집에는 일정 금액의 돈이 있음, 3) 최대로 훔칠 수 있는 금액을 구해야 함
#이 문제는 각 위치에서 두 가지 선택이 있음 : 1) 현재 집을 털기(이전 집은 털 수 없음), 2) 현재 집을 털지 않기(이전 집은 털 수 있음)
#Example 1.의 예시를 들어 생각해보면,

class Solution:
def rob(self, nums: List[int]) -> int:
n = len(nums)

#특수 케이스 처리 : 베열이 비어 있거나, 길이가 1인 경우
if n == 0:
return 0
if n == 1:
return nums[0]

#첫번째 집의 금액을 저장 prev2 = 1
#이 값은 0번째 집까지 털 수 있는 최대 금액을 의미
prev2 = nums[0]
#첫 두 집 중 최대 금액을 저장 max(1, 2) = 2
prev1 = max(nums[0], nums[1])

#i = 2 (세번째 집, value = 3)
for i in range(2, n):
#현재 집을 털거나 털지 않는 경우 중 최대값 :
#현재 집 털기 : prev2 + num[2] = 1 + 3 = 4
#현재 집 안 털기 : prev1 = 2
#current = max(2, 4) = 4
current = max(prev1, prev2 + nums[i])
#다음 반복을 위해 값 업데이트
#prev2, prev1 = 2, 4
prev2, prev1 = prev1, current

return prev1
#i = 3까지 했을 때 최대로 훔칠 수 있는 금액은 4

#시간 복잡도
#O(n), n은 집의 수
#공간 복잡도
#O(1) DP 배열을 사용하는 방법보다 변수 2개만 사용하는 방식이
#공간 복잡도는 동일하면서 공간을 절약할 수 있어 더 효율적임
50 changes: 50 additions & 0 deletions longest-consecutive-sequence/taurus09318976.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 이 문제는 배열에서 가장 자주 등장하는 k개의 요소를 찾는 문제임
# 각 숫자의 1) 등장 횟수를 계산 -> 2) 등장 횟수에 따라 정렬 -> 3) 가장 빈번한 k개의 요소를 반환의 순서로 풀이 해야 함


class Solution:
def topKFrequent(self, nums: List[int], k: int):
#Use Counter if you are using Python3 and you want the number of occurrences for each element:
count = Counter(nums)
#most_common 메서드는 Counter 객체에서 요소들의 빈도를 분석하고 정렬할 때 매우 유용
#만일 매개변수 k가 없으면 모든 요소를 빈도수 순서대로 반환
#기본적으로 빈도수가 높은 것부터 낮은 것 순서(내림차순)
most_common_pairs = count.most_common(k)

result = []
for element, frequency in most_common_pairs:
result.append(element)

return result

#시간 복잡도 분석
#Counter(nums): O(n), 여기서 n은 배열의 길이
#count.most_common(k): 내부적으로 모든 요소를 정렬하므로 O(m log m)이 소요됨. 여기서 m은 고유한 요소의 수(최악의 경우 m = n).
#결과 리스트 구성: O(k)
#전체 시간 복잡도: O(n + m log m) ≈ O(n log n) (최악의 경우)

#공간 복잡도 분석
#Counter 객체: O(m), 여기서 m은 고유한 요소의 수.
#most_common 결과: O(k)
#최종 결과 리스트: O(k)
#전체 공간 복잡도: O(m + k) ≈ O(n) (최악의 경우)

#다른 방식과의 비교
#sorted와 딕셔너리 사용 방식:
#시간 복잡도: O(n log n) - Counter 방식과 동일
#공간 복잡도: O(n) - Counter 방식과 동일
#힙(heap) 사용 방식:
#시간 복잡도: O(n + m log k) ≈ O(n log k) - k가 작을 때 더 효율적
#공간 복잡도: O(m + k) ≈ O(n)
#버킷 정렬 방식:
#시간 복잡도: O(n) - 가장 효율적
#공간 복잡도: O(n)

#결론
#most_common 방식은 간결하고 가독성이 좋지만, 시간 복잡도 면에서는 버킷 정렬 방식보다 덜 효율적.
#대부분의 실제 사례에서는 성능 차이가 미미하고, Python의 내장 함수들이 최적화되어 있어 most_common 방식도 충분히 빠름.
#극도로 큰 데이터셋이나 성능이 매우 중요한 경우에는 버킷 정렬 방식을 고려할 수 있음.
#most_common은 코드가 간결하고 직관적이라는 장점이 있음.
#결론적으로, 작은 규모의 문제나 코드 가독성이 중요한 경우에는 most_common 방식이 좋은 선택이지만, 최고의 성능이 필요한 경우에는 버킷 정렬 방식이 더 효율적.


48 changes: 48 additions & 0 deletions top-k-frequent-elements/taurus09318976.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 이 문제는 배열에서 가장 자주 등장하는 k개의 요소를 찾는 문제임
# 각 숫자의 1) 등장 횟수를 계산 -> 2) 등장 횟수에 따라 정렬 -> 3) 가장 빈번한 k개의 요소를 반환의 순서로 풀이 해야 함


class Solution:
def topKFrequent(self, nums: List[int], k: int):
#Use Counter if you are using Python3 and you want the number of occurrences for each element:
count = Counter(nums)
#most_common 메서드는 Counter 객체에서 요소들의 빈도를 분석하고 정렬할 때 매우 유용
#만일 매개변수 k가 없으면 모든 요소를 빈도수 순서대로 반환
#기본적으로 빈도수가 높은 것부터 낮은 것 순서(내림차순)
most_common_pairs = count.most_common(k)

result = []
for element, frequency in most_common_pairs:
result.append(element)

return result

#시간 복잡도 분석
#Counter(nums): O(n), 여기서 n은 배열의 길이
#count.most_common(k): 내부적으로 모든 요소를 정렬하므로 O(m log m)이 소요됨. 여기서 m은 고유한 요소의 수(최악의 경우 m = n).
#결과 리스트 구성: O(k)
#전체 시간 복잡도: O(n + m log m) ≈ O(n log n) (최악의 경우)

#공간 복잡도 분석
#Counter 객체: O(m), 여기서 m은 고유한 요소의 수.
#most_common 결과: O(k)
#최종 결과 리스트: O(k)
#전체 공간 복잡도: O(m + k) ≈ O(n) (최악의 경우)

#다른 방식과의 비교
#sorted와 딕셔너리 사용 방식:
#시간 복잡도: O(n log n) - Counter 방식과 동일
#공간 복잡도: O(n) - Counter 방식과 동일
#힙(heap) 사용 방식:
#시간 복잡도: O(n + m log k) ≈ O(n log k) - k가 작을 때 더 효율적
#공간 복잡도: O(m + k) ≈ O(n)
#버킷 정렬 방식:
#시간 복잡도: O(n) - 가장 효율적
#공간 복잡도: O(n)

#결론
#most_common 방식은 간결하고 가독성이 좋지만, 시간 복잡도 면에서는 버킷 정렬 방식보다 덜 효율적.
#대부분의 실제 사례에서는 성능 차이가 미미하고, Python의 내장 함수들이 최적화되어 있어 most_common 방식도 충분히 빠름.
#극도로 큰 데이터셋이나 성능이 매우 중요한 경우에는 버킷 정렬 방식을 고려할 수 있음.
#most_common은 코드가 간결하고 직관적이라는 장점이 있음.
#결론적으로, 작은 규모의 문제나 코드 가독성이 중요한 경우에는 most_common 방식이 좋은 선택이지만, 최고의 성능이 필요한 경우에는 버킷 정렬 방식이 더 효율적.
39 changes: 39 additions & 0 deletions two-sum/taurus09318976.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#이 문제는 결국 value 와 합쳤을 때 target이 되는 보수를 구해야 함
class Solution:
def twoSum(self, nums: List[int], target: int):
array = {}

#enumerate(nums)를 사용하여 배열의 각 요소와 그 인덱스를 동시에 가져옴
#i는 인덱스, value는 해당 위치의 값
#Example 1의 경우:
#i=0, value = 2
##i=1, value = 7
for i, value in enumerate(nums):
#diff = 9 - 2 = 7
##diff = 9 - 7 = 2
diff = target - value
#diff(7)이 array딕셔너리에 있는지 확인 -> 빈 딕셔너리이므로 없음
##diff(2)이 array딕셔너리에 있는지 확인 -> 있음 array[2] = 0
if diff in array:
##return (0, 1) 반환. 루프 종료.
return (array[diff], i)
#현재 array = {2:0}
array[value] = i
return


#시간복잡도
#이 알고리즘은 해시맵(딕셔너리)을 활용하여 배열을 한 번만 순회하므로 O(n) 시간 복잡도로 문제를 해결
#각 숫자를 처리하면서 현재 숫자와 더해서 target이 되는 값(diff)이 이미 처리된 숫자들 중에 있는지 확인
#있다면 두 숫자의 인덱스를 반환
#없다면 현재 숫자와 인덱스를 딕셔너리에 저장하고 다음 숫자로 넘어감

#공간 복잡도 분석:
#최악의 경우, 배열의 모든 요소를 딕셔너리에 저장해야 함
#예를 들어, 답이 배열의 마지막 두 요소에 있다면 n-2개의 요소를 딕셔너리에 저장해야 함
#이는 O(n)의 추가 공간을 필요로 합니다.
#i, value, diff 등과 같은 변수들은 상수 공간만 차지하므로 이는 O(1)의 공간을 필요로 함
#따라서 전체 공간 복잡도는 O(n) + O(1) = O(n)입니다.
#이 알고리즘은 시간 복잡도를 O(n)으로 개선하기 위해 O(n)의 추가 공간(딕셔너리)을 사용하는 시간-공간 트레이드오프의 예임.
#O(n²) 시간 복잡도의 브루트 포스 접근법과 비교하면, 시간을 절약하기 위해 약간의 추가 공간을 사용하는 것임.