Skip to content

[shinsj4653] Week 01 Solutions #1200

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
Apr 6, 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
30 changes: 30 additions & 0 deletions contains-duplicate/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
# Constraints

1 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9

# Time Complexity: O(n)

배열 내 원소를 순회하며 각 원소별로 등장횟수를 기록
-> 무슨 원소가 들어있는지 모르므로, defaultdict가 좋아보임
-> 등장 횟수 값이 2 이상인 경우 배열 순회 멈추기

# Space Complexity: O(n)

최대 배열 원소 개수만큼 key-value 지니는 사전 활용
"""

from collections import defaultdict
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
count_dict = defaultdict(int)

for n in nums:
if count_dict[n] + 1 >= 2 :
return True

else :
count_dict[n] += 1

return False
59 changes: 59 additions & 0 deletions house-robber/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Inputs: 정수형 배열 nums

Outputs: 훔치는 돈의 max값

Constraints:
1 <= nums.length <= 100
0 <= nums[i] <= 400

Time Complexity: O(2^n) X

dp[n] = max(dp(n), dp(n - 2) + nums[i])
재귀 사용
2^(100)
2^10 = 10^3
막상 실제 값을 출력하면 말이 안되는 값..

Space Complexity: O(n)
dp 배열은 nums와 똑같으므로

# 에러
constraint로 인한 반례 항상 생각하도록!
len이 0이거나 1일때는 따로 처리!

# 반례
nums =
[2,1,1,2]

output = 3, expected = 4

len(nums) - 1이 0 혹은 1일때, 즉 nums길이가 1 혹은 2일 경우엔 따로 처리

"""


class Solution:
def rob(self, nums) -> int:
dp = [-1 for _ in range(len(nums))]
n = len(nums) - 1

if n == 0:
return nums[0]

# 초기값 세팅
dp[0] = nums[0]
dp[1] = max(nums[1], nums[0])

if n == 1:
return dp[1]

def memo(i):
if dp[i] != -1:
return dp[i]

dp[i] = max(memo(i - 1), nums[i] + memo(i - 2))
return dp[i]

return max(memo(n - 1), nums[n] + memo(n - 2))

41 changes: 41 additions & 0 deletions longest-consecutive-sequence/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
Inputs:
정렬되지 않은 정수 배열 nums

Outputs:
가장 긴 연속된 부분 배열의 길이

Constraints:
0 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9

Time Complexity: O(n) 이어야함
어차피 n 최대 길이가 10^5이라 O(n^2)은 불가능!

1 2 3 4라면,
2 3 4
3 4 -> 이 두 후보는 정답에 포함됨

Space Complexity: O(n)
중복 제거한 nums 인 numSet의 크기는 최대 n
"""


class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
numSet = set(nums)
ret = 0

for num in numSet:
if num - 1 in numSet:
continue

cnt = 1

while num + 1 in numSet:
cnt += 1
num += 1

ret = max(ret, cnt)

return ret
67 changes: 67 additions & 0 deletions top-k-frequent-elements/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Constraints:

1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
k is in the range [1, the number of unique elements in the array].

nums 배열에서 원소들의 빈도수 중, 가장 빈도수가 높은 k개의 수들 반환

Time Complexity: O(klogn)

내부적으로 정렬되는 O(logn)을 가지는 최소 힙 사용?

우선 빈도수 사전에 기록 -> dict[숫자] = 빈도수 O(n)
그 다음, 사전.items() 돌면서 heap 에 k개 만큼 넣기 O(k * logn)

k개 만큼 우선순위 큐에 넣기 (-빈도수, 숫자) -> 튜플 넣으면 첫번쨰 원소기준으로 정렬됨

그리고, 나머지 사전.items() 만큼 for i in range(k + 1, n) 만큼만 돌기
-> 만약 힙의 맨 앞 값보다 작으면 넣고, 아니라면 pass

Space Complexity: O(n)

nums만큼 사전에 빈도수 저장

# 간과한 사실
첫 k개만 우선순위 큐에 넣고, 나머지 n - k 만큼 돌때,
힙의 맨 앞 값보다 작거나 같을 때 -> 맨 앞 값을 빼면 안됨!! 그게 정답 수 중 하나일 수 있음


아뿔싸..맨 앞 값만 정렬되어있는 상태라, 마지막 값 반환 시 heappop으로 해줘야할듯!
단순히 for i in range(k) 해서 맨 앞 k 개를 반환하면 정렬되지 않은 상태에서 값을 뽑아내므로 틀릴 수 있음

# 반례

[2,3,4,1,4,0,4,-1,-2,-1]

맨 앞의 값이랑만 비교하다보니, 최대 빈도수 값은 정확히 나오는데 두 번째 이후 값이 첫 번째 값보다 작지 않아서 힙에 못 들어온다..
그래서, 맨 앞의 값 비교 로직 없앰!!

하지만, 힙 내 원소를 k개를 유지 못해서 정렬 시간이 log N 이 되어버림..
-> heap의 사이즈를 k로 유지하면서 작은 빈도 수부터 제거하면,
결국 heap 안에는 가장 많이 등장한 k개의 원소만 남는다.
"""

from collections import defaultdict
from heapq import heappush, heappop


class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
freq_dict = defaultdict(int)
min_heap = []
ret = []

for n in nums:
freq_dict[n] += 1

for key, value in freq_dict.items():
heappush(min_heap, (value, key))
if len(min_heap) > k:
heappop(min_heap)

for _ in range(k):
ret.append(heappop(min_heap)[1])

return ret
47 changes: 47 additions & 0 deletions two-sum/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
# Constraints

2 <= nums.length <= 10^4
-10^9 <= nums[i] <= 10^9
-10^9 <= target <= 10^9

같은 숫자 두번 사용 X

# Time Complexity: O(n)

O(n^2) 으로도 가능은 하지만, 문제에서 이거보다 더 적은 시간복잡도로 풀 수도 있다는 말이 존재
배열 순회하며
첫 원소는 target - n 을 한 값을 set에 넣어두기
다음 원소부터는 해당 값이 set에 있는지 체크
없다면 target - n 넣기

근데 생각해보니 원소의 "idx" 를 반환해야함
-> set대신 dict를 써서,
-> dict[value] = idx로 구성
-> dict[7] = 0
-> 배열 7 오면, 현재 idx랑 기존 idx 가져오기 가능!

# Space Complexity: O(n)

배열 원소 개수만큼 target - n 값이 들어갈 set 크기가 결정됨

"""


class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
ret = []
diffDict = dict()

diffDict[target - nums[0]] = 0

for i in range(1, len(nums)):
if nums[i] in diffDict:
ret.append(diffDict[nums[i]])
ret.append(i)
return ret

else:
diffDict[target - nums[i]] = i

return ret