Skip to content

[shinsj4653] Week 04 Solutions #1338

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 6 commits into from
Apr 26, 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
45 changes: 45 additions & 0 deletions coin-change/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
[문제풀이]
# Inputs
- 정수 배열 coins
- 총 돈의 값 amount
# Outputs
- amount 를 채울 수 있는 동전의 가장 적은 수
- 만약 만들 수 없다면 -1 return
# Constraints
- 1 <= coins.length <= 12
- 1 <= coins[i] <= 2^31 - 1
- 0 <= amount <= 10^4
# Ideas
- 우선 이전 풀이 본 거 연습해보기
- DP 탑다운 방식으로! 이 문제 풀이를 내가 100% 이해하고 있는게 맞는지 손으로 도식화 해보기로함


[회고]
재귀랑 dp는 다양한 유형을 많이 풀어보는 수 밖에..
"""


class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
memo = {}

def dp(amount):
Copy link
Preview

Copilot AI Apr 26, 2025

Choose a reason for hiding this comment

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

Consider caching the result of dp(amount) by storing it in memo after computation to avoid repeated calculations and improve performance.

Suggested change
def dp(amount):
def dp(amount):
if amount in memo:
return memo[amount]

Copilot uses AI. Check for mistakes.


if amount == 0:
return 0

retList = []
for coin in coins:
if amount - coin >= 0:
if amount - coin not in memo:
memo[amount - coin] = dp(amount - coin)

if memo[amount - coin] != -1:
retList.append(memo[amount - coin])

return min(retList) + 1 if retList else -1

return dp(amount)


83 changes: 83 additions & 0 deletions find-minimum-in-rotated-sorted-array/shinsj4653.py
Copy link
Contributor

Choose a reason for hiding this comment

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

전체적인 문제 풀이에 대한 아이디어, 흐름, 해설을 통한 개선점까지 같이 적어주시는 부분이 굉장히 좋은 것 같습니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""
[문제풀이]
# Inputs
- sorted rotated array : nums
- nums안의 요소는 unique
# Outputs
- 배열의 가장 작은 값 Return
# Constraints
- O(logN) 시간대로 풀어야함
- n == nums.length
- 1 <= n <= 5000
- -5000 <= nums[i] <= 5000
- All the integers of nums are unique.
- nums is sorted and rotated between 1 and n times.
# Ideas
그냥 정렬은 O(NlogN) 이어서 불가능
rotate : 맨 끝의 요소가 맨 처음으로 옴
이진탐색이 O(logN) 이긴한데..->하지만, 이진탐색은 정렬된 배열에서만 사용가능
그리고, 이 문제에선 아닌 것 같다

끝의 원소를 빼서 stack에 append -> 모두 o(1)

회전되어 있는 배열의 특성을 활용하여
-> 끝의 원소 빼고, 그걸 stack 에 넣기
-> 그리고 stack의 맨 끝 원소보다 nums의 끝 원소가 더 클때
stack[-1] 이 정답
-> 근데 이건 o(n) 아닌가??

우선 내 풀이 정답
해설 참고
-> 내 풀이는 O(n) 이다.. O(logN) 풀이가 필요
이분탐색 응용문제이다

[회고]

"""

# 내 풀이
from collections import deque


class Solution:
def findMin(self, nums: List[int]) -> int:

if len(nums) == 1:
return nums[0]

nums = deque(nums)

st = []
ret = 0

while nums:
num = nums.pop()

if not nums:
ret = num
break

if num < nums[-1]:
ret = num
break

return ret

# 해설
class Solution:
def findMin(self, nums: List[int]) -> int:

left, right = 1, len(nums) - 1

while left <= right:
mid = (left + right) // 2
if nums[mid - 1] > nums[mid]:
return nums[mid]
if nums[0] < nums[mid]:
left = mid + 1
else:
right = mid - 1

return nums[0]


56 changes: 56 additions & 0 deletions maximum-depth-of-binary-tree/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""
[문제풀이]
# Inputs
- 이진 트리의 root
# Outputs
- 가장 최고 깊이
# Constraints
The number of nodes in the tree is in the range [0, 104].
-100 <= Node.val <= 100
# Ideas
dfs, 즉 재귀 돌면서
depth 를 max로 업데이트 하면 될 것 같은 느낌?

[회고]
내 풀이는 정답
해설 방법도 궁금하여 참고
-> TC, SC도 파악하는 연습!

TC: o(n)
SC: o(n)

"""

# 내 풀이
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
def dfs(node, depth):
if node is None:
return depth - 1

return max(dfs(node.left, depth + 1), dfs(node.right, depth + 1))

return dfs(root, 1)
# 해설
# bfs 풀이도 존재
class Solution:
Copy link
Preview

Copilot AI Apr 26, 2025

Choose a reason for hiding this comment

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

Duplicate 'Solution' class definition may cause unintended overrides. Consider merging the two implementations or renaming one of them.

Suggested change
class Solution:
class SolutionBFS:

Copilot uses AI. Check for mistakes.

def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
max_depth = 0
stack = [(root, 1)]
while stack:
node, depth = stack.pop()
max_depth = max(depth, max_depth)
if node.left:
stack.append((node.left, depth + 1))
if node.right:
stack.append((node.right, depth + 1))
return max_depth

60 changes: 60 additions & 0 deletions merge-two-sorted-lists/shinsj4653.py
Copy link
Contributor

Choose a reason for hiding this comment

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

풀이에 대해 고민하셨던 부분을 읽어보니 저와 비슷한 고민을 하셨던 것 같아요. 저도 오랫동안 고민하다가 이전 Tree 문제들이 재귀를 이용해 풀이를 진행했던 걸 상기하고 ListNode의 구조를 활용해서 풀이를 했는데, 풀이 과정에 대한 고찰이 꼼꼼하게 적혀있어서 좋았습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""
[문제풀이]
# Inputs
- two sorted linked lists
# Outputs
- 두 링크드 리스트를 합쳐서 하나의 정렬된 (오름차순) 리스트 반환
# Constraints
- The number of nodes in both lists is in the range [0, 50].
- -100 <= Node.val <= 100
- Both list1 and list2 are sorted in non-decreasing order.
# Ideas
두 링크드 리스트는 모두 오름차순으로 정렬되어 있음
-> ListNode는 val, next 로 되어있음

우선 두 리스트 이어붙이고,
먼가 리스트 정렬 알고리즘 써야할듯?
리스트라서, 두 노드를 바꾸는 swap() 함수 쓰면서,
왼쪽보다 오른쪽이 작으면 바꾸는 식으로 하면 될듯?

즉, 붙어있는 두 노드 비교하면서 쭉 돌기
하지만 인덱스가 없어서 어떻게 순회할지?
-> point라는 기준을 둬서 이 point를 기준으로 prev, next를 만들어서 순회
-> 근데 prev, next만으로는 swap이 어려워서 2개가 아닌 3개를 둬야할 것 같은데,
구현 방법이 떠오르지 않아서 해설 참고

해설 참고
- 기존 리스트 변경이 아닌, 아예 새로운 리스트를 재창조 하는 방식으로!


[회고]
기존 리스트를 swap하려고 하다 보니, 어렵게 생각하게됨..

"""


# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:

retList = ListNode(None)
head = retList

while list1 and list2:
if list1.val < list2.val:
head.next = list1
list1 = list1.next

else:
head.next = list2
list2 = list2.next

head = head.next

head.next = list1 or list2
return retList.next

150 changes: 150 additions & 0 deletions word-search/shinsj4653.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"""
[문제풀이]
# Inputs
- board: m*n grid of characters
- word: str
# Outputs
- word 가 grid 안에 있으면 true, 아니면 false
# Constraints
- 탐색: 상하좌우
- m == board.length
- n = board[i].length
- 1 <= m, n <= 6
- 1 <= word.length <= 15

- board, word => 무조건 대소문자로 구성
# Ideas
1. 퍼지면서 탐색 -> bfs?
q = cur.append(i, j, "")
q.pop() 해서
if 현재 w 가 word랑 같다면 그 즉시 bfs stop하고 return True
만약 bfs 끝까지 했는데도 안나오면 return False

bfs: q에 다음 원소 넣을 때 현재 값에 이어붙인문자가 w랑 어떤식으로 비교해야 맞는 조건절이 되는걸까?
=> cur_w의 len 값을 i로 사용하려했지만 w가 더 짧으면 idxError 뜰까봐 보류
=> 메모리 초과 오류 뜸..
=> 아..같은 자리를 방문하면 안됨!! 즉, 원복이 필요함!
-> 백트래킹으로 풀이 change

2. dfs로도 꼭 풀어보기!
백트래킹 복습 용으로 굿

board안의 숫자는 오직 대소문자 -> isalpha() 로 체킹 가능
=> 방문하면 0으로 바꾸기

풀기는 풀었지만..7090ms : Beats 7.34%

Follow up : Could you use search pruning to make your solution faster with a larger board
가지치기 기법 어떻게 도입할까??
=> cur_idx 하나 둬서, AB.. ABC -> 진행 도중, 하나라도 word랑 다르면 바로 그 경로 컷
=> 그래도 4587ms.. Beats 41.00%
=> 먼가 더 정석 성능 개선이 필요

해설 참고
=> word_idx를 이용, any문을 이용한 리팩토링
=> 해설 풀이 : 4385ms

[회고]
idx를 이용한 가지치기 방법 잘 알아두자
"""

# from collections import deque
# class Solution:
# def exist(board, word):
#
# q = deque([])
# n, m = len(board), len(board[0])
#
# q.append((0, 0, board[0][0]))
#
# dy = [-1, 0, 1, 0]
# dx = [0, 1, 0, -1]
#
# while q:
# cur_y, cur_x, cur_w = q.popleft()
#
# if cur_w == word:
# return True
#
# for i in range(3):
# ny = cur_y + dy[i]
# nx = cur_x + dx[i]
#
# if 0 <= ny < n and 0 <= nx < m:
# q.append((ny, nx, cur_w + board[ny][nx]))
#
# return False
#
# exist([["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], "ABCCDE")


class Solution:
Copy link
Preview

Copilot AI Apr 26, 2025

Choose a reason for hiding this comment

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

Multiple definitions of 'Solution' detected. Consider consolidating them into a single class or renaming one to prevent unintended overrides.

Suggested change
class Solution:
class SolutionDFS:

Copilot uses AI. Check for mistakes.

def exist(self, board: List[List[str]], word: str) -> bool:

n, m = len(board), len(board[0])

dy = [-1, 0, 1, 0]
dx = [0, 1, 0, -1]

v = [[False for _ in range(m)] for _ in range(n)]

def dfs(y, x, w):
#print('y, x : ', y, x)
#print('w: ', w)
if w == word:
return True

if len(w) >= len(word):
return False

for k in range(4):
ny = y + dy[k]
nx = x + dx[k]

if 0 <= ny < n and 0 <= nx < m and not v[ny][nx]:
v[ny][nx] = True
if dfs(ny, nx, w + board[ny][nx]):
return True
v[ny][nx] = False

for i in range(n):
for j in range(m):
if not v[i][j] and board[i][j] == word[0]:
v[i][j] = True
if dfs(i, j, board[i][j]):
return True
v[i][j] = False

return False

# 해설
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:

n, m = len(board), len(board[0])

dy = [-1, 0, 1, 0]
dx = [0, 1, 0, -1]

def dfs(y, x, idx):
if idx == len(word):
return True

if not (0 <= y < n and 0 <= x < m):
return False

if board[y][x] != word[idx]:
return False

temp = board[y][x]
board[y][x] = ""

for i in range(4):
if dfs(y + dy[i], x + dx[i], idx + 1):
return True

board[y][x] = temp
return False

return any(dfs(i, j, 0) for i in range(n) for j in range(m))