Skip to content

Commit 9f7fc53

Browse files
committed
feat: 4개 문제 풀이 추가 (two-sum, contains-duplicate 등)
1 parent c10802e commit 9f7fc53

File tree

4 files changed

+267
-0
lines changed

4 files changed

+267
-0
lines changed

contains-duplicate/unpo88.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class Solution:
2+
def containsDuplicate(self, nums: list[int]) -> bool:
3+
return len(set(nums)) != len(nums)
4+
5+
"""
6+
================================================================================
7+
풀이 과정
8+
================================================================================
9+
10+
[1차 시도] Counter를 이용한 Hash Table
11+
────────────────────────────────────────────────────────────────────────────────
12+
1. Hashing을 이용해서 숫자 Count를 한 것에서 개수가 2이상인 것을 뽑으면 되겠는데?
13+
14+
nums_count = Counter(nums)
15+
for count in nums_count.values():
16+
if count >= 2:
17+
return True
18+
return False
19+
20+
2. 속도가 많이 느리네 더 좋은 방법은 없을까?
21+
22+
23+
[2차 시도] Early Return with Hash Table
24+
────────────────────────────────────────────────────────────────────────────────
25+
3. 해싱을 만들면서 2개 이상이면 즉각 return 하도록 구현해볼까?
26+
27+
nums_count = defaultdict(int)
28+
for num in nums:
29+
nums_count[num] += 1
30+
31+
if nums_count[num] == 2:
32+
return True
33+
return False
34+
35+
4. 그래도 속도가 많이 개선되지는 않았네?
36+
37+
38+
[최종 개선] Set을 이용한 비교
39+
────────────────────────────────────────────────────────────────────────────────
40+
5. 속도를 획기적으로 개선하려면 어떻게 접근해볼 수 있을까?
41+
6. set으로 중복을 제거한다음에 개수를 비교해볼 수 있지 않으려나?
42+
43+
return len(set(nums)) != len(nums)
44+
45+
7. 조금 더 속도가 빨라졌다.
46+
47+
48+
[성능 분석]
49+
────────────────────────────────────────────────────────────────────────────────
50+
8. 근데 잘 생각해보면 Big-O 시간 복잡도는 O(n) 일 것 같은데
51+
9. 그러면 Early Return을 해주는 방법 2가 더 빠르다고 생각했는데 왜 3번 방식이 더 빠를까?
52+
10. set이 CPython 내부에서 C 코드로 실행되는구나 OK
53+
"""
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
class Solution:
2+
def longestConsecutive(self, nums: list[int]) -> int:
3+
if not nums:
4+
return 0
5+
6+
nums_set = set(nums)
7+
max_length = 0
8+
9+
for num in nums_set:
10+
# 조기 종료: 남은 숫자보다 max_length가 크면 더 이상 불가능
11+
if max_length >= len(nums_set):
12+
break
13+
14+
# 수열의 시작점인지 확인 (이전 값이 없어야 함)
15+
if num - 1 not in nums_set:
16+
current_num = num
17+
current_length = 1
18+
19+
# 연속된 다음 숫자들을 찾아가며 길이 계산
20+
while current_num + 1 in nums_set:
21+
current_num += 1
22+
current_length += 1
23+
24+
max_length = max(max_length, current_length)
25+
26+
return max_length
27+
28+
"""
29+
================================================================================
30+
풀이 과정
31+
================================================================================
32+
33+
[문제 분석] 연속 수열의 최대 길이 찾기
34+
────────────────────────────────────────────────────────────────────────────────
35+
1. 연속 수열의 길이를 반환해야하는데
36+
2. O(n) 시간 내에 동작하는 알고리즘으로 만들어야하네
37+
→ 시간을 획기적으로 줄여야하니까 set을 사용하면 좋으려나?
38+
39+
40+
[구현 전략] 기준점 기반 탐색
41+
────────────────────────────────────────────────────────────────────────────────
42+
3. 연속 수열이니까 특정 기준점으로부터 + 1인 값이 얼마나 반복되는지 최대 길이를 구해야겠다.
43+
4. 특정 기준점이 여러 번 바뀔 수도 있는데, set으로 중복 제거를 했으니까 문제 없어보인다.
44+
5. 기준점을 수열의 숫자가 시작하는 시점으로 잡으려면, 수열의 이전 값이 존재하지 않아야겠네
45+
46+
nums_set = set(nums)
47+
max_length = 0
48+
49+
for num in nums_set:
50+
if num - 1 not in nums_set: # 수열의 시작점인 경우만
51+
current = num
52+
length = 1
53+
54+
while current + 1 in nums_set:
55+
current += 1
56+
length += 1
57+
58+
max_length = max(max_length, length)
59+
60+
return max_length
61+
62+
6. 더 개선할 부분이 있나?
63+
7. Claude에게 코드로 질문
64+
8. Early Return 조건을 활용하라고 답변 (배열이 없는 경우와 남은 숫자보다 max_length가 더 큰 경우)
65+
66+
def longestConsecutive(self, nums: list[int]) -> int:
67+
if not nums:
68+
return 0
69+
70+
nums_set = set(nums)
71+
max_length = 0
72+
73+
for num in nums_set:
74+
# 조기 종료: 남은 숫자보다 max_length가 크면 더 이상 불가능
75+
if max_length >= len(nums_set):
76+
break
77+
78+
if num - 1 not in nums_set:
79+
current_num = num
80+
current_length = 1
81+
82+
while current_num + 1 in nums_set:
83+
current_num += 1
84+
current_length += 1
85+
86+
max_length = max(max_length, current_length)
87+
88+
return max_length
89+
"""

top-k-frequent-elements/unpo88.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from collections import Counter
2+
3+
4+
class Solution:
5+
def topKFrequent(self, nums: list[int], k: int) -> list[int]:
6+
nums_count = Counter(nums)
7+
return [key for key, _ in nums_count.most_common(k)]
8+
9+
"""
10+
================================================================================
11+
풀이 과정
12+
================================================================================
13+
14+
[1차 시도] Counter의 most_common() 활용
15+
────────────────────────────────────────────────────────────────────────────────
16+
1. k개의 빈도가 가장 높은 요소?
17+
2. Counter 함수를 이용해서 K개 개수를 세면 될듯?
18+
19+
nums_count = Counter(nums)
20+
return [key for key, _ in nums_count.most_common(k)]
21+
22+
[성능 분석]
23+
3. Counter.most_common() 메서드는 내부는 어떻게 구현되어있지?
24+
25+
26+
def most_common(self, n=None):
27+
'''List the n most common elements and their counts from the most
28+
common to the least. If n is None, then list all element counts.
29+
30+
>>> Counter('abracadabra').most_common(3)
31+
[('a', 5), ('b', 2), ('r', 2)]
32+
33+
'''
34+
# Emulate Bag.sortedByCount from Smalltalk
35+
if n is None:
36+
return sorted(self.items(), key=_itemgetter(1), reverse=True)
37+
38+
# Lazy import to speedup Python startup time
39+
import heapq
40+
return heapq.nlargest(n, self.items(), key=_itemgetter(1))
41+
42+
4. n이 없으면 모든 요소를 빈도수 순서대로 반환
43+
5. Heap 기반 알고리즘을 사용하고 있네? (Min Heap)
44+
6. _itemgetter(1)은 카운트를 기준으로 정렬하기 위한 것
45+
"""

two-sum/unpo88.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
class Solution:
2+
def twoSum(self, nums: list[int], target: int) -> list[int]:
3+
num_to_index = {}
4+
5+
for i, num in enumerate(nums):
6+
diff = target - num
7+
8+
if diff in num_to_index:
9+
j = num_to_index[diff]
10+
return [i, j]
11+
12+
num_to_index[num] = i
13+
14+
"""
15+
================================================================================
16+
풀이 과정
17+
================================================================================
18+
19+
[1차 시도] Brute Force - O(n^2)
20+
────────────────────────────────────────────────────────────────────────────────
21+
1. 단순 반복으로 그냥 문제를 풀어보자.
22+
2. 단 같은 숫자일 경우에는 넘어가자.
23+
24+
for i in range(len(nums)):
25+
for j in range(len(nums)):
26+
if i == j:
27+
continue
28+
if nums[i] + nums[j] == target:
29+
return [i, j]
30+
31+
3. O(n^2) 으로 문제를 풀었는데
32+
4. 시간이 오래걸리니까 다른 풀이 방법이 있는 것 같음
33+
34+
35+
[2차 시도] Hash Table - Two Pass
36+
────────────────────────────────────────────────────────────────────────────────
37+
5. 해싱으로 문제를 풀 방법이 있으려나?
38+
6. 넘버마다 인덱스를 저장하고
39+
7. target에서 현재 가진 값을 뺀 값이 nums에 있는지를 판단하면 될 것 같은데?
40+
8. 그리고 현재 가진 값과 뺀 값의 인덱스를 그대로 반환하면 될 것 같고
41+
9. 근데 동일한 인덱스는 제외해야할듯
42+
43+
num_index_dict = defaultdict()
44+
for index, num in enumerate(nums):
45+
num_index_dict[num]=index
46+
print(num_index_dict)
47+
48+
for index, num in enumerate(nums):
49+
if (target - num) in nums and num_index_dict[target - num] != index:
50+
return [index, num_index_dict[target-num]]
51+
52+
53+
[3차 시도] Hash Table - One Pass
54+
────────────────────────────────────────────────────────────────────────────────
55+
10. 단 한 번의 루프에서도 동작시킬 수 있을듯?
56+
57+
num_index_dict = defaultdict()
58+
59+
for index, num in enumerate(nums):
60+
if (target - num) in num_index_dict:
61+
return [index, num_index_dict[target - num]]
62+
63+
num_index_dict[num] = index
64+
65+
66+
[최종 개선] 코드 가독성 향상
67+
────────────────────────────────────────────────────────────────────────────────
68+
11. 속도가 많이 빨라졌다. 코드 가독성만 높여보자
69+
70+
num_to_index = {}
71+
72+
for i, num in enumerate(nums):
73+
diff = target - num
74+
75+
if diff in num_to_index:
76+
j = num_to_index[diff]
77+
return [i, j]
78+
79+
num_to_index[num] = i
80+
"""

0 commit comments

Comments
 (0)