diff --git a/3sum/shinsj4653.py b/3sum/shinsj4653.py new file mode 100644 index 000000000..9c275cb66 --- /dev/null +++ b/3sum/shinsj4653.py @@ -0,0 +1,115 @@ +""" +Inputs: 정수 배열 nums + +Outputs: triplet 모음 배열 (중복 요소 X) + +Constraints: 3 < = nums.length <= 3 * 10^3 +-10^5 <= nums[i] <= 10^5 + +Time Complexity: + +각 수들의 위치 다르면서, 합이 0이 되는 조합들의 모음 결과 +n^3 은 안됨 + +하지만 가능한 모든 조합 구하기를 효율화 시키면 될듯? + +x 0 1 2 3 4 5 +0 [_,-1,0,1,-2,-5] +1 [_,_,1,2,-1,-4] +2 [_,_,_, +3 +4 +5 + +n^2 + + + +0 [1 2] +0 [1 3] +0 [1 4] +0 [1 5] + +0 1 [2 3] +0 1 [2 4] +0 1 [2 5] + +0 1 2[3 4] +0 1 2[3 5] + +0 1 2 3 [4 5] + +우선 대괄호 안 두 수 합 사전 만들고, +keys() 순회하며, +key = a, b -> a보다 작은 수 for문 돌며 합 구하기? +-> 그럼 시간복잡도 : O(n^3 보다 살짝 작은??) + +하지만 이 풀이로는 중복 후보가 나옴.. + + +Space Complexity: O(n^2) + +대괄호 내 두 수 조합 만큼의 크기가 사전 크기 + +# 1차 제출 코드 + +from collections import defaultdict + +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + n = len(nums) + v = defaultdict(int) + ret = [] + memo = set() + + for i in range(1, n): + for j in range(i + 1, n): + v[(i, j)] = nums[i] + nums[j] + + print(v) + for key in v.keys(): + a, b = key + print('key: a, b', a, b) + + for i in range(a): + if nums[i] + v[key] == 0 and \ + not (nums[i] in memo and nums[a] in memo and nums[b] in memo): + print('sum zero!') + memo.add(nums[i]) + memo.add(nums[a]) + memo.add(nums[b]) + ret.append([nums[i], nums[a], nums[b]]) + + + + return ret + +테스트 케이스만 정답.. +nums = +[-1,0,1,2,-1,-4,-2,-3,3,0,4] 인 경우는 오답 + +[회고] +완탐, dp로 해봐도 안 풀리면 투 포인터 생각해보기! +""" + +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + tuples = set() + nums.sort() + + for i in range(len(nums) - 2): + left, right = i + 1, len(nums) - 1 + + while left < right: + three_sum = nums[i] + nums[left] + nums[right] + if three_sum < 0: + left += 1 + elif three_sum > 0: + right -= 1 + else : + tuples.add((nums[i], nums[left], nums[right])) + left += 1 + right -= 1 + + return list(tuples) + diff --git a/climbing-stairs/shinsj4653.py b/climbing-stairs/shinsj4653.py new file mode 100644 index 000000000..1d815f8a1 --- /dev/null +++ b/climbing-stairs/shinsj4653.py @@ -0,0 +1,104 @@ +""" +계단 오르기 +맨 꼭대기 가는데 n steps만큼 걸림 + +매번 올라가는데 1 or 2 계단 오르기 가능! + +Inputs: n + +Outputs: how many distinct ways to get to the top? + +Constraints: 1 <= n <= 45 + +Time Complexity: O(2^n) + +계단 오르는 방법 중, 중복되지 않는 모든 가지 수 구하기 +우선 완탐으로 해보고, 그 다음 최적부분구조 할 수 있는지 체크 + +n = 2 + +1 1 -> dp[1] +2 0 -> dp + +2 dp(n - 2) + dp(n - 1) + 1 + +n = 3 +2 1 +1 1 1 => dp[2] 값 + +1 2 => 여기선 dp[2] 로 가면 안됨! + +1 2 +1 1 1 => dp[2] 값 + +2 1 => 이건 dp[1] 값 + + +n = 4 +1 3 => dp[3] +2 2 => dp[2] + +n = 5 +2 2 1 +2 1 2 +1 2 2 + +n = 6 + +5 1 +4 2 + +n = 7 + +6 1 +5 4 +4 3 + +특정 수를 구성하는 1과 2의 배열 가짓수들이 정해져있음!! + +한 호출마다 뻗어지는 가짓수, 즉 호출수를 모르겠어서 시간복잡도 모르겠음 + +점화식을 어떻게 세우지? + +3 +1 2 + +기저조건또 헷갈... n 3 // 2 + 1 + +하지만, 도식화해보니 +결국 dp(n) = dp(n - 1) + dp(n - 2) + +1 2 +1 1 1 => dp[2] 값 + +2 1 => 이건 dp[1] 값 + +Space Complexity: O(n) +dp 배열 n만큼의 크기 지님 + +""" + + +class Solution: + def climbStairs(self, n: int) -> int: + + if n == 1: + return 1 + + dp = [0] * (n + 1) + dp[0] = 1 + dp[1] = 1 + + def climb(n): + + if dp[n]: + return dp[n] + + else: + dp[n] += climb(n - 1) + climb(n - 2) + return dp[n] + + return climb(n) + +# sol = Solution() +# sol.climbStairs(3) diff --git a/product-of-array-except-self/shinsj4653.py b/product-of-array-except-self/shinsj4653.py new file mode 100644 index 000000000..d7e7426a0 --- /dev/null +++ b/product-of-array-except-self/shinsj4653.py @@ -0,0 +1,71 @@ +""" +Inputs: 정수형 배열 nums + +Outputs: 정수형 배열 answer + +Constraints: 2 <= nums.length <= 10^5 +-30 <= nums[i] <= 30 +The input is generated such that answer[i] is guaranteed to fit in a 32-bit integer. + +Time Complexity: 반드시 o(n) + +answer의 각 원소는 본인을 제외한 나머지 원소들 곱한 결과 + +나눗셈 연산도 불가능 +사전? +1 2 3 4 +2 4 6 8 +6 12 18 24 +24 48 72 96 + +dict[0] : +dict[1] : +dict[2] : +dict[3] : + +스택?? push, pop 하는데 o(1) 걸림 + +(1,0) (2,1) (3,2) (4,3) + +스택에서 뺀 다음, 다시 넣으면 while st에 갇히지 않나? + +# 풀이 본 이후 + +nums 1 2 3 4 + +1 1 1 1 + +1 1 2 6 : 기준 idx 전까지의 곱 + +24 12 4 1 : 기준 idx 후까지의 곱 + +=> 더 개선된 풀이: 누적곱을 덮어씌우는 방법 + +6 +24 12 8 6 + +24 + + +Space Complexity: O(1) +product 배열에 곱 결과를 덮어씌워도 무방 + +""" + + +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + + products = [1 for _ in range(len(nums))] + + before = 1 + for i in range(len(nums) - 1): + before *= nums[i] + products[i + 1] *= before + + after = 1 + for i in range(len(nums) - 1, 0, -1): + after *= nums[i] + products[i - 1] *= after + + return products diff --git a/valid-anagram/shinsj4653.py b/valid-anagram/shinsj4653.py new file mode 100644 index 000000000..21696faab --- /dev/null +++ b/valid-anagram/shinsj4653.py @@ -0,0 +1,75 @@ +""" +Inputs: two strings : s, t + +Outputs: t 가 s의 anagram인지에 대한 여부 + +Constraints: + +1 <= s.length, t.length <= 5 * 10^4 +s and t consist of lowercase English letters. + +Time Complexity: O(n) + +각 문자들의 등장 횟수만 같으면 되지 않나? + +s의 Counter 생성 +t의 Counter 생성 + +t Counter의 keys() 돌면서, +해당 값이 s Counter 배열 key에 있는지, 그리고 그 key의 value값이 서로 같은지 체크 + +Space Complexity: O(n) + +""" + +# 첫 코드 + +from collections import defaultdict + + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + s_dict, t_dict = defaultdict(int), defaultdict(int) + + for ch in s: + s_dict[ch] += 1 + + for ch in t: + t_dict[ch] += 1 + + for key in t_dict.keys(): + if key not in t_dict or t_dict[key] != s_dict[key]: + return False + + return True + +# 반례 발생 + +# s = "ab", t = "a" +# 어느 한 문자열을 기준으로 세면 안되는 것 같다 +# 두 count 사전을 모두 돌아야할듯. t keys()를 기준으로만 돌면 true가 나와버림. 답은 false인데 + + +from collections import defaultdict + + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + s_dict, t_dict = defaultdict(int), defaultdict(int) + + for ch in s: + s_dict[ch] += 1 + + for ch in t: + t_dict[ch] += 1 + + for key in t_dict.keys(): + if key not in s_dict or t_dict[key] != s_dict[key]: + return False + + for key in s_dict.keys(): + if key not in t_dict or t_dict[key] != s_dict[key]: + return False + + return True + diff --git a/validate-binary-search-tree/shinsj4653.py b/validate-binary-search-tree/shinsj4653.py new file mode 100644 index 000000000..070c63a0a --- /dev/null +++ b/validate-binary-search-tree/shinsj4653.py @@ -0,0 +1,101 @@ +""" +[문제풀이] +# Inputs +TreeNode 클래스 객체 + +# Outputs +valid 이진 탐색 트리인지에 대한 여부 + +# Constraints +The number of nodes in the tree is in the range [1, 104]. +-2^31 <= Node.val <= 2^31 - 1 + +# Ideas +root 배열 길이 기준으로 풀려고 했지만, root는 배열이 아닌 TreeNode 클래스의 객체이다. +1. bfs로 구현해보기 +트리 높이 기준으로 퍼지면서 탐색하는 모양이라 bfs 선택 + +cur = root +q.append(cur) + +while not q: + cur_node = q.popleft() + if cur_node == null: + continue + + if cur_node.right != null and (cur_node.left.val > cur_node.val or cur_node.right.val < cur_node.val): + return False + + else: + q.append(cur_node.left) + +먼가 조건문이 길어지는 것 같아 효율적인 풀이는 아닌 것 같지만..일단 시도! + +n이 node 개수라면 +Time: O(n), Space: O(n) + +from collections import deque + +class Solution: + def isValidBST(self, root: Optional[TreeNode]) -> bool: + q = deque([]) + q.append(root) + + while q: + cur_node = q.popleft() + if cur_node is None: + continue + + if cur_node.left is not None and cur_node.left.val >= cur_node.val: + return False + + elif cur_node.right is not None and cur_node.right.val <= cur_node.val: + return False + + else: + q.append(cur_node.left) + q.append(cur_node.right) + + return True + +- 반례 발생 +root = +[5,4,6,null,null,3,7] + +왜 BST가 아닌지 이해가 안간다.. +-> 3이 5보다 작아서 그렇다 +루트 기준 오른쪽은 자식 값들도 무조건 작아야한다. +그럼 한 단계 위의 값만 보면 안된다는 건데, 탐색 방법 바꿔야 할 것 같다 + +2. 재귀로 돌면서, 이 값보다는 커야한다는 배열을 인자로 함께 넘겨주기? +하지만, 어느 dfs에서 배열 원소들보다 본인 값이 커야하는지, 작야하는지 모름!! + +결국 풀이 참고 + +[회고] + + +""" + +# 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 +from collections import deque + +class Solution: + def isValidBST(self, root: Optional[TreeNode]) -> bool: + ret = True + + def dfs(node, low, high): + if not node: + return True + + if not (low < node.val < high): + return False + + return dfs(node.left, low, node.val) and dfs(node.right, node.val, high) + + return dfs(root, float("-inf"), float("inf"))