diff --git a/3sum/taurus09318976.py b/3sum/taurus09318976.py new file mode 100644 index 000000000..ea773d0f6 --- /dev/null +++ b/3sum/taurus09318976.py @@ -0,0 +1,49 @@ +# 이 문제는 1)정렬을 통해 중복을 처리, 2)투 포인터를 사용하여 효율적으로 탐색, +#3) 합이 0보다 작으면 left를 +1, 크면 right를 -1이동, 4)중복된 + +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + nums.sort() #중복된 숫자를 쉽게 처리하고, 투 포인터 기법을 사용하기 위해 배열을 정렬 + result = [] + + #첫번째 숫자를 선택하는 루프 + #마지막 두 숫자는 left와 right가 사용하므로 len(nums)-2해야 함 + #예: len(nums) = 4라면, range(2)=[0,1] + for i in range(len(nums) - 2): + #첫번째 숫자가 이전과 같으면 건너뜀 + if i > 0 and nums[i] == nums[i-1]: + continue + + #투 포인터 설정 : left는 첫번째 숫자 다음부터, right는 배열의 끝부터 설정 + left, right = i + 1, len(nums) - 1 + + while left < right: + total = nums[i] + nums[left] + nums[right] + #합이 0보다 작으면 left를 +1 + if total < 0: + left += 1 + #합이 0보다 크면 right를 -1이동 + elif total > 0: + right -= 1 + else: + #합이 0인 경우 처리 + result.append([nums[i], nums[left], nums[right]]) + #중복된 숫자 건너뛰기 + while left < right and nums[left] == nums[left + 1]: + left += 1 + while left < right and nums[right] == nums[right - 1]: + right -= 1 + #다음 가능한 조합을 찾기 위해 포인터를 이동 + left += 1 + right -= 1 + + return result + + + #시간 복잡도: O(n²) + #정렬: O(n log n) + #메인 루프: O(n²) + #공간 복잡도: O(1) (출력 배열 제외하고 추가적인 공간을 사용하지 않음) + + + diff --git a/climbing-stairs/taurus09318976.py b/climbing-stairs/taurus09318976.py new file mode 100644 index 000000000..fa2634406 --- /dev/null +++ b/climbing-stairs/taurus09318976.py @@ -0,0 +1,29 @@ +#이 문제는 피보나치 수열과 동일한 패턴을 가지고 있음. 피보나치 수열의 (n+1)번째 수와 같음 + +class Solution: + def climbStairs(self, n: int) -> int: + #n이 1이나 2인 경우는 바로 결과 반환 + if n == 1: + return 1 + if n == 2: + return 2 + + #첫 번째, 두 번째 계단의 방법 수 저장 + prev, curr = 1, 2 + + #세 번째 계단부터 n계단까지 계산 + for i in range(3, n + 1): + prev, curr = curr, prev + curr + + return curr + + + #시간 복잡도: O(n) + #for 루프가 n-2번 실행됨(3부터 n까지) + #각 반복에서 상수 시간(1)의 연산만 수행됨 + #따라서 전체 시간은 n에 비례함 + + #공간 복잡도: O(1) + #추가적인 배열이나 리스트를 사용하지 않음 + #두 개의 변수(prev, curr)만 사용함 + #입력 크기(n)가 아무리 커져도 사용하는 공간은 일정함 diff --git a/product-of-array-except-self/taurus09318976.py b/product-of-array-except-self/taurus09318976.py new file mode 100644 index 000000000..e2ddf438b --- /dev/null +++ b/product-of-array-except-self/taurus09318976.py @@ -0,0 +1,55 @@ +#이 문제는 배열의 각 요소 i를 제외한 나머지 요소들의 곱을 구하는 문제임 +#1)각 요소 i를 기준으로 왼쪽 숫자들의 곱과 오른쪽 숫자들의 곱을 따로 계산, 2)최종 결과는 왼쪽 곱과 오른쪽 곱의 곱 + +class Solution: + def productExceptSelf(self, nums: List[int]): + #입력 배열의 길이를 저장 + ##Example 1의 경우 : len(nums) = 4 + n = len(nums) + #결과를 저장할 배열을 곱셈의 항등원인 1로 모두 초기화 + #cf. 빈 집합의 곱은 1, 합은 0으로 정의됨 + ##answer = [1] * 4 = [1, 1, 1, 1] + answer = [1] * n + + #i를 기준으로 왼쪽 숫자들의 곱을 계산 + #왼쪽 곱의 초기값 + left_product = 1 + for i in range(n): + #현재 위치의 왼쪽 곱을 저장 + ##nums[0]의 왼쪽에는 아무 숫자도 없으므로, + ##아무것도 없는 상태의 곱은 1임. 따라서 answer[0]=1 + ##answer[1]=1 / answer[2]=2 / answer[3]=6 + answer[i] = left_product + #다음 위치를 위해 현재 수를 곱함 + ##left_product = 1 * 1 = 1 / left_product = 1 * 2 = 2 + ##left_product = 2 * 3 = 6 / left_product = 6 * 4 = 24 + left_product *= nums[i] + + ##첫 번째 for문 후 answer = [1, 1, 2, 6] + #i를 기준으로 오른쪽 숫자들의 곱 계산 및 최종 결과 생성 + right_product = 1 + #오른쪽에서 왼쪽으로 순회 + for i in range(n-1, -1, -1): + #현재 위치의 오른쪽 곱을 저장 + ##answer[3] = 6 * 1 = 6 / answer[2] = 2 * 1 = 2 + ##answer[1] = 1 * 1 = 1 / answer[1] = 1 * 1 = 1 + answer[i] *= right_product + #다음 위치를 위해 현재 수를 곱함 + ##right_product = 1 * 4 = 4 / right_product = 4 * 3 = 12 + ##right_product = 12 * 2 = 24 / right_product = 24 * 1 = 24 + right_product *= nums[i] + + + #최종 결과를 반환 + ##최종 answer = [24, 12, 8, 6] + return answer + + #시간 복잡도: O(n) + ##두 번의 선형 순회만 수행하며, 각 순회는 O(n) 시간이 소요 + #공간 복잡도: O(1) + ##추가적인 공간을 사용하지 않음 + ##단, 출력 배열은 문제의 요구사항이므로 제외 + + + + diff --git a/valid-anagram/taurus09318976.py b/valid-anagram/taurus09318976.py new file mode 100644 index 000000000..05a4cb47c --- /dev/null +++ b/valid-anagram/taurus09318976.py @@ -0,0 +1,31 @@ +#이 문제를 해결하기 위해선 1)두 문자열의 길이가 같은지 확인(길이가 다르면 아나그램이 될 수 없음), 2)char_count딕셔너리를 사용하여 첫번째 문자열의 문자별 개수를 확인, 3)두번째 문자열을 순회하면서 각 문자의 개수를 하나씩 감소시킴, 4)만약 두번째 문자열에 첫번째 문자열에 없는 문자가 있거나, 어떤 문자의 개수가 음수가 되면(첫번째 문자열에 있는 문자가 두번째 문자열에 없다는 의미) 아나그램이 아님 +class Solution: + def isAnagram(self, s: str, t: str): + # 두 문자열의 길이가 다르면 아나그램이 될 수 없음 + if len(s) != len(t): + return False + + # 각 문자의 개수를 저장할 빈 딕셔너리 + char_count = {} + + # 첫 번째 문자열의 각 문자를 순회 + for i in s: + #해당 문자가 없으면 0, 있으면 현재값 i를 반환하고, 각 문자의 개수 1을 더함 + char_count[i] = char_count.get(i, 0) + 1 + + # 두 번째 문자열의 문자별 개수만큼 char_count딕셔너리에서 빼기 + for i in t: + #첫번째 문자열에 없는 문자가 있는 경우 + if i not in char_count: + return False + + char_count[i] -= 1 + #char_count가 음수이므로 첫번째 문자열에 있는 문자가 두번째 문자열에 없다는 의미 + if char_count[i] < 0: + return False + + return True + + + #시간 복잡도: O(n), n= 문자열의 길이 + #공간 복잡도: O(1), 입력 크기(n)가 아무리 커져도 사용하는 공간이 일정함(영어 소문자만 사용하므로 최대 26개의 키만 저장하면 됨) diff --git a/validate-binary-search-tree/taurus09318976.py b/validate-binary-search-tree/taurus09318976.py new file mode 100644 index 000000000..2d8dfe066 --- /dev/null +++ b/validate-binary-search-tree/taurus09318976.py @@ -0,0 +1,41 @@ +# 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 + +#val: 노드의 값, left: 왼쪽 자식 노드, right: 오른쪽 자식 노드 +#helper 함수: 재귀적으로 BST의 유효성을 검사 +#lower: 현재 노드의 값이 가져야 하는 최소값 +#upper: 현재 노드의 값이 가져야 하는 최대값 + +class Solution: + def isValidBST(self, root: TreeNode): + def helper(node, lower=float('-inf'), upper=float('inf')): + if not node: + return True + + # BST 조건 검사 현재 노드의 값이 허용되는 범위를 벗어나는지 확인(벗어나면 false 반환) + if node.val <= lower or node.val >= upper: + return False + + # 왼쪽 서브트리 검사 (상한을 현재 노드의 값으로 설정) + if not helper(node.left, lower, node.val): + return False + + # 오른쪽 서브트리 검사 (하한을 현재 노드의 값으로 설정) + if not helper(node.right, node.val, upper): + return False + + return True + + return helper(root) + + #시간 복잡도: O(n) + #모든 노드를 한번씩 방문 + #공간 복잡도: O(n) + #재귀 호출 스택의 깊이가 트리의 높이만큼 필요 + + +