From a353a021e27316a2533a3d99655d2fd799cd1cb9 Mon Sep 17 00:00:00 2001 From: Lyla Date: Tue, 31 Dec 2024 14:55:00 -0500 Subject: [PATCH 1/4] solve 3 --- merge-two-sorted-lists/pmjuu.py | 33 ++++++++++ missing-number/pmjuu.py | 13 ++++ word-search/pmjuu.py | 106 ++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 merge-two-sorted-lists/pmjuu.py create mode 100644 missing-number/pmjuu.py create mode 100644 word-search/pmjuu.py diff --git a/merge-two-sorted-lists/pmjuu.py b/merge-two-sorted-lists/pmjuu.py new file mode 100644 index 000000000..2d9904c77 --- /dev/null +++ b/merge-two-sorted-lists/pmjuu.py @@ -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) diff --git a/missing-number/pmjuu.py b/missing-number/pmjuu.py new file mode 100644 index 000000000..5332417e2 --- /dev/null +++ b/missing-number/pmjuu.py @@ -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) diff --git a/word-search/pmjuu.py b/word-search/pmjuu.py new file mode 100644 index 000000000..a119c032a --- /dev/null +++ b/word-search/pmjuu.py @@ -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) From fdf1daead93944aaa7e289938fe3dc88a4f26f9b Mon Sep 17 00:00:00 2001 From: Lyla Date: Wed, 1 Jan 2025 12:02:30 -0500 Subject: [PATCH 2/4] solve 1 --- palindromic-substrings/pmjuu.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 palindromic-substrings/pmjuu.py diff --git a/palindromic-substrings/pmjuu.py b/palindromic-substrings/pmjuu.py new file mode 100644 index 000000000..d3b343552 --- /dev/null +++ b/palindromic-substrings/pmjuu.py @@ -0,0 +1,30 @@ +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) From 10d3c49b6aad534e885eb593e02974d710a9b777 Mon Sep 17 00:00:00 2001 From: Lyla Date: Wed, 1 Jan 2025 12:29:33 -0500 Subject: [PATCH 3/4] add second solution --- palindromic-substrings/pmjuu.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/palindromic-substrings/pmjuu.py b/palindromic-substrings/pmjuu.py index d3b343552..41c4ddf8c 100644 --- a/palindromic-substrings/pmjuu.py +++ b/palindromic-substrings/pmjuu.py @@ -1,3 +1,4 @@ +# Dynamic programming class Solution: def countSubstrings(self, s: str) -> int: n = len(s) @@ -28,3 +29,32 @@ def countSubstrings(self, s: str) -> int: # 공간 복잡도: # - 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) From ff0482ef6054f0719df789edac2e760b63d9521c Mon Sep 17 00:00:00 2001 From: Lyla Date: Thu, 2 Jan 2025 12:12:24 -0500 Subject: [PATCH 4/4] solve --- coin-change/pmjuu.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 coin-change/pmjuu.py diff --git a/coin-change/pmjuu.py b/coin-change/pmjuu.py new file mode 100644 index 000000000..e9cc8c483 --- /dev/null +++ b/coin-change/pmjuu.py @@ -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)