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
49 changes: 49 additions & 0 deletions 3sum/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
class Solution:
def threeSum(self, nums: list[int]) -> list[list[int]]:
"""
nums에서 세 숫자를 골라 합이 0이 되는 조합을 구하는 함수
세 숫자는 서로 다른 인덱스에 위치해야 함. 중복된 조합은 포함하지 않아야 함.

방법
1. brute force. 세 숫자를 모두 조합하여 합이 0이 되는지 확인. O(n^3) 시간복잡도 -> 너무 오래 걸림!
2. 첫번째 값을 고정하고 나머지 두개의 합을 two sum 문제에서 해결한 것 처럼 dict에 저장하여 찾기. O(n^2) 시간복잡도, O(n) 공간복잡도
-> 중복된 조합을 걸러내는 과정이 필요함
3. 정렬을 해서, 첫번째 값을 고정하고, 나머지 두개의 합이 첫번째 값의 음수가 되는 경우를 찾음 - 포인터 방식.
-> O(n^2) 시간복잡도, O(1) 공간복잡도. 2번 방법보다 정렬을 하지 않으니 효율적
4. 3번 방법에 시간을 줄일 수 있는 예외 케이스 혹은 조건을 찾아 빠르게 종료하기
- 첫번째 값이 양수인 경우, 나머지 두개의 합이 음수가 될 수 없으므로 종료
- 첫번째 값이 이전 값과 같은 경우, 중복된 조합이 되니 건너뛰기
- append 값을 찾은 후에 j+1, k-1을 하면서 중복된 값이 아닐때까지 이동하기

Args:
nums (list[int]): 정렬되지 않은 정수목록

Returns:
list[list[int]]: 합이 0이 되는 세 숫자의 조합 목록
"""
answer = []
s_nums = sorted(nums)
n = len(s_nums)
for i in range(n - 2):
x = s_nums[i]
if i > 0 and x == s_nums[i - 1]:
continue
if x > 0:
break
j, k = i + 1, n - 1
while j < k:
y, z = s_nums[j], s_nums[k]
total = x + y + z
if total == 0:
answer.append([x, y, z])
j += 1
k -= 1
while j < k and s_nums[j] == s_nums[j - 1]:
j += 1
while j < k and s_nums[k] == s_nums[k + 1]:
k -= 1
elif total < 0:
j += 1
else:
k -= 1
return answer
28 changes: 28 additions & 0 deletions climbing-stairs/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Solution:
def climbStairs(self, n: int) -> int:
"""
한번에 1계단 혹은 2계단 씩 올라갈 수 있을때, n개의 계단을 올라기가 위한 방법의 수를 구하는 함수

방법:
1. dp로 풀이하기. 점화식 계산
n=2일때, 1,1 / 2 -> 2가지
n=3일때, 1,1,1 / 1,2 / 2,1 -> 3가지
n=4일때, 1,1,1,1 / 1,1,2 / 1,2,1 / 2,1,1 / 2,2 -> 5가지
1) n-1에서 1계단 올라가기
2) n-2에서 2계단 올라가기
-> dp[i] = dp[i-1] + dp[i-2]
2. 이전 값 두개만 알아두면 되니, dp 배열을 만들지 않고, prev1, prev2로 계산하기
시간복잡도 O(n), 공간복잡도 O(1)

Args:
n (int): 최종적으로 올라가야 하는 계단의 수

Returns:
int: n개의 계단을 올라가기 위한 방법의 갯수
"""
if n <= 3:
return n
prev1, prev2 = 2, 3
for i in range(3, n):
prev1, prev2 = prev2, prev1 + prev2
return prev2
33 changes: 33 additions & 0 deletions product-of-array-except-self/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class Solution:
def productExceptSelf(self, nums: list[int]) -> list[int]:
"""
nums의 각 원소에 대해서, 그 원소를 제외한 나머지 원소들의 곱을 구하는 함수
시간제약은 O(n)이고, 나눗셈을 사용하지 않아야 함

방법:
1. brute-force. 각 원소마다, 나머지 원소들의 곱을 구하기. O(n)의 시간 제약을 만족하지 못함
2. 전체 곱을 구해두고, 각 원소마다 자기 자신의 값으로 나누기. 나눗셈 제약에 걸려 사용 불가
3. 루프에서 자신의 원소를 빼고 앞의 값들의 곱과 뒤의 곱들의 값을 구하기.
- 앞에서부터 곱을 구해나가면서, 배열에 저장하기. 초기 값은 1로 설정
- 뒤에서부터 곱을 구해나가면서, 배열에 저장하기. 초기 값은 1로 설정
- 현 위치 기준 앞의 곱과 뒤의 곱을 곱해서 최종 답을 구하기
-> 앞의 곱과 뒤의 곱의 목록을 유지하니 공간 복잡도가 O(n), 더 효율화 할 수 없을까?
4. 별도의 배열을 만들지 않고, 앞에서부터 곱하며 배열에 저장한 후, 뒤에서부터 다시 곱하며 동일 배열에 업데이트.
-> 시간복잡도 O(n), 공간복잡도 O(1) (답 배열 제외)

Args:
nums (list[int]): 정수 목록

Returns:
list[int]: 각 원소에 대해서, 그 원소를 제외한 나머지 원소들의 곱을 담은 목록
"""
answer = [1] * len(nums)
nxt = 1
for idx, num in enumerate(nums):
answer[idx] = nxt
nxt *= num
nxt = 1
for idx in range(len(nums) - 1, -1, -1):
answer[idx] *= nxt
nxt *= nums[idx]
return answer
24 changes: 24 additions & 0 deletions valid-anagram/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from collections import Counter


class Solution:
def isAnagram(self, s: str, t: str) -> bool:
"""
s와 t가 아나그램인지 확인하는 함수.
아나그램은 문자열의 문자들이 동일하지만 순서가 다른 경우를 말함. 대소문자는 구분하지 않지만, 언어마다의 특수 기호 등은 고려해야 함.

방법:
1. s와 t를 정렬하여 비교; o(nlogn) 시간복잡도
2. s와 t의 각 문자의 빈도수를 세어 비교; o(n) 시간복잡도
-> 실제 dict로 구현하기보다 Counter를 사용하면 o(n)에서도 약간 빠르게 구현 가능

* 언어마다의 특수 문자/기호를 고려해야 해, casefold()를 사용.

Args:
s (str): 비교할 문자열 1
t (str): 비교할 문자열 2

Returns:
bool: s와 t가 아나그램이면 True, 아니면 False
"""
return Counter(s.casefold()) == Counter(t.casefold())
46 changes: 46 additions & 0 deletions validate-binary-search-tree/kangdaia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from typing import Optional


class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right


class Solution:
def checker(self, node: Optional[TreeNode], low: float, high: float) -> bool:
"""(Helper)
주어진 노드가 유효한 BST 노드인지 검증하는 함수

Args:
node (Optional[TreeNode]): 검증할 node 객체
low (float): node.val이 될 수 있는 최소값
high (float): node.val이 될 수 있는 최대값

Returns:
bool: node가 유효한 BST 노드인지 여부
"""
if node is None:
return True
value = node.val
left, right = node.left, node.right
if not (low < value < high):
return False
return self.checker(left, low, value) and self.checker(right, value, high)

def isValidBST(self, root: Optional[TreeNode]) -> bool:
"""
현재 트리가 올바른 binary tree인지 검증하는 함수

checker 함수를 이용하여 트리의 모든 노드가 BST의 조건을 만족하는지 검증함.
checker 함수는 재귀적으로 호출되고, 각 노드의 값이 허용된 범위 내에 있는지 확인함.
이후 왼쪽 자식 노드는 현재 노드의 값보다 작은 범위로, 오른쪽 자식 노드는 현재 노드의 값보다 큰 범위로 검증함.

Args:
root (Optional[TreeNode]): 검증되지 않는 tree 객체

Returns:
bool: 올바른 binary tree인지 여부
"""
return self.checker(root, -float("inf"), float("inf"))
Loading