Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion 3sum/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,64 @@
# O(n^2) time, O(n) space
"""
https://leetcode.com/problems/3sum/
문제 설명:
정렬되지 않은 정수 배열 nums가 주어질 때,
세 수의 합이 0이 되는 모든 유니크한 triplet을 찾는 문제.
조건:
- 중복 조합은 허용되지 않음.
- 예: [-1, 0, 1]과 [0, -1, 1]은 같은 조합이므로 하나만 포함.
풀이 전략:
1. 배열을 정렬한다.
2. 첫 번째 수를 고정한 뒤, 나머지 두 수를 투포인터로 탐색한다.
- 합이 0보다 작으면 left를 증가
- 합이 0보다 크면 right를 감소
- 합이 0이면 정답에 추가, 중복 방지 처리도 함께 수행
TC: O(n^2), 정렬 O(n log n) + 투포인터 O(n^2)
SC: O(1), 출력 공간 result 제외
"""

from typing import List


class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
result = []

for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue # 중복 제거

left, right = i + 1, len(nums) - 1

while left < right:
total = nums[i] + nums[left] + nums[right]
# 조건 만족시 정답에 추가
if total == 0:
result.append([nums[i], nums[left], nums[right]])
# 같은 값을 가진 left가 여러 개 있다면, 중복 건너뜀
while left < right and nums[left] == nums[left + 1]:
left += 1
# 같은 값을 가진 right가 여러 개 있다면, 중복 건너뜀
while left < right and nums[right] == nums[right - 1]:
right -= 1
left += 1
right -= 1
# 총합이 0보다 작으면, 더 큰 수가 필요하니까 left를 오른쪽으로 이동
elif total < 0:
left += 1
# 총합이 0보다 크면, 더 작은 수가 필요하니까 right를 왼쪽으로 이동
else:
right -= 1

return result



# O(n^2) time, O(n) space
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
triplets = set()
Expand Down
54 changes: 54 additions & 0 deletions climbing-stairs/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
https://leetcode.com/problems/climbing-stairs/description/
한 번에 1계단 혹은 2계단 오를 수 있음
1: 1
2: 2
3: 1 + 1 + 1, 1 + 2, 2 + 1 => 3
4: 1 + 1 + 1 + 1, 1 + 1 + 2, 2 + 1 + 1, 1 + 2 + 1, 2 + 2 => 5
5: 1 + 1 + 1 + 1 + 1,
1 + 1 + 1 + 2,
1 + 1 + 2 + 1 + 1,
1 + 2 + 1 + 1,
2 + 1 + 1 + 1,
2 + 2 + 1,
2 + 1 + 2,
1 + 2 + 2,
=> 8
steps[n] = steps[n - 1] + steps[n - 2]
TC: O(n)
SC: O(n)
"""

class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
elif n == 2:
return 2
steps = [0] * n
steps[0] = 1
steps[1] = 2
for i in range(2, n):
steps[i] = steps[i - 2] + steps[i - 1]
return steps[n - 1]

"""
변수 2개로 최적화
공간 복잡도 O(1) 개선 풀이
"""
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
elif n == 2:
return 2

prev1 = 1
prev2 = 2

for i in range(2, n):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

range 루프에서 index를 사용하지 않기에 _ 사용 적절해보입니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@printjin-gmailcom 아 최적화하면서 index를 사용하지 않는 부분을 놓쳤네요. 감사합니다.

prev1, prev2 = prev2, prev1 + prev2
return prev2
42 changes: 42 additions & 0 deletions product-of-array-except-self/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
https://leetcode.com/problems/product-of-array-except-self/description/
문제: 정수 배열 nums가 주어졌을 때, 각 원소를 제외한 나머지 원소들의 곱을 반환하세요.
단, 나누기 연산을 사용하지 말고 O(n) 시간 복잡도로 해결하세요.
핵심 아이디어:
각 원소를 기준으로:
- 왼쪽에 있는 원소들의 곱
- 오른쪽에 있는 원소들의 곱
을 각각 곱해주면, 자기 자신을 제외한 전체 곱이 된다.
예시: [1, 2, 3, 4]
- 인덱스 0: 왼쪽(없음) × 오른쪽(2×3×4) = 24
- 인덱스 1: 왼쪽(1) × 오른쪽(3×4) = 12
- 인덱스 2: 왼쪽(1×2) × 오른쪽(4) = 8
- 인덱스 3: 왼쪽(1×2×3) × 오른쪽(없음) = 6
TC: O(n) - 배열을 두 번 순회
SC: O(1) - 결과 배열을 제외한 추가 공간 사용하지 않음
"""

from typing import List

class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
result = [1] * n # 결과 배열 초기화

# 1단계: 왼쪽에서 오른쪽으로 순회하며 왼쪽 원소들의 곱 계산
left_product = 1
for i in range(n):
result[i] = left_product # 현재 위치에 왼쪽 곱 저장
left_product *= nums[i] # 다음을 위해 현재 원소 곱하기

# 2단계: 오른쪽에서 왼쪽으로 순회하며 오른쪽 원소들의 곱 계산
right_product = 1
for i in range(n - 1, -1, -1):
result[i] *= right_product # 기존 왼쪽 곱에 오른쪽 곱 곱하기
right_product *= nums[i] # 다음을 위해 현재 원소 곱하기

return result
41 changes: 41 additions & 0 deletions valid-anagram/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드를 구조화하여 세가지 방법을 모두 제공한 것이 매우 좋습니다 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@printjin-gmailcom 이번에 재수 2번째 도전이라 여러 풀이로 도전했습니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안그래도 꽤나 익숙한 아이디이긴했어요 ㅎㅎ 코드가 다 깔끔하고 좋아서 많이 배워갑니다다. 5기 화이팅 :)

https://leetcode.com/problems/valid-anagram/description/
두 문자열이 애너그램인지 확인하는 함수를 작성하세요.
애너그램이란 두 문자열이 중복된 알파벳을 같은 개수만큼 포함하고 있는 것을 의미합니다.
TC: O(n)
SC: O(k), k = 알파벳 개수
"""

from collections import defaultdict

class Solution:
def isAnagram(self, s: str, t: str) -> bool:
def makeMap(s: str):
str_map = defaultdict(int)
for char in s:
str_map[char] += 1
return str_map

return makeMap(s) == makeMap(t)


"""
정렬 풀이
TC: O(nlogn)
SC: O(1)
"""
def isAnagram(s: str, t: str) -> bool:
return sorted(s) == sorted(t)

"""
Counter 사용 풀이
TC: O(n)
SC: O(k)
"""
from collections import Counter

def isAnagram(s: str, t: str) -> bool:
return Counter(s) == Counter(t)
70 changes: 70 additions & 0 deletions validate-binary-search-tree/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,73 @@
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드를 구조화하여 두 방법을 모두 제공한 것이 매우 좋습니다 :)

모든 왼쪽 서브트리는 현재 노드보다 작아야 하고,
모든 오른쪽 서브트리는 현재 노드보다 커야 한다.
이걸 위해서 범위(min/max)를 재귀로 내려보내야 한다.
TC: O(n), 모든 노드 1번씩 탐색
SC: O(h), 재귀 호출 스택, h는 트리 높이
"""

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 isValidBST(self, root: Optional[TreeNode]) -> bool:
def validate(node, low, high):
if not node:
return True # 비어있는 노드는 BST
# 현재 노드가 범위 밖이면 BST 조건 위배
if not (low < node.val < high):
return False
# 왼쪽은 최대값을 현재 노드보다 작게 제한
# 오른쪽은 최소값을 현재 노드보다 크게 제한
return (validate(node.left, low, node.val) and
validate(node.right, node.val, high))

return validate(root, float('-inf'), float('inf'))


"""
스택 풀이
- BST에서 중위 순회하면 항상 오름차순이어야 한다는 성질을 이용한 방법
- 중위 순회: 왼쪽 → 현재 노드 → 오른쪽
- BST는 중위 순회 시 값이 항상 증가해야 하므로, (오름차순)
이전 노드(prev)보다 현재 노드 값이 작거나 같으면 잘못된 BST
TC: O(n), 모든 노드 1번씩 탐색
SC: O(h), 최대 스택 깊이 = 트리 높이
"""

class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
stack = []
prev = None # 이전 중위 순회 값

while stack or root:
# 왼쪽 끝까지 탐색
while root:
stack.append(root)
root = root.left

root = stack.pop()

# 이전 값보다 작거나 같으면 BST 위반
if prev is not None and root.val <= prev:
return False
prev = root.val

# 오른쪽으로 이동
root = root.right

return True


# O(n) time, O(n) space

# Definition for a binary tree node.
Expand Down