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
21 changes: 21 additions & 0 deletions contains-duplicate/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'''
Approach:
주어진 배열에서 중복된 요소가 존재하는지 확인하는 문제입니다.
해시 테이블 자료구조인 set을 이용해 nums의 모든 요소를 순회하며 중복을 제거한 객체를 생성했습니다.
이후 set의 길이와 원본 배열의 길이를 비교하여, 길이가 다르다면 중복된 요소가 존재함을 의미합니다.

Time Complexity:
O(n)
- set(nums)를 생성할 때 nums의 모든 원소를 한 번씩 순회하며 해시 테이블에 삽입하기 때문입니다.

Space Complexity:
O(n)
- 중복을 제거한 원소들이 새로운 집합(set)에 저장되므로,
최대 nums의 크기만큼 추가 공간이 필요합니다.
'''
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
if len(nums) != len(set(nums)):
return True
else:
return False
93 changes: 93 additions & 0 deletions longest-consecutive-sequence/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
'''
1차시도 : 시간 복잡도 O(n)으로 해결 실패..;;
Approach
- nums 리스트가 비어있는 경우 0을 반환합니다.
- nums 리스트의 중복을 제거하고 정렬합니다.
- 정렬된 리스트를 순회하며 이전 숫자와 현재 숫자가 연속되는지 확인합니다.
- 연속된다면 count를 증가시키고, 연속되지 않는다면 max_count와 비교하여 갱신 후 count를 1로 초기화합니다.
- 최종적으로 max_count를 반환합니다.

Time Complexity: O(n log n)
- 중복 제거 및 정렬에 O(n log n) 발생

Space Complexity: O(n)
- 중복 제거된 리스트 저장 공간으로 인해 O(n) 발생
'''
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
# 리스트에 값이 없는 경우는 0 반환
if len(nums) == 0:
return 0

# 정렬
new_nums = list(set(nums))
new_nums.sort()
# 변수 생성 : 배열의 길이가 1이상인 경우 연속되는 숫자는 무조건 1개 포함된다고 가정
count = 1
max_count = 1

for idx, val in enumerate(new_nums):
# 첫 번째 인덱트(idx == 0)는 비교할 이전 값이 없으므로 그냥 건너뛰기
if idx == 0:
continue
if new_nums[idx-1] +1 == val:
count+=1
# 마지막 값인 경우
if idx == len(new_nums)-1:
if max_count <= count:
max_count = count
else:
# 이전갑과 연속되지 않는 경우
if max_count <= count:
max_count = count
count = 1
else:
count = 1

return max_count

'''
2차시도 : Set 자료구조 활용
Approach
- Set 자료구조로 중복 값을 제거하고, Set을 활용한 존재 여부 확인 시간은 O(1)이기 때문에 이를 활용했습니다.
- nums 리스트가 비어이는 경우 0을 반환합니다.
- Set으로 중복된 값을 제거합니다.
- Set을 순회하며 각 값에 대해 val-1이 Set에 없는 경우 새로운 연속 수열의 시작점으로 간주합니다.
- 시작점 이후로 While문을 사용해서 val+1, val+2,... 가 Set에 존재하는지 확인하며 count를 증가시킵니다.
- 최종적으로 max_count를 반환합니다.

Time Complexity: O(n)
- Array를 Set으로 변환: O(n)
- 각 원소에 대해:
- 시작점이 아닌 경우: if (val - 1) not in num_set → O(1) 후 바로 넘어감
- 시작점인 경우: while로 연속 구간을 끝까지 탐색: 각 숫자는 연속되는 숫자 내에서 최대 한 번씩만 방문되므로,
전체 while 반복 횟수의 합은 O(n)을 넘지 않음.

Space Complexity: O(n)
- Set 자료구조에 중복 제거된 값들을 저장하는데 O(n) 발생
'''
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
# 값이 없는 경우 0 반환
if len(nums) == 0:
return 0

# set으로 중복된 값 제거
num_set = set(nums)
max_count = 1

for val in num_set:
# val-1 이 없다면, val은 새로운 연속 수열의 시작점
if (val - 1) not in num_set:
current = val
count = 1

# 시작점 이후 연속되는 숫자가 set안에 있는지 검증
while (current + 1) in num_set:
current += 1
count += 1
# while문 탈출 (=연속되는 숫자가 없는 경우) 최대 연속된 숫자 길이와 비교함
if count > max_count:
max_count = count

return max_count
88 changes: 88 additions & 0 deletions top-k-frequent-elements/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from typing import List

'''
[1차 시도]
Approach: nums 리스트의 각 원소의 빈도수를 hash_map에 저장후, 빈도수 기준으로 정렬을 하고 상위 k개를 반환
count 함수를 사용해서 간견할게 코드를 완성하고자 했습니다.

Time Complexity: O(n²)
- for num in nums 순환과 nums.count(num) 의 중첩으로 인해 O(n²) 발생

Space Complexity: O(n)
- hash_map 저장 공간과 sorted_hash_map 저장 공간으로 인해 O(n) 발생

-
'''
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
hash_map = {}
for num in nums:
hash_map[num] = nums.count(num)

# hash_map 정렬
sorted_hash_map = sorted(hash_map.items(), key=lambda x: x[1], reverse=True)
# 상위 k개 반환
return [x[0] for x in sorted_hash_map[:k]]

'''
[2차 시도]
Approach: 위의 방식에서 count 함수를 제거하고, hash_map에 빈도수를 직접 카운팅 하도록 수정하도록 해서
Time Complexity를 개선하기 위해 노력했습니다.

Time Complexity: O(n log n)
- for num in nums 순환에 O(n) 발생
- hash_map 정렬에 O(m log m)으로 예측 되며 최대 m =< n 이므로 O(n log n) 발생

'''
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
hash_map = {}
for num in nums:
if hash_map.get(num):
hash_map.update({num: hash_map[num]+1})
else:
hash_map.update({num: 1})

# hash_map 정렬
sorted_hash_map = sorted(hash_map.items(), key=lambda x: x[1], reverse=True)
# 상위 k개 반환
return [x[0] for x in sorted_hash_map[:k]]


'''
[3차 시도 - Bucket Sort 활용]
Approach: Bucket Sort 방식을 활용할 수 있다는 것을 알게 됐습니다.
for loop와 조건문이 반복되기도 하지만, 배열의 크기에 맞춰 한번씩만 순회하기 때문에
Time Complexity를 O(n)으로 개선할 수 있었습니다.

Time Complexity: O(n)
- for num in nums 순환하며 빈도수 카운팅: O(n)
- 빈도에 따라 숫자들을 버킷에 넣기: O(n)
- 버킷을 뒤에서부터 순회하며 상위 k개 숫자 채우기: O(n)

Space Complexity: O(n)
- hash_map 딕셔너리와 bucket 리스트로 인해 O(n) 발생
'''
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
hash_map = {}
for num in nums:
hash_map[num] = hash_map.get(num, 0) + 1

# 예시 nums = [1,6,6,3,2,6,8], bucket = [[1,3,2,8],[],[6]]
bucket = [[] for _ in range(len(nums) + 1)]
for num, count in hash_map.items():
bucket[count].append(num)

result: List[int] = []
# 가장 큰 빈도부터 내려오면서 숫자 수집 (for 루프 역순)
for count in range(len(bucket) - 1, -1, -1):
if not bucket[count]:
continue

for num in bucket[count]:
result.append(num)
if len(result) == k:
return result

return result
47 changes: 47 additions & 0 deletions two-sum/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'''
Approach:
주어진 배열을 두 번 순회하며 모든 가능한 쌍을 검사합니다.
각 원소에 대해 이후의 원소들과의 합이 target과 같은지 비교하여 일치하는 경우 인덱스를 반환합니다.

Time Complexity:
O(n²)
- Outer Loop에서 n번 반복
- Inner Loop에서 각 idx마다 최소 n-1번 반복

Space Complexity:
O(1)
- 결과를 저장하기 위해 상수 값을 필요로 하지만, 입력값의 크키에 비례한 새로운 공간 불요
'''

class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
for idx, xnum in enumerate(nums):
for jdx in range(idx + 1, len(nums)):
if (xnum + nums[jdx]) == target:
return [idx, jdx]
return []

'''
(개선)
Approach:
“You may assume that each input would have exactly one solution, and you may not use the same element twice.”
라는 문구에서 항상 정답이 존재하며 같은 원소를 중복 사용할 수 없음을 알 수 있습니다.
이를 바탕으로 각 원소 num에 대해 (target - num)이 이전에 등장한 적이 있는지를 해시맵을 이용해 빠르게 확인하도록 개선했습니다.
즉, 중복이 없고 답이 반드시 존재한다는 조건 아래에서, inner loop 없이 바로 찾기 위해 딕셔너리를 사용하 것입니다.

Time Complexity:
O(n)
- 리스트를 한 번 순회하면서 딕셔너리를 채워 넣는 데 걸리는 전체 시간

Space Complexity:
O(n)
- 해시맵에 key-value 쌍으로 저장되는 공간
'''
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hash_map = {}
for i, num in enumerate(nums):
diff = target - num
if diff in hash_map:
return [hash_map[diff], i]
hash_map[num] = i