diff --git a/contains-duplicate/haklee.py b/contains-duplicate/haklee.py new file mode 100644 index 000000000..53ded373a --- /dev/null +++ b/contains-duplicate/haklee.py @@ -0,0 +1,18 @@ +"""TC: O(n)? O(n^2)?, SC: O(n) + +ref: https://wiki.python.org/moin/TimeComplexity +set는 dict와 거의 비슷하게 구현되어 있는데, +dict의 `Set Item`의 Average Case는 O(1)이더라도 +Amortized Worst Case가 O(n)이다! + +즉, set에 아이템을 추가할때마다 해시 충돌이 일어날 경우 +최악의 경우 O(n^2)이 걸리므로, 아래의 set(nums)의 +TC가 O(n^2)이 되는 것일까..? + +set(nums)의 결과가 최악의 경우 SC가 O(n)이다. +""" + + +class Solution: + def containsDuplicate(self, nums: List[int]) -> bool: + return len(nums) != len(set(nums)) diff --git a/kth-smallest-element-in-a-bst/haklee.py b/kth-smallest-element-in-a-bst/haklee.py new file mode 100644 index 000000000..8a6695cff --- /dev/null +++ b/kth-smallest-element-in-a-bst/haklee.py @@ -0,0 +1,42 @@ +"""TC: O(n), SC: O(n) + +BST의 전체 노드 개수가 n개라고 가정. + +TC는 최악의 경우 BST 노드 전체를 순회해야 하므로 O(n). + +노드를 순회하면서 지나온 노드 값을 따로 저장하지 않고 카운터로 처리하고 있다. +즉, traverse 함수를 재귀적으로 호출하는 부분의 콜 스택의 깊이 값만 고려하면 되는데, +root 노드부터 전부 left로 이어진 트리가 만들어질 경우 SC가 O(n)으로 최악. +""" + + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: + global cnt + cnt = 0 + + def traverse(node: Optional[TreeNode]) -> int: + """아이디어: + 노드의 왼쪽 자식을 먼저 순회하고, + 본인의 값을 체크하면서 cnt값을 늘리고, + 노드의 오른쪽 자식을 순회. + + 순회하다가 cnt값이 k가 되면, 즉, k번째 작은 원소를 찾으면 + 순회를 멈추고 찾은 값을 리턴. + + 리턴된 값이 -1인 경우 순회 중 원하는 값을 찾지 못했다는 뜻이다. + 문제 조건에서 노드의 val 값이 0 이상이라고 되어있어서 -1을 선택. + """ + global cnt + return -1 if not node\ + else v if (v := traverse(node.left)) >= 0\ + else node.val if (cnt := cnt + 1) == k\ + else traverse(node.right) + + return traverse(root) diff --git a/number-of-1-bits/haklee.py b/number-of-1-bits/haklee.py new file mode 100644 index 000000000..246271d3e --- /dev/null +++ b/number-of-1-bits/haklee.py @@ -0,0 +1,14 @@ +"""TC: O(log n), SC: O(log n) + +n이 2배 커지면 bin(n)의 길이가 1 늘어나고, 이 bin(n) 값을 +전부 순회하므로 O(log n). +bin(n)을 리스트로 바꿔서 sum을 했으므로 SC도 O(log n)이 된다. + +하지만 n의 크기가 2^31 - 1 이하로 제한되어 있으므로 +TC, SC 분석이 크게 의미있진 않음. +""" + + +class Solution: + def hammingWeight(self, n: int) -> int: + return sum([i == "1" for i in bin(n)]) diff --git a/palindromic-substrings/haklee.py b/palindromic-substrings/haklee.py new file mode 100644 index 000000000..936d54c6f --- /dev/null +++ b/palindromic-substrings/haklee.py @@ -0,0 +1,38 @@ +"""TC: O(n^2), SC: O(1) + +SC는 sol이라는 카운터 값만 관리하고 있으므로 O(1). + +TC는 +- 팰린드롬의 중심점의 위치가 range(l)로 주어지므로 여기서 O(n), +- 중심점에서 시작과 끝을 한 칸씩 늘려가면서 팰린드롬 체크할때 O(1), +- 시작과 끝이 최대로 늘어날 수 있는 길이가 O(n), +즉, O(n^2). +""" + + +class Solution: + def countSubstrings(self, x: str) -> int: + l = len(x) + sol = 0 + + for i in range(l): + # 시작과 끝이 일치하는 상태에서 시작. + # 즉, 팰린드롬의 길이가 홀수. + s = e = i + b = True + while b: + sol += (b := (0 <= s and e < l and x[s] == x[e])) + s -= 1 + e += 1 + + # 시작과 끝이 하나 차이나는 상태에서 시작. + # 즉, 팰린드롬의 길이가 짝수. + s = e = i + e += 1 + b = True + while b: + sol += (b := (0 <= s and e < l and x[s] == x[e])) + s -= 1 + e += 1 + + return sol diff --git a/top-k-frequent-elements/haklee.py b/top-k-frequent-elements/haklee.py new file mode 100644 index 000000000..077a32dbb --- /dev/null +++ b/top-k-frequent-elements/haklee.py @@ -0,0 +1,26 @@ +"""TC: O(n log n), SC: O(n) + +1 +nums를 순회하면서 dict를 채우는 데에 TC: O(n), SC: O(n) +* 단, dict에서 `Set Item` 할때 + Amortized Worst Case O(n) 말고 + Average Case O(1) 적용 가정 + +2 +ref: https://docs.python.org/3/library/collections.html#collections.Counter +A Counter is a dict subclass for counting hashable objects. + +Counter, 즉, dict의 (값, 키) 튜플을 sorting하는 데에 TC: O(n log n), SC: O(n) +* 이때 값이 클수록 앞에 오게 하기 위해 값을 음수로 바꿔줬다. + +3 +sorted된 리스트에서 튜플의 두 번째 아이템만 뽑은 다음에 +리스트의 앞 k개의 아이템 리턴. +""" + +from collections import Counter + + +class Solution: + def topKFrequent(self, nums: List[int], n: int) -> List[int]: + return [i for _, i in sorted([(-v, k) for k, v in Counter(nums).items()])][:n]