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
25 changes: 25 additions & 0 deletions contains-duplicate/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Solution:
def containsDuplicate(self, nums: list[int]) -> bool:
"""
리스트에 숫자가 두번 이상 등장하는 경우가 있으면 True,
모든 숫자가 한 번씩만 등장하면 (unique) False를 반환하는 함수

방법:
1. 처음부터 끝까지 리스트를 순회하면서 동일한 숫자가 있는지 확인하는 방법 (with dict); o(n) 시간복잡도
2. 리스트를 set으로 변환하여 길이를 비교하는 방법; o(n) 시간복잡도 -> PICK!
3. 리스트를 정렬한 후 인접한 숫자가 동일한지 확인하는 방법; o(nlogn) 시간복잡도

* 길이가 1일 경우, 중복이 있을 수 없으므로 False를 반환한다.

방법(2)가 가장 간단하고 효율적이지만, 메모리 사용량은 길이가 n인 리스트를 set으로 변환할 때 O(n) 만큼 필요하다.
방법(3)은 추가적인 메모리를 사용하지 않지만, 정렬할 때 O(nlogn) 시간복잡도가 든다.

Args:
nums (List[int]): 동일한 숫자를 포함한 정수 배열

Returns:
bool: 중복이 없으면 False, 있으면 True
"""
if len(nums) <= 1:
return False
return len(nums) != len(set(nums))
29 changes: 29 additions & 0 deletions house-robber/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class Solution:
def rob(self, nums: list[int]) -> int:
"""
연속된 집을 훔치지 않고 최대한 많은 돈을 훔치는 함수

방법
1. DP 방식으로, 각 집을 훔칠 때의 최대 돈의 양을 업데이트 하는 방법.
dp[0], dp[1]를 초기화 하고, dp[2]는 dp[0]+nums[2]로 구성
이후 dp[i]는 dp[i-2]와 dp[i-3] 중 큰 값에 nums[i]를 더한 값으로 구성
max(dp)로 최대값 찾기
2. 1번 방법에서 점화식을 좀 더 간단하게, dp[i]는 dp[i-1]과 dp[i-2]+nums[i] 중 큰 값으로 구성하는 방법.
dp[i-1]은 i번째 집을 훔치지 않았을 때의 최대값, dp[i-2]+nums[i]는 i번째 집을 훔쳤을 때의 최대값이므로, 둘 중 큰 값을 dp[i]로 업데이트 하는 방식.
dp[-1]이 최대값이므로, max(dp) 대신 dp[-1]로 최대값 찾기
3. 2번 방법에서 dp 리스트 대신, 두 개의 변수로 이전 두 집을 훔쳤을 때의 최대값을 업데이트 하는 방법.

Args:
nums (list[int]): 각 집에 있는 돈의 양이 담긴 리스트

Returns:
int: 최대로 훔칠 수 있는 돈의 양
"""
if len(nums) <= 2:
return max(nums)
prev1, prev2 = 0, 0
for num in nums:
temp = prev1
prev1 = max(prev1, prev2 + num)
prev2 = temp
return prev1
32 changes: 32 additions & 0 deletions longest-consecutive-sequence/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Solution:
def longestConsecutive(self, nums: list[int]) -> int:
"""
가장 길게 연속된 숫자들의 길이를 반환하는 함수
** 조건: O(n) 시간복잡도로 풀이해야 한다.

방법
0. set 자료구조를 사용해 중복 제거
1. 정렬한 후 순회하면 연속된 숫자가 끊기는 지점을 찾아 max 길이를 업데이트 하는 방법.
=> O(nlogn) => 시간복잡도 조건을 만족하지 못한다.
2. DP 방식으로 max(list) 만큼 리스트를 만들어, 각 숫자가 존재하는지 체크하면서 연속된 숫자들의 길이를 업데이트 하는 방법.
=> 음수 숫자가 존재할 수 있어, 해당 방법은 사용할 수 없다.
3. 목록을 순회하면서, 각 숫자가 연속된 숫자의 시작점인지 확인한 후, 연속된 숫자들의 길이를 파악해, max 길이를 업데이트 하는 방법.
=> O(n)
4. union-find 자료구조를 사용해, 각 숫자들을 연결한 후, 가장 긴 연결된 숫자들의 길이를 반환하는 방법.
=> O(n), 구현 x

Args:
nums (list[int]): 정렬되지 않은 중복 포함 정수 배열

Returns:
int: 가장 길게 연속된 숫자들의 길이
"""
u_nums = set(nums)
longest = 0
for u_num in u_nums:
if u_num - 1 not in u_nums:
local = 1
while u_num + local in u_nums:
local += 1
longest = max(local, longest)
return longest
27 changes: 27 additions & 0 deletions top-k-frequent-elements/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import heapq
from collections import Counter

class Solution:
def topKFrequent(self, nums: list[int], k: int) -> list[int]:
"""반복되는 횟수가 높은 순으로 Top k인 숫자들을 찾는 함수

방법
1. 전체 목록을 순회하면서, 각 숫자가 몇 번 나오는지 세어, dict map 만들기.
이후 value 값 기준으로 정렬해, 상위 k개를 반환하는 방법 => O(n) + O(n log n) => O(n log n)
2. 1번의 방법에서 dict map을 만드는 걸, python 내장 모듈인 Counter로 대체하기.
Counter가 약간 더 빠름; C implementation이기 때문.
3. 1번 방법의 sorted 대신, heapq 모듈의 nlargest 함수를 이용하기.
전체 목록을 순회하지 않고, top k에 해당하는 값만 파악하기에 효율적임. O(n) + O(n log k) => O(n log k)
4. quick select 알고리즘. O(n) + O(n) => O(n); 해당 문제에 구현하지 못함.

Args:
nums (list[int]): 정렬되지 않은 중복 포함 정수 배열
k (int): Top k의 개수

Returns:
list[int]: Top k에 해당하는 숫자들의 리스트
"""
if len(nums) <= 1:
return nums
count = Counter(nums)
return heapq.nlargest(k, count.keys(), key=count.get)
29 changes: 29 additions & 0 deletions two-sum/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class Solution:
def twoSum(self, nums: list[int], target: int) -> list[int]:
"""
리스트에서 두 숫자의 합이 target이 되는 경우가 있으면, 그 두 숫자의 인덱스를 반환하는 함수
방법:
1. 리스트를 순회하면서, 각 숫자에서 target을 만들기 위한 나머지 숫자가 있는지 모두 순회 (brute-force); o(n^2) 시간복잡도
2. 리스트를 순회하면서, 각 숫자에서 target을 만들기 위한 나머지 숫자가 있는지 search (binary search); o(nlogn) 시간복잡도
3. 리스트를 순회하면서, 각 숫자를 dict에 저장하여 (key=숫자, value=인덱스),
target을 만들기 위한 나머지 숫자를 dict에서 search; o(n) 시간복잡도 -> PICK!
* 답이 항상 존재한다는 가정하에 문제를 풀이.
* 리스트의 길이가 2 이하인 경우, 두 숫자의 합이 target이 되는 경우가 항상 존재하므로 [0, 1]을 반환한다.
Args:
nums (list[int]): 중복을 포함한 정수 배열
target (int): 찾아야 하는 두 숫자의 합
Returns:
list[int]: 찾아낸 두 숫자의 인덱스
"""
if len(nums) <= 2:
return [0, 1]
seen = dict()
for i, num in enumerate(nums):
remain = target - num
if remain in seen:
return [seen[remain], i]
seen[num] = i