diff --git a/3sum/JinuCheon.py b/3sum/JinuCheon.py new file mode 100644 index 0000000000..fcb586b578 --- /dev/null +++ b/3sum/JinuCheon.py @@ -0,0 +1,87 @@ +# brute force 로 풀어본 답안. O(n3) 다. 역시 timeout. +# dic, set 자료형 익히기 겸 해봤다. 파이썬 편하다 최고. +class Solution: + def threeSum(self, nums: list[int]) -> list[list[int]]: + n = len(nums) + result = set() + + for i in range(n): + for j in range(n): + for k in range(n): + if (i == j or j == k or i == k): + continue + if (nums[i] + nums[j] + nums[k] == 0): + result.add(tuple(sorted([nums[i], nums[j], nums[k]]))) + + return list(result) + +# LLM 에게 힌트 얻어서 진행. +# i != j, i != k, j != k 조건 때문에 정렬을 하면 안된다고 착각하고 있었다. 사실 고정된 순서는 중요하지 않음. +# 정렬을 진행하고, two pointer 로 진행. +# 통과! +class Solution2: + def threeSum(self, nums: list[int]) -> list[list[int]]: + # 정렬 + nums.sort() + n = len(nums) + result = set() + + for i in range(n): + # i 자리 중복 skip (이전 원소와 같으면 건너뜀) + if i > 0 and nums[i] == nums[i - 1]: + continue + + # i + left + right === 0 이 되어야 함. + left = i + 1 + right = n - 1 + + while left < right: + if nums[left] + nums[right] == -nums[i]: + result.add(tuple([nums[i], nums[left], nums[right]])) + left += 1 + right -= 1 + + elif nums[left] + nums[right] < -nums[i]: + left += 1 + else: + right -= 1 + + return list(result) + +# LLM의 피드백. +# 중복을 스킵하는 효율적인 방법이 있었음. +class Solution: + def threeSum(self, nums: list[int]) -> list[list[int]]: + nums.sort() + n = len(nums) + result = [] + + for i in range(n): + if i > 0 and nums[i] == nums[i - 1]: + continue + + if nums[i] > 0: + break + + left, right = i + 1, n - 1 + target = -nums[i] + + while left < right: + s = nums[left] + nums[right] + if s == target: + result.append([nums[i], nums[left], nums[right]]) + left += 1 + right -= 1 + + # left, right 자리도 중복 skip + while left < right and nums[left] == nums[left - 1]: + left += 1 + while left < right and nums[right] == nums[right + 1]: + right -= 1 + + elif s < target: + left += 1 + else: + right -= 1 + + return result diff --git a/climbing-stairs/JinuCheon.py b/climbing-stairs/JinuCheon.py new file mode 100644 index 0000000000..1e228edeb9 --- /dev/null +++ b/climbing-stairs/JinuCheon.py @@ -0,0 +1,53 @@ +# 재귀를 만드는 것이 잘 생각나지 않아서, 이렇게 저렇게 시도해보다 결국 LLM 도움. +# 그렇지만 제출 결과 Time Out. +# 2^N 복잡도임. max 45 의 경우 35,184,372,088,832. +class Solution: + def climbStairs(self, n: int) -> int: + # 1 -> 한칸만 가능 + # 2 -> (1,1) or (2) + if n <= 2: + return n; + + # 1칸 진행한 케이스 + 2칸 진행한 케이스 + return self.climbStairs(n-1) + self.climbStairs(n-2); + +# memonization 적용. 실무를 하고나서 이걸 보니, 캐싱이라고 부르고 싶다. +# 1~N 숫자 하나당 한번의 계산을 하게 되니, 시간복잡도는 O(1) 이다. +# 이게 왜 easy 난이도지? 잊어먹었다가 주말에 자력으로 풀어보자. +class Solution: + def climbStairs(self, n: int) -> int: + self.memo = {} + return self.dfs(n) + + def dfs(self, n: int) -> int: + if n <= 2: + return n + + # 이미 해당 수를 계산한 적이 있다면 early return. + if n in self.memo: + return self.memo[n] + + # 새로운 결과가 있으면 무조건 저장. + self.memo[n] = self.dfs(n - 1) + self.dfs(n - 2) + return self.memo[n] + + +# yuseok89 님 피드백 반영. +# 점화식(recursive relation): 수열의 항을 그 이전 항들을 이용해서 정의하는 식. +# 함수 호출 오버헤드 제거 & 안정성 +class Solution3: + def climbStairs(self, n: int) -> int: + if n < 2: + return n + + dp = [0] * (n+1) + + # set init values + dp[1] = 1 + dp[2] = 2 + + # i 번째 계단 오르는 경우의 수: 1칸 + 2칸 경우의 수의 합 + for i in range(3, n+1): + dp[i] = dp[i - 1] + dp[i - 2] + + return dp[n]; diff --git a/product-of-array-except-self/JinuCheon.py b/product-of-array-except-self/JinuCheon.py new file mode 100644 index 0000000000..89e243e00f --- /dev/null +++ b/product-of-array-except-self/JinuCheon.py @@ -0,0 +1,33 @@ +# 처음에 직관적으로 떠오른 O(n2) 풀이. +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + n = len(nums) + result = [1] * n + for i in range(n): + for j in range(n): + if i == j: + continue + result[j] *= nums[i] + + return result + +# 고민하다가 LLM 에게 힌트 달라고 질문. +# 좌 / 우 누적곱으로 처리하는 방식. +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + n = len(num) + result = [1] * n + + # 왼쪽 누적곱을 result에 미리 채워둠 + cumulativeLeftSum = 1 + for i in range(n): + result[i] = cumulativeLeftSum + cumulativeLeftSum *= nums[i] + + # 오른쪽 누적곱을 곱해나가면서 완성 + cumulativeRightSum = 1 + for i in range(n - 1, -1, -1): + result[i] *= cumulativeRightSum + cumulativeRightSum *= nums[i] + + return result diff --git a/valid-anagram/JinuCheon.py b/valid-anagram/JinuCheon.py new file mode 100644 index 0000000000..969d5c5b67 --- /dev/null +++ b/valid-anagram/JinuCheon.py @@ -0,0 +1,39 @@ +# my own solution +# O(n) +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + count1 = {} + for ch in s: + count1[ch] = count1.get(ch, 0) + 1 + + count2 = {} + for ch in t: + count2[ch] = count2.get(ch, 0) + 1 + + return count1 == count2 + +# gpt suggestion +### half space +#### O(n) +class Solution2: + def isAnagram(self, s: str, t: str) -> bool: + count = {} + for ch in s: + count[ch] = count.get(ch, 0) + 1 + for ch in t: + count[ch] = count.get(ch, 0) - 1 + return all(v == 0 for v in count.values()) + +### simple solution (What??) +#### O(n) +#### Counter works like my own solution internally. But I'm ganna forgot this, becuase I'm learning now. +from collections import Counter +class Solution3: + def isAnagram(self, s: str, t: str) -> bool: + return Counter(s) == Counter(t) + +### using sort +#### O(n log n) +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + return sorted(s) == sorted(t)