-
-
Notifications
You must be signed in to change notification settings - Fork 247
[jongwanra] WEEK 01 solutions #1678
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
Changes from all commits
1e822ef
4b5ddb2
151a0f1
87ba189
ea4ed88
c9ffedf
5ddf84f
8460438
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
|
||
""" | ||
[문제] | ||
https://leetcode.com/problems/contains-duplicate/description/ | ||
|
||
[문제 접근 방법] | ||
Set 자료구조를 활용하여 중복 여부를 개수로 확인한다. | ||
|
||
[Complexity] | ||
N: nums 길이 | ||
TC: O(N) | ||
SC: O(N) | ||
""" | ||
|
||
class Solution(object): | ||
def containsDuplicate(self, nums): | ||
return len(set(nums)) != len(nums) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
""" | ||
[Problem] | ||
https://leetcode.com/problems/house-robber/description/ | ||
""" | ||
|
||
class Solution(object): | ||
""" | ||
[Brain Storming] | ||
같은 날에, 인접한 집을 털면 안된다. | ||
하루에 털 수 있는 최대 금액을 구하는 문제. | ||
|
||
1 <= nums.length <= 100 | ||
nums.length가 최대 100이기 때문에, | ||
DFS로 문제를 접근해도 풀 수 있는 문제라고 생각한다. | ||
|
||
각 집을 넣는 경우와 안넣는 경우 인접한 경우를 따져서 최대 금액을 구해보자. | ||
|
||
[Complexity] | ||
Time: 집을 터는 경우, 안 터는 경우 2^100.. -> Time Limit Exceeded 발생 | ||
Space: O(N) 재귀 호출 스택의 길이도 비례하여 길어짐. | ||
""" | ||
def rob1(self, nums): | ||
answer = 0 | ||
visited = [False] * len(nums) | ||
|
||
def dfs(depth, sum): | ||
# nonlocal nums | ||
nonlocal answer | ||
nonlocal visited | ||
|
||
|
||
if depth == len(nums): | ||
answer = max(answer, sum) | ||
print(sum, visited) | ||
return | ||
|
||
# 다음 집을 포함한 경우 | ||
if depth == 0 or not visited[depth - 1]: | ||
visited[depth] = True | ||
dfs(depth + 1, sum + nums[depth]) | ||
|
||
# 다음 집을 포함하지 않은 경우 | ||
visited[depth] = False | ||
dfs(depth + 1, sum) | ||
|
||
dfs(0, 0) | ||
return answer | ||
|
||
def rob(self, nums): | ||
""" | ||
다른 사람의 풀이 | ||
DFS + Memoization 기법을 활용한다. | ||
ref: https://www.algodale.com/problems/house-robber/ | ||
|
||
[Complexity] | ||
Time: O(N) | ||
Space: O(N) | ||
|
||
""" | ||
cache = {} | ||
def dfs(depth): | ||
if depth in cache: | ||
return cache[depth] | ||
if depth >= len(nums): | ||
cache[depth] = 0 | ||
return cache[depth] | ||
|
||
cache[depth] = max(nums[depth] + dfs(depth + 2), dfs(depth + 1)) | ||
return cache[depth] | ||
|
||
return dfs(0) | ||
|
||
|
||
sol = Solution() | ||
print(sol.rob([1, 2, 3, 1])) | ||
print(sol.rob([2,7,9,3,1])) | ||
|
||
# Edge Case | ||
print(sol.rob([1]) == 1) | ||
print(sol.rob([183,219,57,193,94,233,202,154,65,240,97,234,100,249,186,66,90,238,168,128,177,235,50,81,185,165,217,207,88,80,112,78,135,62,228,247,211])) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
""" | ||
[Problem] | ||
https://leetcode.com/problems/longest-consecutive-sequence/description/ | ||
|
||
[Brain Storming] | ||
O(N)으로 연속된 길이를 찾아야 한다? | ||
계수 정렬을 이용하면 가능하다. 하지만 nums[i] <= 10^9이기 떄문에 공간을 너무 많이 잡아먹는다. | ||
|
||
[Plan] | ||
1. max num과 min num을 찾는다. | ||
2. set을 통해 O(1)로 빠르게 num을 찾을 수 있도록 변경한다. | ||
3. for loop를 min num ~ max num으로 순회한다 | ||
3-1. 연속된 길이를 비교하며 기록한다. | ||
|
||
-> Time Limit Exceeded 발생 | ||
-> [0,1,2,4,8,5,6,7,9,3,55,88,77,99,999999999] | ||
|
||
[Plan2] | ||
Heap 자료구조를 이용해서 구한다. | ||
nums를 전부 heapify할 경우 O(N), | ||
nums를 순회하면서 heappop을 할 경우 N * log(N) | ||
""" | ||
|
||
import heapq | ||
|
||
|
||
class Solution(object): | ||
""" | ||
[Complexity] | ||
N: nums.length | ||
M: max_num - min_num + 1 | ||
--- | ||
Time: O(N + M) | ||
Space: O(N) | ||
|
||
nums가 [1, 9999999] 일 경우 굉장히 비효율적인 풀이. | ||
""" | ||
|
||
def longestConsecutive1(self, nums): | ||
if not nums: | ||
return 0 | ||
|
||
min_num = min(nums) | ||
max_num = max(nums) | ||
num_set = set(nums) | ||
|
||
answer = 0 | ||
|
||
cur_num = min_num | ||
while cur_num <= max_num: | ||
count = 0 | ||
while cur_num in num_set: | ||
count += 1 | ||
cur_num += 1 | ||
answer = max(answer, count) | ||
cur_num += 1 | ||
|
||
return answer | ||
|
||
""" | ||
[Complexity] | ||
N: nums.length | ||
Time: O(N * log N) | ||
Space: O(N) | ||
""" | ||
|
||
def longestConsecutive2(self, nums): | ||
if not nums: | ||
return 0 | ||
heapq.heapify(nums) | ||
|
||
answer = 1 | ||
prev_num = heapq.heappop(nums) | ||
count = 1 | ||
|
||
while nums: | ||
cur_num = heapq.heappop(nums) | ||
if cur_num == prev_num: | ||
continue | ||
if cur_num - prev_num == 1: | ||
# 연속인 경우 | ||
count += 1 | ||
prev_num = cur_num | ||
# 연속이 아닌 경우 | ||
else: | ||
count = 1 | ||
prev_num = cur_num | ||
answer = max(answer, count) | ||
|
||
return answer | ||
|
||
""" | ||
다른 사람의 풀이 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정렬 시 보편적으로 시간 복잡도 O(NlogN), 기수 정렬은 작성하신 바와 같이 입력 범위에 민감하기 때문에, 정렬 없이 문제를 해결하는 것이 포인트였습니다. 다양하게 접근해보신 고민이 보입니다. 구간의 시작점을 찾아 끊어질 때까지 증가하면서 찾는 다른 사람의 풀이도 흥미롭네요. 고생하셨습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. union-find를 사용하는 풀이도 확인해보시면 좋을 것 같습니다. 조건에 따라 그룹핑하는 문제에 유용합니다. |
||
참고: https://www.algodale.com/problems/longest-consecutive-sequence/ | ||
|
||
[Plan] | ||
1. nums를 Set에 저장한다. | ||
2. 모든 정수에 대해서 for-loop를 순회한다. | ||
2-1. 정수에서 1을 뺀 값이 Set에 있다면, 구간내 첫 번째 값이 될 수 없기 때문에 무시 | ||
2-2. 없다면, 1씩 길이를 최대길이로 늘려본다. | ||
2-3. 구간내 첫 번째 값이 중복으로 들어갈 수 있는 경우를 대비하여 cache 추가 | ||
3. 최대 구간의 길이와 비교한다. | ||
|
||
[Complexity] | ||
N: nums.length | ||
Time: O(N) | ||
Space: O(N) | ||
""" | ||
|
||
def longestConsecutive(self, nums): | ||
answer = 0 | ||
num_set = set(nums) | ||
cache = set() | ||
|
||
for num in nums: | ||
if num - 1 in num_set: | ||
continue | ||
if num in cache: | ||
continue | ||
|
||
cache.add(num) | ||
length = 1 | ||
while num + length in num_set: | ||
length += 1 | ||
|
||
answer = max(answer, length) | ||
return answer | ||
|
||
|
||
solution = Solution() | ||
# Normal Case | ||
print(solution.longestConsecutive([100, 4, 200, 1, 3, 2]) == 4) | ||
print(solution.longestConsecutive([0, 3, 7, 2, 5, 8, 4, 6, 0, 1]) == 9) | ||
print(solution.longestConsecutive([1, 0, 1, 2]) == 3) | ||
|
||
# Edge Case | ||
print(solution.longestConsecutive([]) == 0) | ||
print(solution.longestConsecutive([0, 1, 2, 4, 8, 5, 6, 7, 9, 3, 55, 88, 77, 99, 999999999]) == 10) | ||
print(solution.longestConsecutive([9, 1, 4, 7, 3, -1, 0, 5, 8, -1, 6]) == 7) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
""" | ||
[Problem] | ||
https://leetcode.com/problems/top-k-frequent-elements/ | ||
|
||
[Brain Storming] | ||
가장 자주 사용되는 요소 k개를 반환한다. | ||
|
||
1<= nums.length <= 10^5 | ||
O(n^2) time complexity일 경우 시간 초과 발생 | ||
|
||
[Plan] | ||
1. nums를 순회하면서 Hash Table에 key:element value:count 저장한다. | ||
2. nums를 순회하면서 Heap에 (count, element)를 count를 기준으로 Max Heap 형태로 저장한다. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 1번 수행 후, count:value로 추가적인 정렬 hash table을 만들었는데요, 빈도의 종류 S <= N이므로 빌드 비용 O(SlogN) 발생 후 인덱스 K로 접근하는 방향을 생각했습니다. heapify 비용이 싸니까 이 방식도 유용하네요. 배워갑니다! |
||
3. Max Heap에서 k개 만큼 pop한다. | ||
|
||
[Complexity] | ||
N: nums.length, K: k | ||
heapq.heapify(heap): O(N) | ||
heapq.heappop(heap): log(N) | ||
|
||
Time: O(N + (K * log(N))) | ||
Space: O(N + K) | ||
* num_to_count_map: O(N) | ||
* heap: O(N) | ||
* answer: O(K) | ||
|
||
|
||
""" | ||
|
||
import heapq | ||
|
||
class Solution(object): | ||
def topKFrequent(self, nums, k): | ||
num_to_count_map = {} | ||
for num in nums: | ||
num_to_count_map[num] = num_to_count_map.get(num, 0) + 1 | ||
|
||
heap = [] | ||
for num, count in num_to_count_map.items(): | ||
heap.append((-count, num)) | ||
heapq.heapify(heap) | ||
|
||
answer = [] | ||
for _ in range(k): | ||
negative_count, frequent_num = heapq.heappop(heap) # log(N) | ||
answer.append(frequent_num) | ||
return answer | ||
|
||
solution = Solution() | ||
|
||
# Normal Case | ||
print(solution.topKFrequent([1,1,1,2,2,3], 2) == [1, 2]) | ||
print(solution.topKFrequent([1], 1) == [1]) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
""" | ||
[Problem] | ||
https://leetcode.com/problems/two-sum/description/ | ||
|
||
nums.length <= 10^4 => 10,000 * 10,000 => n^2 time complexity일 경우 1초 이상 소요 | ||
|
||
[Plan] | ||
nums를 hash table로 만들자. (key: element, value: index) | ||
이후에 nums를 돌면서 target - current_num을 뺀 값이 hash table에 존재한 경우 return하자. | ||
그랬을 경우, O(n) 시간 복잡도를 예상한다. | ||
|
||
[Complexity] | ||
N: nums length | ||
Time: O(N) => HashTable에 nums를 만큼 반복문 돌림 | ||
Space: O(N) => nums length 만큼 반복문을 돌면서 hash table을 생성 | ||
""" | ||
|
||
class Solution(object): | ||
def twoSum(self, nums, target): | ||
num_to_index_map = dict() | ||
for index in range(len(nums)): | ||
num_to_index_map[nums[index]] = index | ||
|
||
for index in range(len(nums)): | ||
num = nums[index] | ||
diff = target - num | ||
# target - num 값이 존재 하지 않을 경우 무시 | ||
if not diff in num_to_index_map: | ||
continue | ||
# index가 자기 자신인 경우 무시 | ||
if index == num_to_index_map[diff]: | ||
continue | ||
return [index, num_to_index_map[diff]] | ||
|
||
return [0, 0] | ||
|
||
|
||
solution = Solution() | ||
print(solution.twoSum([3, 2, 4], 6)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
주어진 입력이 set으로 전환되는 비용에 대해 조금 더 구체적인 설명이 있으면 좋을 것 같아요!