From f9fd527498954e841cd8a7457b5c7d95da93742a Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sun, 5 Jul 2026 16:13:54 +0900 Subject: [PATCH 1/6] 125. Valid Palindrome --- valid-palindrome/okyungjin.py | 85 +++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 valid-palindrome/okyungjin.py diff --git a/valid-palindrome/okyungjin.py b/valid-palindrome/okyungjin.py new file mode 100644 index 0000000000..fe43c06ea5 --- /dev/null +++ b/valid-palindrome/okyungjin.py @@ -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')) From 5f1817f3528d19e51db789e872a6317c98ffc52f Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 11 Jul 2026 16:12:30 +0900 Subject: [PATCH 2/6] 39. Combination Sum --- combination-sum/okyungjin.py | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 combination-sum/okyungjin.py diff --git a/combination-sum/okyungjin.py b/combination-sum/okyungjin.py new file mode 100644 index 0000000000..6693ecdac9 --- /dev/null +++ b/combination-sum/okyungjin.py @@ -0,0 +1,104 @@ +# https://leetcode.com/problems/combination-sum/ + +# [접근] +# 처음에는 1부터 target 까지 결과를 저장하는 dp를 떠올렸다. 이 문제는 조합의 개수를 구하는게 아니라 전체 후보군을 구하는 문제이기 때문에 dfs로 백트래킹하도록 접근법을 바꿨다. + +class Solution: + 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]) # deep copy된 combination을 인자로 넘긴다. + + dfs(0, 0, []) + + return result + + +# +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + result = [] + size = len(candidates) + + def dfs(start_idx: int, total: int, combination: List[int]) -> None: + if total == target: + # 결과에 추가할 때 combination 복사 + result.append(combination.copy()) + return + + if total > target: + return + + for i in range(start_idx, size): + num = candidates[i] + + # 반환 전 num 추가 + # -> 정답 찾으면 result에 추가할 때 combination deep copy 필요 + combination.append(num) + + dfs(i, total + num, combination) + + # 반환 후에 num 제거 + combination.pop() + + + dfs(0, 0, []) + + return result + +# 위 풀이와 거의 유사하다. +# 백트래킹시에 배열이 매번 깊은 복사되는 비효율이 있어서 result 배열에 담을 때만 복사하도록 했다. +class Solution: + 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: + # result + if total == target: + 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 deep copy 필요 + combination.append(num) + + dfs(i, total + num, combination) + + # 반환 후에 num 제거 + combination.pop() + + dfs(0, 0, []) + + return result From 2d4fff1488c0c662b610d5595c8248085ee43ca9 Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 11 Jul 2026 16:21:54 +0900 Subject: [PATCH 3/6] 191. Number of 1 Bits --- number-of-1-bits/okyungjin.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 number-of-1-bits/okyungjin.py diff --git a/number-of-1-bits/okyungjin.py b/number-of-1-bits/okyungjin.py new file mode 100644 index 0000000000..3c07d0d860 --- /dev/null +++ b/number-of-1-bits/okyungjin.py @@ -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 From bb613ebf00b070fd33291427a5e1e5afa69bfeff Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 11 Jul 2026 16:22:20 +0900 Subject: [PATCH 4/6] 191. Number of 1 Bits --- number-of-1-bits/okyungjin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/number-of-1-bits/okyungjin.py b/number-of-1-bits/okyungjin.py index 3c07d0d860..e3507ed200 100644 --- a/number-of-1-bits/okyungjin.py +++ b/number-of-1-bits/okyungjin.py @@ -2,7 +2,7 @@ # n을 2진법으로 변환했을 때 1의 개수를 세는 문제이다. # `n & 1` 연산을 통해 마지막 비트가 1인지 검사해서 count를 증가시킨다. -# 확인한 비트를 `n >>= 1` 으로 한자리 버린다. +# 확인한 비트를 `n >> 1` 으로 한자리 버린다. class Solution: def hammingWeight(self, n: int) -> int: From f16fb02a4af85a01154c80f19a795a52156d334e Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 11 Jul 2026 16:25:51 +0900 Subject: [PATCH 5/6] 39. Combination Sum --- combination-sum/okyungjin.py | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/combination-sum/okyungjin.py b/combination-sum/okyungjin.py index 6693ecdac9..578942eacb 100644 --- a/combination-sum/okyungjin.py +++ b/combination-sum/okyungjin.py @@ -3,7 +3,7 @@ # [접근] # 처음에는 1부터 target 까지 결과를 저장하는 dp를 떠올렸다. 이 문제는 조합의 개수를 구하는게 아니라 전체 후보군을 구하는 문제이기 때문에 dfs로 백트래킹하도록 접근법을 바꿨다. -class Solution: +class Solution_01: def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: result = [] size = len(candidates) @@ -34,38 +34,6 @@ def dfs(start_idx: int, total: int, combination: List[int]) -> None: return result -# -class Solution: - def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: - result = [] - size = len(candidates) - - def dfs(start_idx: int, total: int, combination: List[int]) -> None: - if total == target: - # 결과에 추가할 때 combination 복사 - result.append(combination.copy()) - return - - if total > target: - return - - for i in range(start_idx, size): - num = candidates[i] - - # 반환 전 num 추가 - # -> 정답 찾으면 result에 추가할 때 combination deep copy 필요 - combination.append(num) - - dfs(i, total + num, combination) - - # 반환 후에 num 제거 - combination.pop() - - - dfs(0, 0, []) - - return result - # 위 풀이와 거의 유사하다. # 백트래킹시에 배열이 매번 깊은 복사되는 비효율이 있어서 result 배열에 담을 때만 복사하도록 했다. class Solution: From d2f8a5f6326fa434438e836398df0dd7d89bb1e3 Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 11 Jul 2026 16:31:48 +0900 Subject: [PATCH 6/6] 39. Combination Sum --- combination-sum/okyungjin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/combination-sum/okyungjin.py b/combination-sum/okyungjin.py index 578942eacb..c9dd3566c6 100644 --- a/combination-sum/okyungjin.py +++ b/combination-sum/okyungjin.py @@ -27,7 +27,7 @@ def dfs(start_idx: int, total: int, combination: List[int]) -> None: dfs( i, total + num, # num 을 더한 합으로 호출 - combination + [num]) # deep copy된 combination을 인자로 넘긴다. + combination + [num]) # 얕은 복사된 combination을 인자로 넘긴다. dfs(0, 0, []) @@ -47,6 +47,7 @@ def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: def dfs(start_idx: int, total: int, combination: List[int]) -> None: # result if total == target: + # combination을 얕은 복사 후 추가한다 result.append(combination.copy()) return @@ -59,7 +60,7 @@ def dfs(start_idx: int, total: int, combination: List[int]) -> None: num = candidates[i] # 반환 전 num 추가 - # -> 정답 찾으면 result에 추가할 때 combination deep copy 필요 + # -> 정답 찾으면 result에 추가할 때 combination 얕은 복사 필요 combination.append(num) dfs(i, total + num, combination)