Skip to content

[shinsj4653] Week 03 Solutions #1272

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 20, 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
162 changes: 162 additions & 0 deletions combination-sum/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
"""
[문제풀이]
# Inputs
서로 다른 정수 배열 candidates
타겟 정수 target
# Outputs
서로 다른 숫자 조합들(리스트) 담은 리스트
# Constraints
unique combinations 개수: 150 이하
1 <= candidates.length <= 30
2 <= candidates[i] <= 40
All elements of candidates are distinct.
1 <= target <= 40

# Ideas
같은 숫자가 여러번 선택될 수 있음
[2,3,6,7] -> target = 7
몇 개의 숫자로 구성되는지를 기준으로?
최소 숫자 : 2, target max : 40 -> 한 조합 당 최대 20개 숫자

한 개로 구성:
7

두 개
5 2
4 3

세 개
2 2 3


2 3 5 -> 8

8 0
7 1
6 2
5 3
4 4

1. 한 개인 경우랑 두 개인 경우만 카운트
재귀 돌면서 후보에 있다면 그 후보 담은 리스트 반환
점점 올라가면서 return 된 리스트들 더해서 반환

근데 구현 방법이 쉽게 떠오르지 않음..

결국 어찌저찌 최종 리스트들이 반환되게끔 구현하긴 했지만, dp의 장점도 못살리고, set으로 tuple중복 없애려는 구현방법도 실패..

정답 참고

[회고]

다시 풀면서 막힌 포인트

1. 재귀
→ dfs(i, total + num)

나는 dfs(start, sum(nums)) 로 해버렸다

- sum 대신 total + num 으로 지금까지의 합을 갱신하면 더 효율적!
- start를 넣으면 중복 가짓수 발생.. i를 넣어야 중복 없이 카운트 가능

⇒ 재귀 풀 때 어떤 값을 인자값으로 넣어야 하는지를 설정하는게 가장 어려운듯..연습 많이 해야할듯..


2. DP
다시 풀면서 막힌 포인트

→ dp[num].append(combination + [candidate])

나는 dp[num].append(combination + [num]) 을 해버렸다

따라서, 후보군들로 이뤄진 후보가 아니라,

누적된 합이 적용된 리스트들이 후보로 인식되어 최종 반환 리스트에 들어가졌다.
어떤 변수를 어디에 넣어야 할지, 구현 로직(흐름)을 다시 정리! 복습!
"""

# 1번째 코드
# from collections import defaultdict
#
#
# class Solution:
# def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
# ret = []
#
# if target == 1:
# return ret
#
# elif target == 2:
# if target in candidates:
# ret.append([target])
# return ret
#
# dp = defaultdict(set)
#
# for num in candidates:
# if num == target:
# ret.append([num])
#
# candidates = set(candidates)
#
# def dfs(num):
# if num < 2:
# return
#
# if num < 4:
# if num in candidates:
# return [num]
#
# else:
# for i in range(2, num // 2 + 1):
# # dp[num].add(dfs(target - num) + dfs(num))
# return dfs(num - i) + dfs(i)
#
# for num in range(2, target // 2 + 1):
# print(dfs(target - num) + dfs(num))
# dp[num].add(tuple(dfs(target - num) + dfs(num)))
#
# temp = set()
# for value in dp.values():
# print(value)
# # temp.add(value)
#
# for t in temp:
# ret.append(list(t))
#
# return ret

# 2번째 코드 : dp 활용
class Solution:
def combinationSum(candidates, target):
dp = [[] for _ in range(target + 1)]
dp[0] = [[]]
for candidate in candidates:
for num in range(candidate, target + 1):
for combination in dp[num - candidate]:
dp[num].append(combination + [candidate])
return dp[target]

combinationSum([2, 3, 5], 8)

# 3번째 코드 : 재귀 활용
class Solution:
def combinationSum(candidates, target):
output, nums = [], []

def dfs(start, total):
if total > target:
return
if total == target:
return output.append(nums[:])
for i in range(start, len(candidates)):
num = candidates[i]
nums.append(num)
dfs(i, total + num)
nums.pop()

dfs(0, 0)
return output
combinationSum([2, 3, 5, 7], 7)


127 changes: 127 additions & 0 deletions decode-ways/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""
[문제풀이]
# Inputs
숫자로 구성된 문자열 s
# Outputs
decode 가능한 경우의 수
# Constraints
1 <= s.length <= 100
s contains only digits and may contain leading zero(s).
# Ideas
모든 경우의 수 -> 1. 우선 완탐

11106 -> 1 1 10 6
가능한 숫자들 : 1~26
11 10 6

진짜 완탐만 가능하지 않나?
1 1 1 0 6 (x)
1 1 1 06 (x)
1 1 10 6 (o)
1 1 106 (x)
11 1 0 6 (x)
10 1 06 (x)

재귀로 구현하면 될듯

n = len(s)
ans = 0

def decode(start_idx):
global ans
if start_idx >= n :
return
for i in range(1, 2):
num = int(s[start_idx:start_idx + i]
Copy link
Preview

Copilot AI Apr 19, 2025

Choose a reason for hiding this comment

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

Missing closing parenthesis in the int conversion. Consider updating the line to 'num = int(s[start_idx:start_idx + i])'.

Suggested change
num = int(s[start_idx:start_idx + i]
num = int(s[start_idx:start_idx + i])

Copilot uses AI. Check for mistakes.

if i == 1:
if num != 0:
ans += 1
decode(start_idx + 1)
elif i == 2 :
if s[start_idx:start_idx+i][0] != 0 and 10 <= num <= 26:
ans += 1
decode(start_idx + 1)


2. 완탐 코드 시간 초과
근데 이거 climbing stairs랑 유사한 문제 아닌가?
1과 2로 오를 수 있는 경우의 수 -> 하지만, 숫자 형태 조건이 걸려있어서 씁..

2
2
11
10240

3



[회고]
첫 제출 코드는 시간초과 발생
메모이제이션으로 코드 개선 가능
"""

## 첫 제출 코드
class Solution:
def numDecodings(self, s: str) -> int:
n = len(s)

# ans를 변수로 두고 반환 방식으로 처리
def decode(start_idx):
if start_idx >= n:
return 1 # 끝에 도달하면 1을 반환 (끝까지 도달하면 유효한 디코딩 방법임)

ans = 0
for i in range(1, 3): # 1자리 또는 2자리 숫자를 확인
if start_idx + i <= n: # 인덱스 범위 확인
num = int(s[start_idx:start_idx + i])
if i == 1:
if num != 0: # 1자리 숫자가 0이 아니면 진행
ans += decode(start_idx + 1)
else:
if 10 <= num <= 26: # 2자리 숫자가 10에서 26 사이일 때 진행
ans += decode(start_idx + 2)

return ans

return decode(0) # 0부터 시작

# 두번째 제출 코드

class Solution:
def numDecodings(self, s: str) -> int:
memo = {len(s): 1}
n = len(s)

# ans를 변수로 두고 반환 방식으로 처리
def dfs(start):
if start in memo:
return memo[start]

if s[start] == "0":
memo[start] = 0
elif start + 1 < n and int(s[start:start + 2]) < 27:
memo[start] = dfs(start + 1) + dfs(start + 2)
else:
memo[start] = dfs(start + 1)

return memo[start]

return dfs(0) # 0부터 시작

# 해설의 Bottom-up 방식이 이해가 안가 디버깅 시도
class Solution:
def numDecodings(s):
dp = [0] * len(s) + [1]
for start in reversed(range(len(s))):
if s[start] == "0":
dp[start] = 0
elif start + 1 < len(s) and int(s[start : start + 2]) < 27:
dp[start] = dp[start + 1] + dp[start + 2]
else:
dp[start] = dp[start + 1]
return dp[0]

numDecodings("2266")


48 changes: 48 additions & 0 deletions maximum-subarray/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
[문제풀이]
# Inputs
- 정수형 nums
# Outputs
- 부분 배열 중 합이 가장 큰 배열의 합
# Constraints
- 1 <= nums.length <= 10^5
- 10^4 <= nums[i] <= 10^4
# Ideas
가장 큰 합을 구하는 방법
정렬은 당연히 X
10^5가 최대라 O(n) 고려 필요
-2 1 -3 4 -1 2 1 -5 4
l, r = 0, 0 -> 움직이면서
r = 1
-2 < 1 -> -1

-2 -1 -4 0 -1 1 2 -3 1
1. 누적합?

-2 1 -2 4 3 5 6 1 5

5 4 -1 7 8
5 9 8 15 23

지금까지의 합 보다 다음 원소가 크면 그대로 두고, 아니면 합으로 대체
=> TC: O(n), SC: O(1)

[회고]
먼가..때려 맞춘 느낌이라 해설 참고
->
"""

class Solution:
def maxSubArray(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]

memo = nums[0]

for i in range(1, len(nums)):
if nums[i] < nums[i - 1] + nums[i]:
nums[i] += nums[i - 1]

return max(nums)


53 changes: 53 additions & 0 deletions number-of-1-bits/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
[문제풀이]
# Inputs
- 양인 정수 n
# Outputs
- number of set bits => 이진수 값의 1 개수
# Constraints
- 1 <= n <= 2^31 - 1
# Ideas
1. 반복문
2로 나눠서 몫 나머지 -> 나머지가 1인지 0인지 체크
그 몫을 또 2로 나눠서 몫, 나머지 ->


11
2-> 5, 1
2-> 2, 1
2-> 1, 0
2-> 0, 1

몫이 0이 될 때 까지 반복

TC: log2N? SC: 1

[회고]
시간 복잡도가 log2N인가?
-> O

해설은 어떤지 궁금
->

"""

class Solution:
def hammingWeight(self, n: int) -> int:
ret = 0
while n > 0:
n, bit = n // 2, n % 2
if bit == 1:
ret += 1

return ret

# 해설

class Solution:
def hammingWeight(self, n: int) -> int:
cnt = 0
while n:
cnt += n & 1
n >>= 1
return cnt

Loading