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
73 changes: 73 additions & 0 deletions combination-sum/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Backtracking
  • 설명: 합이 target과 일치하는 조합을 탐색하고, 조건에 맞으면 결과에 추가하는 방식으로 모든 가능한 조합을 재귀적으로 시도한다. 각 재귀에서 선택 가능한 후보를 하나씩 시도하고 반환시 상태를 되돌리는 백트래킹 패턴이다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution_01.combinationSum — Time: O(n^k) / Space: O(k)
복잡도
Time O(n^k)
Space O(k)

피드백: 백트래킹으로 모든 가능한 조합을 탐색하고, 중복 조합 생성을 방지하기 위해 시작 인덱스를 고정했습니다.

개선 제안: 현재 구현이 적절해 보입니다.

풀이 2: Solution.combinationSum — Time: O(n^k) / Space: O(k)
복잡도
Time O(n^k)
Space O(k)

피드백: 두 번째 구현은 매 재귀에서 불필요한 리스트 복사를 줄여 메모리 사용을 개선합니다.

개선 제안: 현재 구현이 적절해 보입니다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# https://leetcode.com/problems/combination-sum/

# [접근]
# 처음에는 1부터 target 까지 결과를 저장하는 dp를 떠올렸다. 이 문제는 조합의 개수를 구하는게 아니라 전체 후보군을 구하는 문제이기 때문에 dfs로 백트래킹하도록 접근법을 바꿨다.

class Solution_01:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
result = []
size = len(candidates)

# start_idx: 탐색 시작 인덱스
# total: 현재까지의 합
# combination: 선택된 숫자들 배열
def dfs(start_idx: int, total: int, combination: List[int]) -> None:
# 합이 target과 같으면 정답 배열에 추가하고 종료
if total == target:
result.append(combination)
return

# 합이 target 넘었으면 종료
if total > target:
return

# 숫자를 여러번 사용할 수 있으므로 반복문을 start_idx 부터 시작한다.
for i in range(start_idx, size):
num = candidates[i]
dfs(
i,
total + num, # num 을 더한 합으로 호출
combination + [num]) # 얕은 복사된 combination을 인자로 넘긴다.

dfs(0, 0, [])

return result


# 위 풀이와 거의 유사하다.
# 백트래킹시에 배열이 매번 깊은 복사되는 비효율이 있어서 result 배열에 담을 때만 복사하도록 했다.
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
Comment on lines +37 to +40

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

주석에 배열이 매번 깊은 복사되는 비효율을 개선했다고 적혀 있는데, 첫 번째 풀이에서 실제로 깊은 복사가 발생하는 부분이 어디인지 궁금합니다!

혹시 combination + [num]에서 매번 새로운 리스트가 생성되는 비용을 깊은 복사라고 표현하신 걸까요? 👀

@okyungjin okyungjin Jul 11, 2026

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.

얕은 복사라고 적어야 하는데 깊은 복사라고 잘못 적었습니다.
dfs 재귀 호출 시에 매번 새로운 리스트가 생성되는 비용을 표현한게 맞습니다!

result = []
size = len(candidates)

# start_idx: 탐색 시작 인덱스
# total: 현재까지의 합
# combination: 선택된 숫자들 배열
def dfs(start_idx: int, total: int, combination: List[int]) -> None:
# result
if total == target:
# combination을 얕은 복사 후 추가한다
result.append(combination.copy())
return

# 합이 target 넘었으면 종료
if total > target:
return

# 숫자를 여러번 사용할 수 있으므로 반복문을 start_idx 부터 시작한다.
for i in range(start_idx, size):
num = candidates[i]

# 반환 전 num 추가
# -> 정답 찾으면 result에 추가할 때 combination 얕은 복사 필요
combination.append(num)

dfs(i, total + num, combination)

# 반환 후에 num 제거
combination.pop()

dfs(0, 0, [])

return result
23 changes: 23 additions & 0 deletions number-of-1-bits/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Bit Manipulation
  • 설명: 주어진 코드는 비트 연산을 이용해 2진수에서 1의 개수를 세는 방식으로, n & 1로 현재 비트를 확인하고 n >> 1로 한 자리씩 이동시키는 비트 조작 패턴을 사용합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(number_of_bits)
Space O(1)

피드백: 비트를 하나씩 확인하며 1의 개수를 누적합니다. 간단하고 직관적입니다.

개선 제안: 현 구현이 적절해 보입니다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# https://leetcode.com/problems/number-of-1-bits/description/

# n을 2진법으로 변환했을 때 1의 개수를 세는 문제이다.
# `n & 1` 연산을 통해 마지막 비트가 1인지 검사해서 count를 증가시킨다.
# 확인한 비트를 `n >> 1` 으로 한자리 버린다.

class Solution:
def hammingWeight(self, n: int) -> int:
count = 0

while n:
# `n & 1` 연산을 통해 마지막 비트가 1인지 검사해서 count를 증가시킨다.

# 1011
# & 0001
# ------
# 0001 -> 결과 1이 된다
count += n & 1

# 비트 한자리 이동한다 (1011 -> 0101)
n = n >> 1

return count
85 changes: 85 additions & 0 deletions valid-palindrome/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, Greedy
  • 설명: 문자열 양 끝에 포인터를 두고, 알파벳/숫자만 확인하며 좌우로 이동시키는 방식으로 조건을 검사한다. 전형적인 투 포인터 패턴이면서, 유사하게 조건을 만족하는 문자를 찾으며 즉시 판단하는 구성이 Greedy의 직관과도 맞다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(N) O(n)
Space O(1) O(1)

피드백: 두 포인터를 활용해 필요한 문자만 비교하고 불필요한 문자열 전처리를 피합니다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# [문제]
# https://leetcode.com/problems/valid-palindrome/description/

# [요구사항]
# 주어진 문자열이 팰린드롬인지 판별하는 함수를 작성한다.
# 팰린드롬이란?
# 1. 대문자가 있다면 소문자로 변환한다
# 2. 알파벳 or 숫자가 아니라면 제거한다.
# 3. 앞뒤로 읽었을 때 동일한 문자여야 한다.

# [접근법]
# - 문자열 전체를 공백 제거 & 소문자로 변환하지 않고, 투 포인터를 통해 lazy하게 연산한다.
# - 문자열 양 끝에 포인터를 선언하고, alphanumeric인 경우 소문자로 변환 후 두 문자를 비교한다. 다르면 False 리턴
# - alphanumeric이 아니면 alphanumeric 문자가 나올 때까지 이동한다.

# [복잡도]
# 시간 복잡도: O(N)
# 공간 복잡도: O(1)
class SolutionA:
def isPalindrome(self, s: str) -> bool:

# 문자열 양 끝 포인터 선언
left = 0
right = len(s) - 1

while left < right:
# alphanumeric 이 나올 때까지 왼쪽 포인터를 우측으로 이동
while left < right and not isAlphaNumeric(s[left]):
left += 1

# alphanumeric 이 나올 때까지 오른쪽 포인터를 좌측으로 이동
while left < right and not isAlphaNumeric(s[right]):
right -= 1

# 소문자로 변환해서 비교
if s[left].lower() != s[right].lower():
return False

left += 1
right -= 1

return True

# 문자가 alphanumeric인지 판별하는 함수
# A ~ Z 혹은 a ~ z 혹은 0 ~ 9 이면 True를 반환
def isAlphaNumeric(ch: str) -> bool:
return (
ord('A') <= ord(ch) <= ord('Z')
or ord('a') <= ord(ch) <= ord('z')
or ord('0') <= ord(ch) <= ord('9')
)


# SolutuionB: SoulutionA와 같은 로직인데 `isalnum` 내장함수 사용
# isAlphaNumeric 함수를 직접 구현하고 찾아보니 파이썬 내장함수가 있었다.

# [복잡도]
# 시간 복잡도: O(N)
# 공간 복잡도: O(1)
class Solution:
def isPalindrome(self, s: str) -> bool:
# 문자열 양 끝 포인터 선언
left = 0
right = len(s) - 1

while left < right:
# alphanumeric 이 나올 때까지 왼쪽 포인터를 우측으로 이동
while left < right and not s[left].isalnum():
left += 1

# alphanumeric 이 나올 때까지 오른쪽 포인터를 좌측으로 이동
while left < right and not s[right].isalnum():
right -= 1

# 소문자로 변환해서 비교
if s[left].lower() != s[right].lower():
return False

left += 1
right -= 1

return True


print(Solution().isPalindrome('A man, a plan, a canal: Panama'))
Loading