From dfd36e753faa17da5afdd10927e01adebcfe6a05 Mon Sep 17 00:00:00 2001 From: jongwanra Date: Mon, 28 Jul 2025 07:35:01 +0900 Subject: [PATCH 1/6] add valid-anagram solution --- valid-anagram/jongwanra.py | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 valid-anagram/jongwanra.py diff --git a/valid-anagram/jongwanra.py b/valid-anagram/jongwanra.py new file mode 100644 index 000000000..15c5f462a --- /dev/null +++ b/valid-anagram/jongwanra.py @@ -0,0 +1,50 @@ +""" +[Problem] +https://leetcode.com/problems/valid-anagram/ + +[Brain Storm] +아나그램인 경우, true, 아니면 false 반환 +동일한 알파벳이 중복되어 사용될 수 있다. + +[Plan] +1. s에 대해 for-loop을 순회하며 alphabet-count 형태로 map을 만든다. +2. t에 대해 for-loop을 순회한다. + 2-1. t의 alphabet이 alphabet-count > 0 인 경우, count -= 1을 한다. + 2-2. 없는 경우, false로 return 한다. +3. alphabet-count 가 빈 경우 true 그렇지 않으면 false를 반환한다. + +[Complexity] +t.length = N +s.length = M + +Time: O(N + M) +Space: O(M) +""" + + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + alphabet_to_count = {} + for alphabet in s: + alphabet_to_count[alphabet] = alphabet_to_count.get(alphabet, 0) + 1 + + for alphabet in t: + count = alphabet_to_count.get(alphabet, -1) + if count == -1: + return False + + count -= 1 + if count == 0: + alphabet_to_count.pop(alphabet) + else: + alphabet_to_count[alphabet] = count + + return len(alphabet_to_count) == 0 + + + +sol = Solution() +# Normal Case +print(sol.isAnagram("anagram", "nagaram")) +print(sol.isAnagram("rat", "car")) + From d0ecca6b5ea2d38901271baac064eafa3be4074e Mon Sep 17 00:00:00 2001 From: jongwanra Date: Mon, 28 Jul 2025 18:56:22 +0900 Subject: [PATCH 2/6] add climbing-stairs solution --- climbing-stairs/jongwanra.py | 98 ++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 climbing-stairs/jongwanra.py diff --git a/climbing-stairs/jongwanra.py b/climbing-stairs/jongwanra.py new file mode 100644 index 000000000..4dd8bea0f --- /dev/null +++ b/climbing-stairs/jongwanra.py @@ -0,0 +1,98 @@ +""" +[Problem] +https://leetcode.com/problems/climbing-stairs/ + +[Brainstorming] +한 번에 갈 수 있는 계단: 1 or 2 +갈 수 있는 경우의 수를 구해야 하는 문제 +constraints: 1 <= n <= 45 + +n = 1, 1 +n = 2, 2 +n = 3, 3 +n = 4, 5 +... +f(n) = f(n - 1) + f(n - 2) + +[Plan] +1. n + 1 크기의 list를 만든다. +2. list[1] = 1, list[2] = 2를 대입한다. +3. for-loop를 3부터 n까지 순회한다. + 3-1. Bottom-Top 방식으로 n까지 값을 채워간다. +4. n값을 반환한다. + +[Complexity] +Time: O(n) +Space: O(n) +""" + + +class Solution: + def climbStairs(self, n: int) -> int: + answer = [0, 1, 2] + for index in range(3, n + 1): + answer.append(answer[index - 1] + answer[index - 2]) + + return answer[n] + + """ + another solution + ref: https://www.algodale.com/problems/climbing-stairs/ + [Summary] + Bottom Top 방식인데 공간을 최적화하여 접근 + [Complexity] + Time: O(n) + Space: O(1) - Space Optimization + + [Plan] + 1. prev = 1, cur = 2를 저장한다. + 2. for-loop를 순회한다. 3 to n + 1 + + """ + + def climbStairs2(self, n: int) -> int: + if n <= 3: + return n + + prev, cur = [2, 3] + for index in range(4, n + 1): + tmp = cur + cur = cur + prev + prev = tmp + return cur + + """ + another solution + ref: https://www.algodale.com/problems/climbing-stairs/ + [Summary] + Top-Bottom으로 재귀적으로 접근 + [Complexity] + Time: O(n) + Space: O(n) + """ + + def climbStairs3(self, n: int) -> int: + cache = {} + + def dfs(num: int) -> int: + nonlocal cache + if num <= 3: + return num + if num in cache: + return cache[num] + cache[num] = dfs(num - 1) + dfs(num - 2) + return cache[num] + + return dfs(n) + + +sol = Solution() + +# Normal Case +print(sol.climbStairs3(2) == 2) +print(sol.climbStairs3(3) == 3) +print(sol.climbStairs3(4) == 5) +print(sol.climbStairs3(5) == 8) +print(sol.climbStairs3(38)) +# Edge Case +print(sol.climbStairs3(1) == 1) \ No newline at end of file From 33798503ecf06b17479e5e90c7b84f8dc21ee7ce Mon Sep 17 00:00:00 2001 From: jongwanra Date: Mon, 28 Jul 2025 18:57:02 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EC=A4=84=EB=B0=94=EA=BF=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- climbing-stairs/jongwanra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/climbing-stairs/jongwanra.py b/climbing-stairs/jongwanra.py index 4dd8bea0f..7a7532e72 100644 --- a/climbing-stairs/jongwanra.py +++ b/climbing-stairs/jongwanra.py @@ -95,4 +95,4 @@ def dfs(num: int) -> int: print(sol.climbStairs3(5) == 8) print(sol.climbStairs3(38)) # Edge Case -print(sol.climbStairs3(1) == 1) \ No newline at end of file +print(sol.climbStairs3(1) == 1) From a7ee851e2d4e2ccc48ce8d9936ea06c284d74049 Mon Sep 17 00:00:00 2001 From: jongwanra Date: Tue, 29 Jul 2025 07:44:50 +0900 Subject: [PATCH 4/6] add product-of-array-except-self solution --- product-of-array-except-self/jongwanra.py | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 product-of-array-except-self/jongwanra.py diff --git a/product-of-array-except-self/jongwanra.py b/product-of-array-except-self/jongwanra.py new file mode 100644 index 000000000..7416b1054 --- /dev/null +++ b/product-of-array-except-self/jongwanra.py @@ -0,0 +1,52 @@ +""" +[Problem] +https://leetcode.com/problems/product-of-array-except-self/ + +배열 nums가 주어졌을 때, 배열 answer를 반환해라. +answer[i]는 nums[i]를 제외한 모든 요소들의 곱이어야 한다. + +[Brainstorming] +전체 요소들의 곱을 구한다. 해당 요소만 나눗셈으로 제외한다. +-> 이 방식은 다루기 어렵다. 0이 들어갈 수 있음. + +Brute Force 방식으로 밖에 떠오르지 않음.. +O(n)으로 어떻게 풀 수 있지? + +""" +from typing import List +class Solution: + """ + another solution + ref: https://www.algodale.com/problems/product-of-array-except-self/ + + [Brainstorming] + 각 인덱스 요소를 제외한 요소들의 곱은 아래와 같다. + nums[0] * nums[1] * ... * nums[index - 1] * nums[index + 1] * ... nums[len(nums) - 1] + 즉, nums[index] 전의 곱을 누적한 배열과, nums[index] 이후의 곱을 누적한 배열을 구하면 답을 구할 수 있다. + + [Complexity] + N: nums.length + Time: O(N) + Space: O(N) + """ + def productExceptSelf(self, nums: List[int]) -> List[int]: + before_products = [1] * len(nums) + for index in range(1, len(nums)): + before_products[index] = before_products[index - 1] * nums[index- 1] + + after_products = [1] * len(nums) + for index in range(len(nums) - 2, -1, -1): + after_products[index] = after_products[index + 1] * nums[index + 1] + + answer = [] + for index in range(len(nums)): + answer.append(before_products[index] * after_products[index]) + + return answer + +sol = Solution() +print(sol.productExceptSelf([1,2,3,4])) +print(sol.productExceptSelf([-1,1,0,-3,3])) +print(sol.productExceptSelf([2,3,4,5])) + + From c5ccea01e5c4adfe56fbf870763b2e744e532363 Mon Sep 17 00:00:00 2001 From: jongwanra Date: Thu, 31 Jul 2025 10:34:15 +0900 Subject: [PATCH 5/6] add validate-binary-search-tree solution --- validate-binary-search-tree/jongwanra.py | 67 ++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 validate-binary-search-tree/jongwanra.py diff --git a/validate-binary-search-tree/jongwanra.py b/validate-binary-search-tree/jongwanra.py new file mode 100644 index 000000000..3833ffd0d --- /dev/null +++ b/validate-binary-search-tree/jongwanra.py @@ -0,0 +1,67 @@ +""" +[Problem] +https://leetcode.com/problems/validate-binary-search-tree/ + +[Brainstorming] +BST가 유효한지를 검증하는 문제. +1 <= number of nodes <= 10^4(100,000) + +[Plan] +1. Tree를 DFS를 이용하여 만든다. +2. 실제로 입력을 넣어보며, 존재하지 않는 경우 False를 반환한다. +""" +from typing import Optional +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +class Solution: + """ + Attempt 1 - My Solution (incorrect) + 이 풀이의 경우, 자기 자신과 자기 자식 노드들 까지만으로 한정한다. + 따라서, BST를 제대로 검증할 수 없다. + root = [5,4,6,null,null,3,7] 인 경우에는 검증할 수 없다. (Edge Case) + """ + def isValidBST1(self, root: Optional[TreeNode]) -> bool: + invalid_flag = False + def dfs(node:Optional[TreeNode])->None: + nonlocal invalid_flag + if invalid_flag: + return + + if not node: + return + + if node.left and node.left.val > node.val: + invalid_flag = True + return + if node.right and node.right.val < node.val: + invalid_flag = True + return + + dfs(node.left) + dfs(node.right) + + dfs(root) + return not invalid_flag + """ + Attempt 2 - Another Solution + ref: https://www.algodale.com/problems/validate-binary-search-tree + [Complexity] + N: number of nodes in trees + Time: O(N) => Traverse all nodes in the tree. + Space: worst case: O(N), best case: O(log N) + """ + + def isValidBST(self, root:Optional[TreeNode])->bool: + def dfs(node:Optional[TreeNode], min_limit:int, max_limit:int)->bool: + if not node: + return True + if not (min_limit < node.val < max_limit): + return False + + return dfs(node.left, min_limit, node.val) and dfs(node.right, node.val, max_limit) + + From affba32f718aab043a7e51c258c4de2679d7e72f Mon Sep 17 00:00:00 2001 From: jongwanra Date: Thu, 31 Jul 2025 10:36:27 +0900 Subject: [PATCH 6/6] add 3sum solution --- 3sum/jongwanra.py | 106 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 3sum/jongwanra.py diff --git a/3sum/jongwanra.py b/3sum/jongwanra.py new file mode 100644 index 000000000..621af0fb8 --- /dev/null +++ b/3sum/jongwanra.py @@ -0,0 +1,106 @@ +""" +[Problem] +https://leetcode.com/problems/3sum/description/ + +[Brainstorm] +3 <= nums.length <= 3,000 +Brute Force: O(N^3) => 27,000,000,000 => time limited +O(N^2)의 풀이는 시간 제한에 걸리지 않을 것으로 보인다. 3,000 * 3,000 => 9,000,000 + +[Plan] +1. map을 설정한다. key = elements value: index list +2. nested-loop을 순회한다. + 2-1. i == j인 경우 제외 + 2-2. map에서 동일한 인덱스인 경우 제외하고 구한다. + +""" + +from typing import List + + +class Solution: + """ + Attempt-1 My solution (incorrect) + time limited + """ + + def threeSum1(self, nums: List[int]) -> List[List[int]]: + map = {} + for index in range(len(nums)): + values = map.get(nums[index], []) + values.append(index) + map[nums[index]] = values + + triplets = set() + for i in range(len(nums)): + for j in range(len(nums)): + if i == j: + continue + complement = -(nums[i] + nums[j]) + # print(f"nums[{i}]={nums[i]}, nums[{j}]={nums[j]} , complement={complement}") + if complement in map: + values = map[complement] + for k in values: + if k == i or k == j: + continue + triplets.add(tuple(sorted([nums[i], nums[j], nums[k]]))) + return list(triplets) + + """ + Attempt-2 Another solution + ref: https://www.algodale.com/problems/3sum/ + + """ + + def threeSum2(self, nums: List[int]) -> List[List[int]]: + triplets = set() + + for index in range(len(nums) - 2): + seen = set() + for j in range(index + 1, len(nums)): + complement = -(nums[index] + nums[j]) + if complement in seen: + triplet = [nums[index], nums[j], complement] + triplets.add(tuple(sorted(triplet))) + seen.add(nums[j]) + + return list(triplets) + + """ + Attempt-3 Another solution + ref: https://www.algodale.com/problems/3sum/ + + [Plan] + two-pointer로 접근한다. + + [Complexity] + N: nums.length + Time: O(N^2) + Space: O(1) + """ + + def threeSum3(self, nums: List[int]) -> List[List[int]]: + triplets = set() + nums.sort() + + for index in range(len(nums) - 2): + left = index + 1 + right = len(nums) - 1 + + while left < right: + three_sum = nums[index] + nums[left] + nums[right] + if three_sum < 0: + left += 1 + continue + if three_sum > 0: + right -= 1 + continue + triplets.add((nums[index], nums[left], nums[right])) + left += 1 + right -= 1 + return list(triplets) + + +sol = Solution() +print(sol.threeSum3([-1, 0, 1, 2, -1, 4])) +