Skip to content

[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

Merged
merged 8 commits into from
Jul 27, 2025
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
18 changes: 18 additions & 0 deletions contains-duplicate/jongwanra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

"""
[문제]
https://leetcode.com/problems/contains-duplicate/description/

[문제 접근 방법]
Set 자료구조를 활용하여 중복 여부를 개수로 확인한다.

[Complexity]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주어진 입력이 set으로 전환되는 비용에 대해 조금 더 구체적인 설명이 있으면 좋을 것 같아요!

N: nums 길이
TC: O(N)
SC: O(N)
"""

class Solution(object):
def containsDuplicate(self, nums):
return len(set(nums)) != len(nums)

81 changes: 81 additions & 0 deletions house-robber/jongwanra.py
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]))

140 changes: 140 additions & 0 deletions longest-consecutive-sequence/jongwanra.py
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

"""
다른 사람의 풀이
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정렬 시 보편적으로 시간 복잡도 O(NlogN), 기수 정렬은 작성하신 바와 같이 입력 범위에 민감하기 때문에, 정렬 없이 문제를 해결하는 것이 포인트였습니다. 다양하게 접근해보신 고민이 보입니다.

구간의 시작점을 찾아 끊어질 때까지 증가하면서 찾는 다른 사람의 풀이도 흥미롭네요. 고생하셨습니다.

Copy link
Contributor

Choose a reason for hiding this comment

The 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)

55 changes: 55 additions & 0 deletions top-k-frequent-elements/jongwanra.py
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 형태로 저장한다.
Copy link
Contributor

Choose a reason for hiding this comment

The 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])


40 changes: 40 additions & 0 deletions two-sum/jongwanra.py
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))