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
36 changes: 36 additions & 0 deletions 3sum/liza0525.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,39 @@ def threeSum(self, nums: List[int]) -> List[List[int]]:
results.add((nums[i], nums[left], nums[right]))
left, right = left + 1, right - 1
return list(results)


# 7기 풀이
# 시간 복잡도: O(n^2)
# - 배열 정렬: O(n log n)
# - for문과 while문을 이용한 이중 loop문으로 탐색: O(n^2)
# - 전체 시간 복잡도는 O(n^2)
# 공간 복잡도: O(1)
# - 결과 저장 공간은 output이므로 제외 (변수 이름: results)
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort() # 정렬을 한 번 한 후
results = set()

# for 문과 투포인터를 이용해 문제를 푼다.
for i in range(len(nums) - 2):
# i번째와 i - 1 번째 값이 같은 경우에는 이미 이전 loop에서 계산했기 때문에 다음 루프로 넘긴다
if i > 0 and nums[i] == nums[i - 1]:
continue

# 포인터 지정
left, right = i + 1, len(nums) - 1
while left < right:
result = nums[i] + nums[left] + nums[right]
if result < 0:
# 합이 0보다 작다면 요소의 값을 올려야 하기 때문에 left를 올린다. (nums는 정렬이 된 상태)
left += 1
elif result > 0:
# 합이 0보다 크다면 요소의 값을 줄여야 하기 때문에 right를 내린다. (nums는 정렬이 된 상태)
right -= 1
else:
# 합이 0이면 결과 저장 후, 포인터를 조정하여 다음 triplet 세트를 찾는다.
results.add((nums[i], nums[left], nums[right]))
left, right = left + 1, right - 1

return list(results)
31 changes: 31 additions & 0 deletions climbing-stairs/liza0525.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,34 @@ def fibonacci(step):
fibonacci(3)

return memo[n]


# 7기 풀이
# 시간 복잡도: O(n)
# - memoization을 이용해 결과를 저장을 하면, 계산은 0 ~ n까지 한 번씩만 계산
# - 즉, 계단의 개수 n이 최대 계산 횟수이므로 전체 연산은 O(n)
# 공간 복잡도: O(n)
# - memoization을 하기 위한 dict에 최대 n의 개수만큼만 저장
# - 재귀 호출 스택 깊이도 최대 n
class Solution:
# 해당 문제는 이전 계단까지 계산된 경우의 수를 찾아가며 현재 계단까지 오를 수 있는 경우의 수를 계산한다.
# n번째 계단까지 오를 수 있는 경우의 수는 (n-1번째까지 오를 수 있는 경우의 수) + (n-2번째까지 오를 수 있는 경우의 수)이다.
# 이는 동적 프로그래밍을 이용해 memoization을 하며 풀 수 있는 문제라고 할 수 있다.
Copy link
Contributor

Choose a reason for hiding this comment

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

덕분에 memoization에 대해서도 리뷰했습니다!

def climbStairs(self, n: int) -> int:
memo = {}

def dfs(n):
# n이 0 또는 1일 경우에는 하나의 방법만 있기 때문에 memo에 1을 넣고 return해준다.
if n <= 1:
memo[n] = 1
return memo[n]

# memoization을 이미한 경우에는 memo에서 결과를 꺼내 return해준다.
if n in memo:
return memo[n]

# (n번째까지 오를 수 있는 경우의 수) = (n-1번째까지 오를 수 있는 경우의 수) + (n-2번째까지 오를 수 있는 경우의 수)
memo[n] = dfs(n - 1) + dfs(n - 2)
Copy link
Contributor

Choose a reason for hiding this comment

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

저는 a,b,c로 지정해서 풀었는데 이렇게 함수로 만들어서 푸니까 더 직관적이네요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

우와 어떻게 푸셨는지 궁금해서 구경하고 왔는데, 제겐 새로운 풀이 방법이었습니다!
결국 피보나치 수열 문제던데, 변수로도 충분히 풀 수 있다는 점이 정말 새로웠어요 👀✨
공간복잡도가 O(1)이 될 수도 있다는 점에서 감탄하구 왔씁니다!

return memo[n]

return dfs(n)
29 changes: 29 additions & 0 deletions product-of-array-except-self/liza0525.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,32 @@ def productExceptSelf(self, nums: List[int]) -> List[int]:
answers[i] *= after_total_prod

return answers


# 7기 풀이
# 시간 복잡도: O(n)
# - nums의 길이만큼이 최대 연산 횟수가 된다. for문 두 번 돌린 것은 O(2n) -> O(n)으로 표기 가능
# 공간 복잡도: O(n)
# - nums의 길이만큼 res를 만든다.
# - 단 이는 return variable이라서 리트코드에서는 공간 복잡도 계산에서 제외, 조건의 O(1)와 동일하다고 할 수 있다.
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
# 정답에 대한 리스트 추가
res = [1 for _ in range(len(nums))]

previous_res = 1
for i in range(len(nums)):
# i번째 인덱싀 이전까지의 값들을 res[i]에 먼저 곱해준 후,
# 자기 자신을 previous_res에 계산한다. 이는 다음 loop, 즉 i+1번째일 때 계산된 값을 그대로 곱하게 된다.
res[i] *= previous_res
previous_res *= nums[i]

next_res = 1
for i in range(len(nums) -1, -1, -1):
# 리스트의 맨 뒷쪽 index부터 계산해주면 i번째 인덱스 이후의 값들의 곱들을 계산할 수 있다.
# i번째 인덱싀 이후까지의 값들을 res[i]에 먼저 곱해준 후,
# 자기 자신을 next_res 계산한다. 이는 다음 loop, 즉 i-1번째일 때 계산된 값을 그대로 곱하게 된다.
res[i] *= next_res
next_res *= nums[i]

return res
31 changes: 31 additions & 0 deletions valid-anagram/liza0525.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,34 @@ def isAnagram(self, s: str, t: str) -> bool:
if cnt != 0:
return False
return True



# 7기 풀이
# 시간 복잡도: O(n)
# - s, t, letter_dict를 모두 한 loop당 한 번 씩만 돈다.
# 공간 복잡도: O(n)
# - letter_dict 생성 시 s의 길이(n이라고 할 때)에 종속된다.
from collections import defaultdict


class Solution:
def isAnagram(self, s: str, t: str) -> bool:
# s를 구성하는 각 알파벳의 개수를 저장할 defaultdict을 생성
letter_dict = defaultdict(int)

# s의 문자열을 돌며 각 알파벳의 개수를 카운트
for ss in s:
letter_dict[ss] += 1

# t 문자열을 돌만셔 각 알파벳의 개수만큼 dictionary에서 빼준다.
for tt in t:
letter_dict[tt] -= 1

# s, t를 돌며 각 알파벳의 개수를 센 후 value들은 모두 0이 되어야 한다. (아나그램 특성 상)
# 각 알파벳의 value가 양수면 s에 더 많았고, 음수면 t가 더 많았다는 의미가 됨
for v in letter_dict.values():
if v != 0:
return False

return True
28 changes: 28 additions & 0 deletions validate-binary-search-tree/liza0525.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,31 @@ def inorder_tree(tree_node):
return False

return True


# 7기 풀이
# 시간 복잡도: O(n)
# - 전체 트리 노드를 탐색하기 때문에 n
# 공간 복잡도: O(n)
# - 노드를 저장하는 리스트는 n의 길이만큼 생김
class Solution:
# 중위 순회 결과가 strictly increasing인지 확인하는 방식
def isValidBST(self, root: Optional[TreeNode]) -> bool:
tree_res = []

def inorder_search(node):
if node.left:
inorder_search(node.left)

tree_res.append(node.val)

if node.right:
inorder_search(node.right)

inorder_search(root)

for i in range(len(tree_res) - 1):
# i번째 값이 i + 1번째 값보다 크거나 같으면 strictly increasing하지 않다는 의미이므로 False를 리턴한다.
if tree_res[i] >= tree_res[i + 1]:
return False
return True
Loading