diff --git a/combination-sum/jongwanra.py b/combination-sum/jongwanra.py new file mode 100644 index 000000000..52bb0845f --- /dev/null +++ b/combination-sum/jongwanra.py @@ -0,0 +1,100 @@ +""" +[Problem] +https://leetcode.com/problems/combination-sum/ + +candidates: unique array of integers +return a list of all unique combinations of candidates == target +any order + +하나의 숫자는 candidates에서 무제한으로 선택할 수 있다. +두 조합이 서로 다르다고 간주되는 조건은, 선택된 숫자 중 적어도 하나의 개수가 다를 때이다. +[Brainstorming] +DFS를 이용해서 Combination을 만든다. +종료조건: target == sum || target > sum + +[Plan] +1. candidates를 오름차순 정렬 +2. DFS + +[Complexity] +N -> candidates.length +M -> approximately target divided by the smallest candidate. -> target / min(candidates) +Time: O(N^M) +Space: O(N + M) + - 재귀 호출 스택: 깊이는 최대 target / min(candidates) + - chosen: 재귀 스택 깊이 만큼 공간 차지 + - cache: 최악의 경우 answer와 같은 개수의 조합 저장 -> O(number of combinations) +""" + +from typing import List + + +class Solution: + def combinationSum1(self, candidates: List[int], target: int) -> List[List[int]]: + cache = set() + answer = [] + chosen = [] + + def dfs(sum: int) -> None: + nonlocal target, candidates, cache, answer, chosen + print(chosen) + if sum > target: + return + if sum == target: + copied_chosen = chosen[:] + copied_chosen.sort() + + cache_key = tuple(copied_chosen) + if cache_key in cache: + # print(f"already exists {cache_key} in cache") + return + cache.add(cache_key) + answer.append(copied_chosen) + + for candidate in candidates: + chosen.append(candidate) + dfs(sum + candidate) + chosen.pop() + + dfs(0) + return answer + + """ + 중복 조합 방지 another solution + ref: https://www.algodale.com/problems/combination-sum/ + + [Complexity] + N -> candidates.length + M -> target / min(candidates) + Time: O(N^M) + Space: O(M) + """ + + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + answer = [] + combi = [] + + def dfs(sum: int, start: int) -> None: + nonlocal target, answer, combi, candidates + + if sum > target: + return + if sum == target: + answer.append(combi[:]) + return + + for index in range(start, len(candidates)): + candidate = candidates[index] + combi.append(candidate) + dfs(sum + candidate, index) + combi.pop() + + dfs(0, 0) + return answer + + +sol = Solution() +# print(sol.combinationSum([2,3,6,7], 7)) +print(sol.combinationSum([2, 3, 5], 8)) +# print(sol.combinationSum([2], 1)) + diff --git a/number-of-1-bits/jongwanra.py b/number-of-1-bits/jongwanra.py new file mode 100644 index 000000000..debfdaa73 --- /dev/null +++ b/number-of-1-bits/jongwanra.py @@ -0,0 +1,45 @@ +""" +[Problem] +https://leetcode.com/problems/number-of-1-bits/description/ + +양수 n이 주어졌을 때, 이진법에서 1로 설정된 비트의 개수를 반환하는 함수를 작성해라. + + +[Plan] +1. 주어진 양수를 이진수로 변환한다. +2. for-loop을 순회하며 1의 개수를 counting한다. + +[Complexity] +N: bin(n).length - 2 +Time: O(N) +Space = O(N) +""" +class Solution: + def hammingWeight(self, n: int) -> int: + binary = bin(n) + output = 0 + for index in range(2, len(binary)): + if binary[index] == '1': + output += 1 + return output +""" +ref: https://www.algodale.com/problems/number-of-1-bits/ +[Complexity] +Time: O(log n) +Space: O(1) +""" +class AnotherSolution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n: + quotient, remainder = divmod(n, 2) + print(f"n = {n} quotient={quotient}, remainder={remainder}") + count += remainder + n = quotient + return count + +sol = AnotherSolution() +print(sol.hammingWeight(11) == 3) +print(sol.hammingWeight(128) == 1) +print(sol.hammingWeight(2147483645) == 30) + diff --git a/valid-palindrome/jongwanra.py b/valid-palindrome/jongwanra.py new file mode 100644 index 000000000..db9d1ac88 --- /dev/null +++ b/valid-palindrome/jongwanra.py @@ -0,0 +1,37 @@ +""" +[Problem] +https://leetcode.com/problems/valid-palindrome/description/ + +모든 대문자를 소문자로 변환하고 알파벳과 숫자가 아닌 문자들을 전부 제거하한 이후에 앞에서 부터 일으나 뒤에서 부터 읽나 동일하게 읽힌다면, 그 문장은 회문입니다. +영숫자 문자들은 알파벳과 숫자들을 포함합니다. + +[Brainstorming] +leftPosition과 rightPosition을 두고, 비교하면서 아닐 경우 false를 return한다. => O(s.length) + +[Complexity] +N: s.length +Time: O(1/2 * N) => O(N) +Space: O(1) +""" + +class Solution: + def isPalindrome(self, s:str)-> bool: + leftPos, rightPos = 0, len(s) - 1 + while leftPos < rightPos: + while not s[leftPos].isalnum() and leftPos < rightPos: + leftPos += 1 + while not s[rightPos].isalnum() and leftPos < rightPos: + rightPos -= 1 + + if s[leftPos].upper() != s[rightPos].upper(): + return False + leftPos += 1 + rightPos -= 1 + return True + +sol = Solution() +print(sol.isPalindrome("A man, a plan, a canal: Panama") == True) +print(sol.isPalindrome("race a car") == False) +print(sol.isPalindrome(" ") == True) +print(sol.isPalindrome("0P") == False) +print(sol.isPalindrome("a") == True)