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
63 changes: 63 additions & 0 deletions 3sum/okyungjin.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

  • 패턴: Two Pointers, Binary Search, Hash Map / Hash Set
  • 설명: 정렬된 배열에서 하나의 포인터를 고정하고 나머지 두 포인터를 양 끝에서 좁혀가며 합이 목표값(0)이 되도록 탐색하는 패턴이다. 중복 제거를 위해 포인터를 움직이며 검사한다. 추가로 간접적으로 정렬과 조건 비교를 이용하는 두 포인터의 결합 방식이다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n^2)
Space O(1)

피드백: 정렬로 정렬된 배열에서 두 포인터를 움직이며 모든 해를 탐색한다. 중복 제거 로직이 포함되어 있다.

개선 제안: 현재 구현이 충분히 효율적이며, 필요 시 초기 i 반복에서 nums[i]가 양수인 경우의 조기에 종료하는 등의 미세 최적화를 고려할 수 있다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

결과는 공간 복잡도에 포함시키지 않나보네요

Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions climbing-stairs/okyungjin.py
Comment thread
okyungjin marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -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):

@dahyeong-yun dahyeong-yun Jul 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

개인적으로는 3번째 계단에서 시작하는 거면, 3이라고 명시하는 걸 더 선호해서요. 이렇게도 쓸 수 있을 것 같아요.

Suggested change
for _ in range(2, n):
for _ in range(3, n+1):

curr = prev2 + prev1 # 현재 계단
prev2 = prev1
prev1 = curr
Comment on lines +20 to +22

@dahyeong-yun dahyeong-yun Jul 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
curr = prev2 + prev1 # 현재 계단
prev2 = prev1
prev1 = curr
prev2, prev1 = prev1, prev2 + prev1

파이썬이니까 동시 할당을 활용하는 방법도 있을 것 같아요.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

감사합니다! 개인적으로 curr로 작성해주는게 가독성이 더 좋다고 생각해서 풀어서 작성했습니다.


return prev1
43 changes: 43 additions & 0 deletions product-of-array-except-self/okyungjin.py
Comment thread
okyungjin marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

깔끔한 풀이네요 👍🏼

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

시간이 얼마 안 남아서 남은 것들 후딱 풀겠습니다. 늦은 시간인데도 확인해주셔서 감사해요ㅠㅠ!


print(Solution().productExceptSelf([1,2,3,4]))
print(Solution().productExceptSelf([2,5,3,7]))
41 changes: 41 additions & 0 deletions valid-anagram/okyungjin.py
Comment thread
okyungjin marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +21 to +32

@dahyeong-yun dahyeong-yun Jul 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Counter 라는 것은 처음 보는데 아주 편리하게 쓸 수 있네요. 어차피 Counter 객체를 쓴다면 비교 연산으로 더 간단히 표현이 가능한 것 같아요. 찾아보니 Counter가 내부적으로 각 문자의 등장 횟 수를 dict 타입으로 반환하고, dict 타입은 == 연산자로 동일 비교가 가능하네요.

Suggested change
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
# s가 "apple" 일 때, Counter({'p': 2, 'a': 1, 'l': 1, 'e': 1})
return Counter(s) == Counter(t)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@dahyeong-yun 오오 이런 방법도 있네요. 파이썬은 == 으로 비교하면 참조가 아니라 값으로 비교하는 특성이 있군요. 감사합니다 ㅎㅎ!!


class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s) != len(t):
return False

# 파이썬은 == 로 값을 비교한다.
# 참조로 비교하려면 is 사용
return Counter(s) == Counter(t)
Loading