Skip to content

Commit a8bda09

Browse files
authored
Merge pull request #1193 from taurus09318976/main
2 parents ebec677 + 5e5ebe7 commit a8bda09

File tree

5 files changed

+198
-0
lines changed

5 files changed

+198
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#이 문제는 정수 배열이 주어졌을 대, 배열에 중복 값이 있으면 true, 모든 요소가 고유하면, false를 반환
2+
3+
class Solution:
4+
def containsDuplicate(self, nums: List[int]):
5+
#빈 집합 생성
6+
array = set()
7+
8+
#배열의 각 요소를 순회하며, 현재 요소가 이미 집합에 있는지 확인.
9+
#있다면, 중복 값이 있으므로, True를 반환
10+
#없다면, 현재 요소를 집합에 추가
11+
#Example 1의 경우 :
12+
#1 -> 집합에 추가 / 2 -> 집합에 추가
13+
#3 -> 집합에 추가 / 1 -> 이미 집합에 있으므로 True 반환
14+
for i in range(len(nums)):
15+
if nums[i] in array:
16+
return True
17+
array.add(nums[i])
18+
19+
#모든 요소를 검사한 후에도 중복이 발견되지 않았다면, False를 반환
20+
return False
21+
22+
#이 코드는 시간 복잡도 O(n)과 공간 복잡도 O(n)으로 문제를 효율적으로 해결함

house-robber/taurus09318976.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#이 문제의 제약조건 : 1) 인접한 집은 방문할 수 없음, 2)각 집에는 일정 금액의 돈이 있음, 3) 최대로 훔칠 수 있는 금액을 구해야 함
2+
#이 문제는 각 위치에서 두 가지 선택이 있음 : 1) 현재 집을 털기(이전 집은 털 수 없음), 2) 현재 집을 털지 않기(이전 집은 털 수 있음)
3+
#Example 1.의 예시를 들어 생각해보면,
4+
5+
class Solution:
6+
def rob(self, nums: List[int]) -> int:
7+
n = len(nums)
8+
9+
#특수 케이스 처리 : 베열이 비어 있거나, 길이가 1인 경우
10+
if n == 0:
11+
return 0
12+
if n == 1:
13+
return nums[0]
14+
15+
#첫번째 집의 금액을 저장 prev2 = 1
16+
#이 값은 0번째 집까지 털 수 있는 최대 금액을 의미
17+
prev2 = nums[0]
18+
#첫 두 집 중 최대 금액을 저장 max(1, 2) = 2
19+
prev1 = max(nums[0], nums[1])
20+
21+
#i = 2 (세번째 집, value = 3)
22+
for i in range(2, n):
23+
#현재 집을 털거나 털지 않는 경우 중 최대값 :
24+
#현재 집 털기 : prev2 + num[2] = 1 + 3 = 4
25+
#현재 집 안 털기 : prev1 = 2
26+
#current = max(2, 4) = 4
27+
current = max(prev1, prev2 + nums[i])
28+
#다음 반복을 위해 값 업데이트
29+
#prev2, prev1 = 2, 4
30+
prev2, prev1 = prev1, current
31+
32+
return prev1
33+
#i = 3까지 했을 때 최대로 훔칠 수 있는 금액은 4
34+
35+
#시간 복잡도
36+
#O(n), n은 집의 수
37+
#공간 복잡도
38+
#O(1) DP 배열을 사용하는 방법보다 변수 2개만 사용하는 방식이
39+
#공간 복잡도는 동일하면서 공간을 절약할 수 있어 더 효율적임
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# 이 문제는 배열에서 가장 자주 등장하는 k개의 요소를 찾는 문제임
2+
# 각 숫자의 1) 등장 횟수를 계산 -> 2) 등장 횟수에 따라 정렬 -> 3) 가장 빈번한 k개의 요소를 반환의 순서로 풀이 해야 함
3+
4+
5+
class Solution:
6+
def topKFrequent(self, nums: List[int], k: int):
7+
#Use Counter if you are using Python3 and you want the number of occurrences for each element:
8+
count = Counter(nums)
9+
#most_common 메서드는 Counter 객체에서 요소들의 빈도를 분석하고 정렬할 때 매우 유용
10+
#만일 매개변수 k가 없으면 모든 요소를 빈도수 순서대로 반환
11+
#기본적으로 빈도수가 높은 것부터 낮은 것 순서(내림차순)
12+
most_common_pairs = count.most_common(k)
13+
14+
result = []
15+
for element, frequency in most_common_pairs:
16+
result.append(element)
17+
18+
return result
19+
20+
#시간 복잡도 분석
21+
#Counter(nums): O(n), 여기서 n은 배열의 길이
22+
#count.most_common(k): 내부적으로 모든 요소를 정렬하므로 O(m log m)이 소요됨. 여기서 m은 고유한 요소의 수(최악의 경우 m = n).
23+
#결과 리스트 구성: O(k)
24+
#전체 시간 복잡도: O(n + m log m) ≈ O(n log n) (최악의 경우)
25+
26+
#공간 복잡도 분석
27+
#Counter 객체: O(m), 여기서 m은 고유한 요소의 수.
28+
#most_common 결과: O(k)
29+
#최종 결과 리스트: O(k)
30+
#전체 공간 복잡도: O(m + k) ≈ O(n) (최악의 경우)
31+
32+
#다른 방식과의 비교
33+
#sorted와 딕셔너리 사용 방식:
34+
#시간 복잡도: O(n log n) - Counter 방식과 동일
35+
#공간 복잡도: O(n) - Counter 방식과 동일
36+
#힙(heap) 사용 방식:
37+
#시간 복잡도: O(n + m log k) ≈ O(n log k) - k가 작을 때 더 효율적
38+
#공간 복잡도: O(m + k) ≈ O(n)
39+
#버킷 정렬 방식:
40+
#시간 복잡도: O(n) - 가장 효율적
41+
#공간 복잡도: O(n)
42+
43+
#결론
44+
#most_common 방식은 간결하고 가독성이 좋지만, 시간 복잡도 면에서는 버킷 정렬 방식보다 덜 효율적.
45+
#대부분의 실제 사례에서는 성능 차이가 미미하고, Python의 내장 함수들이 최적화되어 있어 most_common 방식도 충분히 빠름.
46+
#극도로 큰 데이터셋이나 성능이 매우 중요한 경우에는 버킷 정렬 방식을 고려할 수 있음.
47+
#most_common은 코드가 간결하고 직관적이라는 장점이 있음.
48+
#결론적으로, 작은 규모의 문제나 코드 가독성이 중요한 경우에는 most_common 방식이 좋은 선택이지만, 최고의 성능이 필요한 경우에는 버킷 정렬 방식이 더 효율적.
49+
50+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# 이 문제는 배열에서 가장 자주 등장하는 k개의 요소를 찾는 문제임
2+
# 각 숫자의 1) 등장 횟수를 계산 -> 2) 등장 횟수에 따라 정렬 -> 3) 가장 빈번한 k개의 요소를 반환의 순서로 풀이 해야 함
3+
4+
5+
class Solution:
6+
def topKFrequent(self, nums: List[int], k: int):
7+
#Use Counter if you are using Python3 and you want the number of occurrences for each element:
8+
count = Counter(nums)
9+
#most_common 메서드는 Counter 객체에서 요소들의 빈도를 분석하고 정렬할 때 매우 유용
10+
#만일 매개변수 k가 없으면 모든 요소를 빈도수 순서대로 반환
11+
#기본적으로 빈도수가 높은 것부터 낮은 것 순서(내림차순)
12+
most_common_pairs = count.most_common(k)
13+
14+
result = []
15+
for element, frequency in most_common_pairs:
16+
result.append(element)
17+
18+
return result
19+
20+
#시간 복잡도 분석
21+
#Counter(nums): O(n), 여기서 n은 배열의 길이
22+
#count.most_common(k): 내부적으로 모든 요소를 정렬하므로 O(m log m)이 소요됨. 여기서 m은 고유한 요소의 수(최악의 경우 m = n).
23+
#결과 리스트 구성: O(k)
24+
#전체 시간 복잡도: O(n + m log m) ≈ O(n log n) (최악의 경우)
25+
26+
#공간 복잡도 분석
27+
#Counter 객체: O(m), 여기서 m은 고유한 요소의 수.
28+
#most_common 결과: O(k)
29+
#최종 결과 리스트: O(k)
30+
#전체 공간 복잡도: O(m + k) ≈ O(n) (최악의 경우)
31+
32+
#다른 방식과의 비교
33+
#sorted와 딕셔너리 사용 방식:
34+
#시간 복잡도: O(n log n) - Counter 방식과 동일
35+
#공간 복잡도: O(n) - Counter 방식과 동일
36+
#힙(heap) 사용 방식:
37+
#시간 복잡도: O(n + m log k) ≈ O(n log k) - k가 작을 때 더 효율적
38+
#공간 복잡도: O(m + k) ≈ O(n)
39+
#버킷 정렬 방식:
40+
#시간 복잡도: O(n) - 가장 효율적
41+
#공간 복잡도: O(n)
42+
43+
#결론
44+
#most_common 방식은 간결하고 가독성이 좋지만, 시간 복잡도 면에서는 버킷 정렬 방식보다 덜 효율적.
45+
#대부분의 실제 사례에서는 성능 차이가 미미하고, Python의 내장 함수들이 최적화되어 있어 most_common 방식도 충분히 빠름.
46+
#극도로 큰 데이터셋이나 성능이 매우 중요한 경우에는 버킷 정렬 방식을 고려할 수 있음.
47+
#most_common은 코드가 간결하고 직관적이라는 장점이 있음.
48+
#결론적으로, 작은 규모의 문제나 코드 가독성이 중요한 경우에는 most_common 방식이 좋은 선택이지만, 최고의 성능이 필요한 경우에는 버킷 정렬 방식이 더 효율적.

two-sum/taurus09318976.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#이 문제는 결국 value 와 합쳤을 때 target이 되는 보수를 구해야 함
2+
class Solution:
3+
def twoSum(self, nums: List[int], target: int):
4+
array = {}
5+
6+
#enumerate(nums)를 사용하여 배열의 각 요소와 그 인덱스를 동시에 가져옴
7+
#i는 인덱스, value는 해당 위치의 값
8+
#Example 1의 경우:
9+
#i=0, value = 2
10+
##i=1, value = 7
11+
for i, value in enumerate(nums):
12+
#diff = 9 - 2 = 7
13+
##diff = 9 - 7 = 2
14+
diff = target - value
15+
#diff(7)이 array딕셔너리에 있는지 확인 -> 빈 딕셔너리이므로 없음
16+
##diff(2)이 array딕셔너리에 있는지 확인 -> 있음 array[2] = 0
17+
if diff in array:
18+
##return (0, 1) 반환. 루프 종료.
19+
return (array[diff], i)
20+
#현재 array = {2:0}
21+
array[value] = i
22+
return
23+
24+
25+
#시간복잡도
26+
#이 알고리즘은 해시맵(딕셔너리)을 활용하여 배열을 한 번만 순회하므로 O(n) 시간 복잡도로 문제를 해결
27+
#각 숫자를 처리하면서 현재 숫자와 더해서 target이 되는 값(diff)이 이미 처리된 숫자들 중에 있는지 확인
28+
#있다면 두 숫자의 인덱스를 반환
29+
#없다면 현재 숫자와 인덱스를 딕셔너리에 저장하고 다음 숫자로 넘어감
30+
31+
#공간 복잡도 분석:
32+
#최악의 경우, 배열의 모든 요소를 딕셔너리에 저장해야 함
33+
#예를 들어, 답이 배열의 마지막 두 요소에 있다면 n-2개의 요소를 딕셔너리에 저장해야 함
34+
#이는 O(n)의 추가 공간을 필요로 합니다.
35+
#i, value, diff 등과 같은 변수들은 상수 공간만 차지하므로 이는 O(1)의 공간을 필요로 함
36+
#따라서 전체 공간 복잡도는 O(n) + O(1) = O(n)입니다.
37+
#이 알고리즘은 시간 복잡도를 O(n)으로 개선하기 위해 O(n)의 추가 공간(딕셔너리)을 사용하는 시간-공간 트레이드오프의 예임.
38+
#O(n²) 시간 복잡도의 브루트 포스 접근법과 비교하면, 시간을 절약하기 위해 약간의 추가 공간을 사용하는 것임.
39+

0 commit comments

Comments
 (0)