Skip to content

Commit

Permalink
Merge pull request #823 from pmjuu/main
Browse files Browse the repository at this point in the history
[Lyla] Week 04
  • Loading branch information
pmjuu authored Jan 3, 2025
2 parents 03ded85 + ff0482e commit 694335e
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 0 deletions.
25 changes: 25 additions & 0 deletions coin-change/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from typing import List


class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
# dp[i]: i ๊ธˆ์•ก์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ์ตœ์†Œ ๋™์ „ ๊ฐœ์ˆ˜
dp = [float('inf')] * (amount + 1)
dp[0] = 0

for i in range(1, amount + 1):
for coin in coins:
if coin <= i:
dp[i] = min(dp[i], dp[i - coin] + 1)

return dp[amount] if dp[amount] != float('inf') else -1


# ์‹œ๊ฐ„ ๋ณต์žก๋„:
# - ์™ธ๋ถ€ ๋ฐ˜๋ณต๋ฌธ์€ ๊ธˆ์•ก(amount)์˜ ๋ฒ”์œ„์— ๋น„๋ก€ํ•˜๊ณ  -> O(n) (n์€ amount)
# - ๋‚ด๋ถ€ ๋ฐ˜๋ณต๋ฌธ์€ ๋™์ „์˜ ๊ฐœ์ˆ˜์— ๋น„๋ก€ํ•˜๋ฏ€๋กœ -> O(m) (m์€ coins์˜ ๊ธธ์ด)
# - ์ด ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n * m)

# ๊ณต๊ฐ„ ๋ณต์žก๋„:
# - dp ๋ฐฐ์—ด์€ ๊ธˆ์•ก(amount)์˜ ํฌ๊ธฐ๋งŒํผ์˜ ๊ณต๊ฐ„์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ O(n)
# - ์ถ”๊ฐ€ ๊ณต๊ฐ„ ์‚ฌ์šฉ์€ ์—†์œผ๋ฏ€๋กœ ์ด ๊ณต๊ฐ„ ๋ณต์žก๋„: O(n)
33 changes: 33 additions & 0 deletions merge-two-sorted-lists/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import Optional


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]:
head = ListNode()
current = head

while list1 and list2:
if list1.val <= list2.val:
current.next = list1
list1 = list1.next
else:
current.next = list2
list2 = list2.next

current = current.next

current.next = list1 or list2

return head.next

# ์‹œ๊ฐ„ ๋ณต์žก๋„:
# - ๋‘ ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ๋ณ‘ํ•ฉํ•˜๋ฏ€๋กœ O(n + m) => O(n) ์œผ๋กœ ํ‘œํ˜„
# ์—ฌ๊ธฐ์„œ n์€ list1์˜ ๊ธธ์ด, m์€ list2์˜ ๊ธธ์ด.
#
# ๊ณต๊ฐ„ ๋ณต์žก๋„:
# - ๊ธฐ์กด ๋…ธ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฏ€๋กœ O(1)
13 changes: 13 additions & 0 deletions missing-number/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import List


class Solution:
def missingNumber(self, nums: List[int]) -> int:
n = len(nums)
# 0๋ถ€ํ„ฐ n๊นŒ์ง€์˜ ์ˆซ์ž์˜ ํ•ฉ์„ ์ˆ˜ํ•™์  ํ•ฉ ๊ณต์‹์„ ์‚ฌ์šฉํ•ด ๊ณ„์‚ฐ
total_sum = n * (n + 1) // 2

return total_sum - sum(nums)

# ์‹œ๊ฐ„ ๋ณต์žก๋„ O(n)
# ๊ณต๊ฐ„ ๋ณต์žก๋„ O(1)
60 changes: 60 additions & 0 deletions palindromic-substrings/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Dynamic programming
class Solution:
def countSubstrings(self, s: str) -> int:
n = len(s)
dp = [[False] * n for _ in range(n)] # dp[i][j]๋Š” s[i:j+1]์ด ํŒฐ๋ฆฐ๋“œ๋กฌ์ธ์ง€ ๋‚˜ํƒ€๋ƒ„
count = 0

for length in range(1, n + 1): # ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ๊ธธ์ด
for i in range(n - length + 1): # ์‹œ์ž‘ ์ธ๋ฑ์Šค
j = i + length - 1 # ๋ ์ธ๋ฑ์Šค

if length == 1: # ๊ธธ์ด 1: ํ•ญ์ƒ ํŒฐ๋ฆฐ๋“œ๋กฌ
dp[i][j] = True
elif length == 2: # ๊ธธ์ด 2: ๋‘ ๋ฌธ์ž๊ฐ€ ๊ฐ™์œผ๋ฉด ํŒฐ๋ฆฐ๋“œ๋กฌ
dp[i][j] = (s[i] == s[j])
else: # ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ: ์–‘ ๋์ด ๊ฐ™๊ณ  ๋‚ด๋ถ€๊ฐ€ ํŒฐ๋ฆฐ๋“œ๋กฌ์ด๋ฉด ์ฐธ
dp[i][j] = (s[i] == s[j] and dp[i + 1][j - 1])

if dp[i][j]:
count += 1

return count


# ์‹œ๊ฐ„ ๋ณต์žก๋„:
# - ์ด์ค‘ ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๋ชจ๋“  ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์„ ํ™•์ธํ•˜๋ฏ€๋กœ O(n^2)
# - ๊ฐ ํ™•์ธ์€ O(1)์ด๋ฏ€๋กœ ์ตœ์ข…์ ์œผ๋กœ O(n^2)

# ๊ณต๊ฐ„ ๋ณต์žก๋„:
# - DP ํ…Œ์ด๋ธ”(dp)์€ O(n^2)์˜ ๊ณต๊ฐ„์„ ์‚ฌ์šฉ
# - ์ถ”๊ฐ€ ๋ณ€์ˆ˜๋Š” O(1)์ด๋ฏ€๋กœ ์ „์ฒด ๊ณต๊ฐ„ ๋ณต์žก๋„๋Š” O(n^2)


# ํˆฌ ํฌ์ธํ„ฐ ๋ฐฉ์‹
class Solution:
def countSubstrings(self, s: str) -> int:
def expand_around_center(left: int, right: int) -> int:
count = 0
# ์ขŒ์šฐ๋กœ ํ™•์žฅํ•˜๋ฉฐ ํŒฐ๋ฆฐ๋“œ๋กฌ์ธ์ง€ ํ™•์ธ
while left >= 0 and right < len(s) and s[left] == s[right]:
count += 1
left -= 1
right += 1
return count

total_count = 0
for i in range(len(s)):
# ํ™€์ˆ˜ ๊ธธ์ด ํŒฐ๋ฆฐ๋“œ๋กฌ (์ค‘์‹ฌ์ด ๋ฌธ์ž ํ•˜๋‚˜)
total_count += expand_around_center(i, i)
# ์ง์ˆ˜ ๊ธธ์ด ํŒฐ๋ฆฐ๋“œ๋กฌ (์ค‘์‹ฌ์ด ๋ฌธ์ž ๋‘ ๊ฐœ)
total_count += expand_around_center(i, i + 1)

return total_count

# ์‹œ๊ฐ„ ๋ณต์žก๋„:
# - ๊ฐ ๋ฌธ์ž์—์„œ ์ค‘์‹ฌ์„ ๊ธฐ์ค€์œผ๋กœ ํ™•์žฅํ•˜๋ฏ€๋กœ ์ตœ๋Œ€ O(n) ํ™•์žฅ
# - ๋ชจ๋“  ๋ฌธ์ž์— ๋Œ€ํ•ด ํ™•์žฅ์„ ์‹œ๋„ํ•˜๋ฏ€๋กœ O(n^2)

# ๊ณต๊ฐ„ ๋ณต์žก๋„:
# - ์ถ”๊ฐ€ ๊ณต๊ฐ„ ์‚ฌ์šฉ ์—†์ด O(1)
106 changes: 106 additions & 0 deletions word-search/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from typing import List


class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
n, m, word_length = len(board), len(board[0]), len(word)

def search(row, col, word_idx, visited):
# ๊ฒฝ๊ณ„ ์ฒดํฌ
if not (0 <= row < n and 0 <= col < m):
return False
# ์ด๋ฏธ ๋ฐฉ๋ฌธํ–ˆ๊ฑฐ๋‚˜, ๋ฌธ์ž๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
if (row, col) in visited or board[row][col] != word[word_idx]:
return False

# ๋ชจ๋“  ๋ฌธ์ž๋ฅผ ์ฐพ์€ ๊ฒฝ์šฐ
if word_idx == word_length - 1:
return True

# ํ˜„์žฌ ์…€์„ ๋ฐฉ๋ฌธํ•œ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ
visited.add((row, col))

# ์ธ์ ‘ํ•œ ์…€ ํ™•์ธ
found = (
search(row - 1, col, word_idx + 1, visited) or
search(row + 1, col, word_idx + 1, visited) or
search(row, col - 1, word_idx + 1, visited) or
search(row, col + 1, word_idx + 1, visited)
)
# ํ˜„์žฌ ์…€ ๋ฐฉ๋ฌธ ํ•ด์ œ (๋ฐฑํŠธ๋ž˜ํ‚น)
visited.remove((row, col))

return found

# ๋ชจ๋“  ์…€์—์„œ ํƒ์ƒ‰ ์‹œ์ž‘
for row in range(n):
for col in range(m):
if board[row][col] == word[0]:
if search(row, col, 0, set()):
return True

return False

# ํ’€์ด 1: ๋ฐฉ๋ฌธ ๊ธฐ๋ก์„ Set์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹
# ์‹œ๊ฐ„ ๋ณต์žก๋„:
# - ๊ฐ ์…€์—์„œ DFS๋ฅผ ์‹œ์ž‘ํ•˜๋ฉฐ, ๊ฐ DFS๋Š” ์ตœ๋Œ€ ๋„ค ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™ํ•˜๋ฉฐ word์˜ ๊ธธ์ด๋งŒํผ ์žฌ๊ท€ ํ˜ธ์ถœ์„ ์ง„ํ–‰ํ•จ.
# - ์ตœ์•…์˜ ๊ฒฝ์šฐ O(n * 4^k), ์—ฌ๊ธฐ์„œ n์€ ์ „์ฒด ์…€์˜ ๊ฐœ์ˆ˜, k๋Š” word์˜ ๊ธธ์ด.
# ๊ณต๊ฐ„ ๋ณต์žก๋„:
# - visited Set ์‚ฌ์šฉ: O(k), ์—ฌ๊ธฐ์„œ k๋Š” word์˜ ๊ธธ์ด.
# - ์žฌ๊ท€ ํ˜ธ์ถœ ์Šคํƒ: O(k), word์˜ ๊ธธ์ด๋งŒํผ ์žฌ๊ท€ ํ˜ธ์ถœ์ด ์Œ“์ž„.
# => ์ด ๊ณต๊ฐ„ ๋ณต์žก๋„: O(k)


class Solution:
def exist(self, board: list[list[str]], word: str) -> bool:
n, m = len(board), len(board[0])
word_length = len(word)

# ์กฐ๊ธฐ ์ข…๋ฃŒ: board์— word๋ฅผ ๊ตฌ์„ฑํ•  ์ถฉ๋ถ„ํ•œ ๋ฌธ์ž๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
from collections import Counter
board_counter = Counter(char for row in board for char in row)
word_counter = Counter(word)
if any(word_counter[char] > board_counter[char] for char in word_counter):
return False

def search(row, col, idx):
# ๊ธฐ๋ณธ ์กฐ๊ฑด: ๋ชจ๋“  ๋ฌธ์ž๊ฐ€ ์ผ์น˜ํ•œ ๊ฒฝ์šฐ
if idx == word_length:
return True

# ๊ฒฝ๊ณ„ ์กฐ๊ฑด ๋ฐ ๋ฌธ์ž ์ผ์น˜ ์—ฌ๋ถ€ ํ™•์ธ
if row < 0 or row >= n or col < 0 or col >= m or board[row][col] != word[idx]:
return False

# ํ˜„์žฌ ์…€์„ ๋ฐฉ๋ฌธํ•œ ๊ฒƒ์œผ๋กœ ์ž„์‹œ ํ‘œ์‹œ
temp = board[row][col]
board[row][col] = "#"

# ๋ชจ๋“  ๋ฐฉํ–ฅ ํƒ์ƒ‰
found = (
search(row - 1, col, idx + 1) or
search(row + 1, col, idx + 1) or
search(row, col - 1, idx + 1) or
search(row, col + 1, idx + 1)
)

# ํƒ์ƒ‰ ํ›„ ์…€ ๋ณต์›
board[row][col] = temp
return found

# ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ž์™€ ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ์…€์—์„œ DFS ์‹œ์ž‘
for i in range(n):
for j in range(m):
if board[i][j] == word[0] and search(i, j, 0):
return True

return False

# ํ’€์ด 2: Board๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•ด ๋ฐฉ๋ฌธ ๊ธฐ๋ก ๊ด€๋ฆฌ
# ์‹œ๊ฐ„ ๋ณต์žก๋„:
# - ๊ฐ ์…€์—์„œ DFS๋ฅผ ์‹œ์ž‘ํ•˜๋ฉฐ, ์ตœ๋Œ€ ๋„ค ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™ํ•˜๋ฉฐ word์˜ ๊ธธ์ด๋งŒํผ ์žฌ๊ท€ ํ˜ธ์ถœ์„ ์ง„ํ–‰ํ•จ.
# - ์ตœ์•…์˜ ๊ฒฝ์šฐ O(n * 4^k), ์—ฌ๊ธฐ์„œ n์€ ์ „์ฒด ์…€์˜ ๊ฐœ์ˆ˜, k๋Š” word์˜ ๊ธธ์ด.
# ๊ณต๊ฐ„ ๋ณต์žก๋„:
# - ์ถ”๊ฐ€ ๊ณต๊ฐ„ ์‚ฌ์šฉ ์—†์ด Board๋ฅผ ์ง์ ‘ ์ˆ˜์ •: O(1).
# - ์žฌ๊ท€ ํ˜ธ์ถœ ์Šคํƒ: O(k), word์˜ ๊ธธ์ด๋งŒํผ ์žฌ๊ท€ ํ˜ธ์ถœ์ด ์Œ“์ž„.
# => ์ด ๊ณต๊ฐ„ ๋ณต์žก๋„: O(k)

0 comments on commit 694335e

Please sign in to comment.