diff --git a/best-time-to-buy-and-sell-stock/devyulbae.py b/best-time-to-buy-and-sell-stock/devyulbae.py new file mode 100644 index 0000000000..8417ec6256 --- /dev/null +++ b/best-time-to-buy-and-sell-stock/devyulbae.py @@ -0,0 +1,32 @@ +""" +Blind 75 - Best Time to Buy and Sell Stock +https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ + +시간복잡도 : O(n) +공간복잡도 : O(1) +풀이 : 한 번의 순회로 해결 + +prices = [7,1,5,3,6,4] + +price | min | max_profit + 7 | 7 | 0 + 1 | 1 | 0 + 5 | 1 | 4 + 3 | 1 | 4 + 6 | 1 | 5 + 4 | 1 | 5 + +""" +from typing import List + +class Solution: + def maxProfit(self, prices: List[int]) -> int: + max_profit = 0 + min_price = prices[0] + + for price in prices: + min_price = min(min_price, price) + max_profit = max(max_profit, price - min_price) + + return max_profit + diff --git a/coin-change/devyulbae.py b/coin-change/devyulbae.py new file mode 100644 index 0000000000..9c50d89639 --- /dev/null +++ b/coin-change/devyulbae.py @@ -0,0 +1,19 @@ +""" +Blind 75 - Coin Change +LeetCode Problem Link: https://leetcode.com/problems/coin-change/ +시간복잡도 : O(n*m) (n: amount, m: len(coins)) +공간복잡도 : O(n) + +""" +from typing import List +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + dp = [float('inf')] * (amount + 1) + dp[0] = 0 + + for coin in coins: # 각 동전마다 + for x in range(coin, amount + 1): # 금액 1 coin부터 amount까지 + dp[x] = min(dp[x], dp[x - coin] + 1) # 해당 금액을 만들기 위한 최소 동전 개수 갱신 + + return dp[amount] if dp[amount] != float('inf') else -1 # amount를 만들 수 없는 경우 -1 반환 + diff --git a/decode-ways/devyulbae.py b/decode-ways/devyulbae.py index 92e25da9a6..b1c88348a9 100644 --- a/decode-ways/devyulbae.py +++ b/decode-ways/devyulbae.py @@ -1,3 +1,39 @@ +""" +Blind75 - Decode Ways +https://leetcode.com/problems/decode-ways/ +시간복잡도: O(n) +공간복잡도: O(n) +풀이 : 메모이제이션 + DFS를 활용한 재귀 풀이 + +아..DP로는 못 풀겠어서 풀이 봤습니다. 강의나 책을 봐야겠군요 class Solution: def numDecodings(self, s: str) -> int: - + 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] +""" +class Solution: + def numDecodings(self, s: str) -> int: + memo = {len(s): 1} + + def dfs(start): + if start in memo: + return memo[start] + + if s[start] == "0": + memo[start] = 0 + elif start + 1 < len(s) 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) + + diff --git a/encode-and-decode-strings/devyulbae.py b/encode-and-decode-strings/devyulbae.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/find-minimum-in-rotated-sorted-array/devyulbae.py b/find-minimum-in-rotated-sorted-array/devyulbae.py new file mode 100644 index 0000000000..65e0e3bbdc --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/devyulbae.py @@ -0,0 +1,24 @@ +""" +Blind 75 - Find Minimum in Rotated Sorted Array +LeetCode Problem Link: https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/ +시간복잡도 : O(log n) +공간복잡도 : O(1) +풀이 : 이진 탐색 +중간점 기준으로 nums[mid-1] > nums[mid] 이면 mid가 최소값 +그렇지 않으면 왼쪽 절반이 정렬되어 있는지 확인해서 왼쪽 절반 or 오른쪽 절반으로 탐색 범위를 좁혀나감 +만약 발견되지 않았다면 nums[0]이 최소값 +""" +from typing import List +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] + diff --git a/group-anagrams/devyulbae.py b/group-anagrams/devyulbae.py new file mode 100644 index 0000000000..9593562bf5 --- /dev/null +++ b/group-anagrams/devyulbae.py @@ -0,0 +1,24 @@ +""" +Blind 75 - Group Anagrams +LeetCode Problem: https://leetcode.com/problems/group-anagrams/ +시간복잡도 : O(N * K) (N은 strs의 길이, K는 strs 내 문자열의 최대 길이) +공간복잡도 : O(N * K) +풀이 : 해시맵을 이용한 풀이 +ASCII 문자를 이용하여 각 문자열의 문자 개수를 세어 이를 키로 사용하여 해시맵에 저장한다 + +""" + +from typing import List +from collections import defaultdict +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + anagrams = defaultdict(list) + + for s in strs: + count = [0] * 26 + for char in s: + count[ord(char) - ord('a')] += 1 + anagrams[tuple(count)].append(s) + + return list(anagrams.values()) + diff --git a/implement-trie-prefix-tree/devyulbae.py b/implement-trie-prefix-tree/devyulbae.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/maximum-depth-of-binary-tree/devyulbae.py b/maximum-depth-of-binary-tree/devyulbae.py new file mode 100644 index 0000000000..88d50a449b --- /dev/null +++ b/maximum-depth-of-binary-tree/devyulbae.py @@ -0,0 +1,24 @@ +""" +Blind 75 - Maximum Depth of Binary Tree +LeetCode Problem Link: https://leetcode.com/problems/maximum-depth-of-binary-tree/ +시간복잡도 : O(n) +공간복잡도 : O(n) +풀이 : 재귀를 이용한 깊이 우선 탐색(DFS) +자식 노드부터 부모 노드로 거슬러 올라가며 최대 깊이를 계산합니다. +종료 조건 - left와 right가 모두 None인 경우 (1+max(0,0))을 반환하며 재귀가 종료됩니다. +""" + +from typing import Optional +# 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: + if not root: + return 0 + + return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right)) + diff --git a/merge-two-sorted-lists/devyulbae.py b/merge-two-sorted-lists/devyulbae.py new file mode 100644 index 0000000000..a4c1d5f7f8 --- /dev/null +++ b/merge-two-sorted-lists/devyulbae.py @@ -0,0 +1,35 @@ +""" +Blind 75 - Merge Two Sorted Lists +LeetCode Problem Link: https://leetcode.com/problems/merge-two-sorted-lists/ +시간복잡도 : O(n+m) +공간복잡도 : O(1) +풀이 : (알고달레 답안) +각 링크드 리스트에 포인터를 두고, 더 작은 값을 가진 노드를 결과 리스트에 추가하다가 한 쪽 리스트가 끝나면 나머지 리스트를 결과 리스트에 추가한다. +마지막에 첫번째 노드를 반환한다. +""" +from typing import Optional + +# 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]: + dummy = ListNode() + tail = dummy + + while list1 and list2: + if list1.val < list2.val: + tail.next = list1 + list1 = list1.next + else: + tail.next = list2 + list2 = list2.next + + tail = tail.next + + tail.next = list1 or list2 + return dummy.next + diff --git a/word-break/devyulbae.py b/word-break/devyulbae.py new file mode 100644 index 0000000000..52e82747cf --- /dev/null +++ b/word-break/devyulbae.py @@ -0,0 +1,23 @@ +""" +Blind 75 - Word Break +LeetCode Problem: https://leetcode.com/problems/word-break/ +시간복잡도 : O(n^2) +공간복잡도 : O(n) +풀이 : 다이나믹 프로그래밍을 이용한 풀이 +문자열 s의 길이를 n이라 할 때, dp[i]를 s의 처음부터 i-1번째 문자까지의 부분 문자열이 +단어 사전에 있는 단어들로 구성될 수 있는지를 나타내는 불리언 값이라고 정의한다. +""" +from typing import List +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + dp = [False] * (len(s) + 1) + dp[0] = True + + word_set = set(wordDict) + for i in range(1, len(s) + 1): + for j in range(i): + if dp[j] and s[j:i] in word_set: # 0~j-1까지 문자열이 단어사전에 있고, j~i-1까지 문자열이 단어사전에 있는 경우 + dp[i] = True + break + + return dp[len(s)] diff --git a/word-search/devyulbae.py b/word-search/devyulbae.py new file mode 100644 index 0000000000..2acae3baf6 --- /dev/null +++ b/word-search/devyulbae.py @@ -0,0 +1,50 @@ +""" +Blind 75 - Word Search +LeetCode Problem Link: https://leetcode.com/problems/word-search/ +시간복잡도 : +공간복잡도 : +풀이 : DFS + 백트래킹 +1. 전체 순회하여 단어의 첫 글자와 일치하는 지점 찾기 +2. 첫 글자 List에 대해서 DFS 수행하여 있다면 return True +3. 없다면 return False +visited를 별도로 저장하는 대신 board의 글자를 임시로 변경하여 방문처리(backtracking) +-> 잊지 말고 board[i][j] = char 로 원상복구 시키기 +""" +from typing import List + +class Solution: + dx = [0, 1, 0, -1] + dy = [1, 0, -1, 0] + + def dfs(self, board, word, i, j, word_index): + # 종료 조건 + if word_index == len(word): + return True + + # 실패 조건 + if (i < 0 or i >= len(board) or + j < 0 or j >= len(board[0]) or + board[i][j] != word[word_index]): + return False + char = board[i][j] + board[i][j] = '#' + # 4방향 탐색 + for direction in range(4): + ni = i + self.dx[direction] + nj = j + self.dy[direction] + if self.dfs(board, word, ni, nj, word_index + 1): + board[i][j] = char + return True + board[i][j] = char + return False + + def exist(self, board: List[List[str]], word: str) -> bool: + rows = len(board) + cols = len(board[0]) + + for i in range(rows): + for j in range(cols): + if self.dfs(board, word, i, j, 0): + return True + return False +