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
78 changes: 78 additions & 0 deletions 3sum/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from typing import List

'''
1차 시도: 실패 (시간 초과)
- nums에서 두 수 (A,B)를 고른 후, 세번째 숫자인 -(A+B)가 A,B를 제외한 nums에 존재하는지 확인
- 중복된 결과를 제거하기 위해 set과 sorted(tuple)을 활용

시간 복잡도: O(N^3)
- Outer loop와 Inner loop 각각 O(N) 이므로 O(N^2)은 기본
- nums[j:]에서 third_num을 찾는 데 O(N) 시간이 걸려서 전체 시간 복잡도는 O(N^3)

공간 복잡도: 최대 O(N^2)
- answer_set은 중복되지 않는 triplet을 저장하며, 3SUM 특성상 유니크한 triplet의 최대 개수는 O(N^2)

'''

class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
answer_set = set()

for i in range(len(nums) - 1):
for j in range(i + 1, len(nums)):
third_num = -1 * (nums[i] + nums[j])

if third_num in nums[j:]:
answer_set.add(tuple(sorted([nums[i], nums[j], third_num])))

return [list(t) for t in answer_set]

'''
개선 : if third_num in nums[j:] 부분을 set을 활용
Approach
- nums에서 두 수 (A,B)를 고른 후, 세번째 숫자인 -(A+B)가 존재하는지 확인하는 기존 기조는 유지함
- (A,B) 쌍 중 ‘A(첫 번째 숫자)’가 동일한 값일 때,
이미 동일한 first 값으로 생성할 수 있는 모든 triplet을 처리했으므로
다시 같은 first로 시작하는 조합을 만들 필요가 없다는 점을 활용
- seen set을 활용해서 (A,B)가 고정된 이후 세번째 숫자인 -(A+B)가 존재하는지 O(1) 시간에 확인

- (예시) seen set은 i가 고정된 이후 j를 순회하면서 nums[j] 값을 저장
- nums = [a, b, c, d, e]
- i = 0 (nums[i] = a)일 때, seen = {}
- j = 1 (nums[j] = b)일 때, seen = {b}
- j = 2 (nums[j] = c)일 때, seen = {b, c}
- j = 3 (nums[j] = d)일 때, seen = {b, c, d}
- j = 4 (nums[j] = e)일 때, seen = {b, c, d, e)

시간 복잡도: O(N^2)
- Outer loop와 Inner loop 각각 O(N) 이므로 전체 시간 복잡도는 O(N^2)

공간 복잡도: 최대 O(N^2)
- seen set은 nums[j]를 저장하며 최악의 경우 O(N)
- used_first도 distinct first 값들을 저장하며 최대 O(N)
- answer_set은 중복되지 않는 triplet을 저장하며, 3SUM 특성상 유니크한 triplet의 최대 개수는 O(N^2)
'''
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
answer_set = set()
n = len(nums)

used_first = set() # 이미 i로 사용한 값들

for i in range(n - 1):
# 같은 값을 첫 번째 숫자로 한 번만 쓰기
if nums[i] in used_first:
continue
used_first.add(nums[i])

seen = set()
for j in range(i + 1, n):
third_num = -1 * (nums[i] + nums[j])

if third_num in seen:
triplet = tuple(sorted([nums[i], nums[j], third_num]))
answer_set.add(triplet)
else:
seen.add(nums[j])

return [list(t) for t in answer_set]
17 changes: 17 additions & 0 deletions climbing-stairs/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'''
Approach: Dynamic Programming
- 혼자서 해결하려고 고민을 30분 이상 했으나 실패해서 알고달레 선생님의 블로그 도움을 받았습니다.
- 해당 문제를 통해 동적 계획,Dynamic Programming
- 더 적은 입력에 대한 답을 먼저 구해서 저장해놓고, 더 큰 입력에 대한 답을 구할 때 활용하는 방식에 대해 학습할 수 있었습니다!

Time Complexity: O(n)
- for loop이 n번 순회하며 각 값에 대한 연산 O(n) 발생
Space Complexity: O(n)
- nums 딕셔너리에 각 계단 수에 대한 경우의 수를 저장
'''
class Solution:
def climbStairs(self, n: int) -> int:
nums = {1:1, 2:2}
for i in range(3, n+1):
nums[i] = nums[i-1] + nums[i-2]
return nums[n]
28 changes: 28 additions & 0 deletions product-of-array-except-self/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'''
Approach
- 배열에 0이 2개 이상 있는 경우, 모든 원소는 0이 되므로 바로 답을 반환
- "self(전체 곱에서 제외될 값)"의 인덱스를 기준으로 왼쪽(before)과 오른쪽(after)곱을 미리 계산해서 배열에 저장
- 최종적으로 before와 after 배열의 같은 인덱스 값을 곱해서 반환

Time Complexity: O(N)
- after, before 배열을 각각 한 번씩 순회하며 계산
- 결과를 반환할때 두 배열을 곱을 계산
Space Complexity: O(N)
- N은 num의 길이이며 N크기에 비례하는 before, after 배열 생성 공간
'''
from typing import List

class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
if nums.count(0) > 1:
return [0] * len(nums)

before = [1] * len(nums)
for idx in range(len(nums)-1):
before[idx+1] = before[idx] * nums[idx]

after = [1] * len(nums)
for jdx in range(len(nums)-1, 0, -1):
after[jdx-1] = after[jdx] * nums[jdx]

return [x * y for x, y in zip(before, after)]
50 changes: 50 additions & 0 deletions valid-anagram/Seoya0512.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'''
Approach 1: Sorting
- 제일 먼저 생각나는 간단한 방법은 sorted 함수를 활용해서 분류해서 s 와 t가 동일한지 확인하는 방법입니다.
- 정렬메소드를 사용하면 n log n의 시간복잡도가 발생하는 것을 인지하고도 풀어봤습니다.

Time Complexity: O(n log n)
- 분류 정렬에서 O(n log n) 발생

Space Complexity: O(n)
- 분류 문자열을 생성하는 공간 때문에 O(n) 발생
'''
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
sorted_s = ''.join(sorted(s))
sorted_t = ''.join(sorted(t))
if(sorted_s == sorted_t):
return True
else:
return False

'''
Approach 2: 빈도수 카운팅
- 두 문자열의 길이를 먼저 비교해서 다르면 False를 반환해서 1차 필터링
- count 딕셔너리를 생성해서 s 문자열의 빈도수를 카운팅
- t 문자열을 순회하면서 딕셔너리에 포함되어 있으면 카운팅을 감소시키고, 값이 없으면 False를 반환


Time Complexity: O(n)
- 두 문자열을 각각 순회하면 딕셔너리 생성, 빈도수 카운팅 및 감소 에서 O(n) 발생

Space Complexity: O(n)
- count 딕셔너리 저장 공간 때문에 O(n) 발생
'''
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
# 길이가 일치하지 않으면 False
if len(s) != len(t):
return False
# 문자 개수 카운트
count = {}
for val in s:
count[val] = count.get(val, 0) + 1
for val in t:
if val not in count:
return False
count[val] -= 1
# 예시 : s = "aacc", t = "ccac" 인 경우 count[val] 이 음수가 될 수 있음
if count[val] < 0:
return False
return True