diff --git a/3sum/okyungjin.py b/3sum/okyungjin.py new file mode 100644 index 0000000000..c94426e0b0 --- /dev/null +++ b/3sum/okyungjin.py @@ -0,0 +1,63 @@ +# [문제 링크] +# https://leetcode.com/problems/3sum/ + +# [요구사항] +# - nums 배열이 주어지고, nums[i] + nums[j] + nums[k] 를 더했을 때 0이 는 숫자 3개의 배열을 반환한다. +# - 결과 집합은 1개 이상임 +# - 정답에 중복이 있으면 안 된다! +# - `3 <= nums.length <= 3000` + +# [접근법] +# 1. 포인터를 3개 선언하고, 하나를 고정한 채로 2Sum으로 나머지 해를 찾는다. +# 2. 중복 제거를 위해 포인터를 좌우로 움직여줘야 한다. + +# 시간 복잡도: O(N^2) +# 공간 복잡도: O(N) + +class Solution: + def threeSum(self, nums: list[int]) -> list[list[int]]: + size = len(nums) + answer = [] + + # 포인터를 사용하기 위해 배열을 정렬한다 + nums.sort() + + # 포인터 3개 중 하나를 고정한다. + for i in range(size - 2): + # 중복 제거 + if i > 0 and nums[i] == nums[i - 1]: + continue + + # 나머지 두 개의 포인터를 left, right라 한다. 양 끝을 할당 + left = i + 1 + right = size - 1 + + while left < right: + total = nums[i] + nums[left] + nums[right] + + # 합이 0보다 작으면 더 큰 숫자를 더해줘야 하므로 left를 우측으로 이동 + if total < 0: + left += 1 + + # 합이 0보다 크면 더 작은 숫자를 더해줘야 하므로 right을 좌측으로 이동 + elif total > 0: + right -= 1 + + # 숫자 3개가 합쳐서 0인 경우 (해를 찾음) + else: + # 정답에 추가하고 + answer.append([nums[i], nums[left], nums[right]]) + + # 포인터를 안쪽으로 한칸 이동한다. + left += 1 + right -= 1 + + # left 중복 제거를 위해 이동 + while left < right and nums[left] == nums[left - 1]: + left += 1 + + # right 중복 제거를 위해 이동 + while left < right and nums[right] == nums[right + 1]: + right -= 1 + + return answer diff --git a/climbing-stairs/okyungjin.py b/climbing-stairs/okyungjin.py new file mode 100644 index 0000000000..48104dd462 --- /dev/null +++ b/climbing-stairs/okyungjin.py @@ -0,0 +1,24 @@ +# 시간 복잡도: O(N) +# 공간 복잡도: O(1) + +# [요구사항] +# 1. 계단의 개수 n이 주어진다. +# 2. 계단은 1칸 또는 2칸 올라갈 수 있다. +# 3. 마지막 칸에 도달할 수 있는 경우의 수를 반환한다. + +# [접근법] +# 1. 계단에 올라올 수 있는 경우의 수는 전전칸까지의 경우의 수 (prev2) + 전칸까지의 경우의 수 (prev1) 를 더한 값이다. +class Solution: + def climbStairs(self, n: int) -> int: + if n <= 2: + return n + + prev2 = 1 # 전전칸 까지의 경우의 수 + prev1 = 2 # 전칸 까지의 경우의 수 + + for _ in range(2, n): + curr = prev2 + prev1 # 현재 계단 + prev2 = prev1 + prev1 = curr + + return prev1 diff --git a/product-of-array-except-self/okyungjin.py b/product-of-array-except-self/okyungjin.py new file mode 100644 index 0000000000..d81fc5e9f7 --- /dev/null +++ b/product-of-array-except-self/okyungjin.py @@ -0,0 +1,43 @@ +# [요구사항] +# 정수배열 nums가 주어진다. +# answer[i]는 nums[i]를 제외한 나머지 숫자의 곱이다. +# answer 배열을 반환한다. +# 단, 나눗셈 없이 O(N)으로 알고리즘을 작성해야한다. + +# [접근법] +# 처음에는 조합(combinations)으로 모든 경우를 구하려 했지만 +# 시간 복잡도가 O(N²) 이상이 되어 시간 초과가 발생했습니다. + +# (고민해보다가 AI의 도움을 받아 힌트를 얻었습니다.) +# 각 위치에서 왼쪽 누적 곱(prefix)과 오른쪽 누적 곱(suffix)을 각각 구해 곱하는 방식으로 풀었습니다. + +# 예시) +# nums = [1, 2, 3, 4] +# prefix = [1, 1, 2, 6] -> 각 위치의 왼쪽 원소들의 곱 +# suffix를 뒤에서부터 누적하면서 answer에 곱해줍니다. +# 최종 answer 배열 [24, 12, 8, 6] + +# 시간 복잡도 : O(N) +# 공간 복잡도 : O(1) (정답 배열 제외) +from typing import List + +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + size = len(nums) + + answer = [] + + prefix = 1 + for i in range(size): + answer.append(prefix) + prefix *= nums[i] + + suffix = 1 + for j in reversed(range(size)): + answer[j] *= suffix + suffix *= nums[j] + + return answer + +print(Solution().productExceptSelf([1,2,3,4])) +print(Solution().productExceptSelf([2,5,3,7])) diff --git a/valid-anagram/okyungjin.py b/valid-anagram/okyungjin.py new file mode 100644 index 0000000000..47b402d122 --- /dev/null +++ b/valid-anagram/okyungjin.py @@ -0,0 +1,41 @@ +# https://leetcode.com/problems/valid-anagram/description/ + +# [요구사항] +# 문자열 두 개가 주어졌을 때 애너그램이 맞는지 아닌지를 반환하는 문제 +# 애너그램이란? 하나의 단어나 구에 들어 있는 글자들을 모두, 각각 정확히 한 번씩만 사용해서 순서를 바꾸어 만든 다른 단어나 구를 의미한다. +# 두 문자열이 애너그램이면 True, 아니면 False 반환 + +# [접근법] +# 1. 길이가 다르면 애너그램이 아니므로 바로 False를 반환한다. +# 2. s의 문자 개수를 센 뒤, t를 순회하며 하나씩 차감한다. +# 3. 없는 문자이거나 개수가 부족한 문자를 만나면 False를 반환한다. +# 4. 모든 문자를 정상적으로 처리하면 True를 반환한다. + +# Time: O(N) +# Space: O(N) + +from collections import Counter + +class Solution01: + def isAnagram(self, s: str, t: str) -> bool: + if len(s) != len(t): + return False + + counter = Counter(s) + + for char in t: + if counter[char] >= 1: + counter[char] -= 1 + else: + return False + + return True + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + if len(s) != len(t): + return False + + # 파이썬은 == 로 값을 비교한다. + # 참조로 비교하려면 is 사용 + return Counter(s) == Counter(t)