diff --git a/insert-interval/KwonNayeon.py b/insert-interval/KwonNayeon.py new file mode 100644 index 000000000..ee8839ccf --- /dev/null +++ b/insert-interval/KwonNayeon.py @@ -0,0 +1,50 @@ +""" +Constraints: +- 0 <= intervals.length <= 10^4 +- intervals[i].length == 2 +- 0 <= starti <= endi <= 10^5 +- intervals is sorted by starti in ascending order. +- newInterval.length == 2 +- 0 <= start <= end <= 10^5 + +Time Complexity: O(n) +- 모든 interval을 한 번씩만 처리함 + +Space Complexity: O(n) +- 최악의 경우 모든 interval을 결과 리스트에 저장 + +풀이방법: +1. 세 단계로 구분하여 처리: + - Step 1: newInterval보다 앞에 있는 intervals → 결과에 바로 추가 + - Step 2: newInterval과 겹치는 intervals → 병합하여 하나의 interval로 만듦 + - Step 3: newInterval보다 뒤에 있는 intervals → 결과에 바로 추가 +2. 병합 조건: + - 두 interval이 겹치는 조건: intervals[i][0] <= mergedInterval[1] + - 병합 시 시작점: min(mergedInterval[0], intervals[i][0]) + - 병합 시 끝점: max(mergedInterval[1], intervals[i][1]) + +노트: +- 세 단계로 구분하여 처리하는 게 쉽지 않았다. 다음에 풀 땐 스스로 해결해볼 것 +""" +class Solution: + def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: + result = [] + i = 0 + n = len(intervals) + + while i < n and intervals[i][1] < newInterval[0]: + result.append(intervals[i]) + i += 1 + + merged_interval = newInterval + while i < n and intervals[i][0] <= merged_interval[1]: + merged_interval[0] = min(merged_interval[0], intervals[i][0]) + merged_interval[1] = max(merged_interval[1], intervals[i][1]) + i += 1 + result.append(merged_interval) + + while i < n: + result.append(intervals[i]) + i += 1 + + return result diff --git a/kth-smallest-element-in-a-bst/KwonNayeon.py b/kth-smallest-element-in-a-bst/KwonNayeon.py new file mode 100644 index 000000000..8791604ad --- /dev/null +++ b/kth-smallest-element-in-a-bst/KwonNayeon.py @@ -0,0 +1,46 @@ +""" +Constraints: +- The number of nodes in the tree is n. +- 1 <= k <= n <= 10^4 +- 0 <= Node.val <= 10^4 + +Time Complexity: O(n) +- 최악의 경우 모든 노드를 방문 + +Space Complexity: O(h) +- 여기서 h는 트리의 높이, 스택에 최대 h개의 노드가 저장됨 + +풀이방법: +1. 중위 순회(in-order)를 활용하여 BST의 노드를 오름차순으로 방문 +2. 스택을 활용: + - 트리의 왼쪽으로 내려가면서 모든 노드를 스택에 저장 + - 스택에서 노드를 꺼내고 카운트 증가 + - k번째 노드를 찾으면 해당 값을 반환 + - 오른쪽 트리에 대해서 이 과정을 반복 +3. 중위 순회 시 노드 값을 오름차순으로 방문하므로, k번째로 방문한 노드가 k번째 작은 값 +""" +# 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: + stack = [] + node = root + count = 0 + + while node or stack: + + while node: + stack.append(node) + node = node.left + + node = stack.pop() + count += 1 + + if count == k: + return node.val + + node = node.right diff --git a/lowest-common-ancestor-of-a-binary-search-tree/KwonNayeon.py b/lowest-common-ancestor-of-a-binary-search-tree/KwonNayeon.py new file mode 100644 index 000000000..00ea98940 --- /dev/null +++ b/lowest-common-ancestor-of-a-binary-search-tree/KwonNayeon.py @@ -0,0 +1,44 @@ +""" +Constraints: +- The number of nodes in the tree is in the range [2, 10^5]. +- -10^9 <= Node.val <= 10^9 +- All Node.val are unique. +- p != q +- p and q will exist in the BST. + +Time Complexity: O(h) +- 여기서 h는 트리의 높이 + +Space Complexity: O(1) +- node 변수만 사용하므로 상수공간 + +풀이방법: +1. LCA 노드란: + - 두 노드 중 하나가 다른 하나의 조상인 경우, 상위에 위치한 노드가 LDA + - 그렇지 않으면, 두 노드를 타고 위로 올라가면 처음 만나는 노드가 LDA +2. BST에서 LCA 찾기: + - 현재 노드의 값이 p와 q보다 큰 경우 -> 왼쪽으로 이동 + - 현재 노드의 값이 p와 q보다 작은 경우 -> 오른쪽으로 이동 + - 그 외의 경우(현재 노드가 p와 q 사이에 있거나 p나 q 중 하나와 같으면) -> 현재 노드가 LCA +""" +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + node = root + + while node: + + if p.val < node.val and q.val < node.val: + node = node.left + + elif p.val > node.val and q.val > node.val: + node = node.right + + else: + return node diff --git a/meeting-rooms/KwonNayeon.py b/meeting-rooms/KwonNayeon.py new file mode 100644 index 000000000..3df860ff5 --- /dev/null +++ b/meeting-rooms/KwonNayeon.py @@ -0,0 +1,50 @@ +""" +Constraints: +- 0 ≤ intervals.length ≤ 10^4 +- intervals[i].length == 2 +- 0 ≤ start_i < end_i ≤ 10^6 +- [(0,8), (8,10)] is not conflict at 8 + +Time Complexity: O(nlogn) +- 정렬에 nlogn, 순회에 n이 필요하므로 전체는 O(nlogn) + +Space Complexity: O(1) +- 정해진 개수의 변수 외에는 추가 공간을 사용하지 않음 + +풀이방법: +1. Base case: 빈 배열/none일 때 True 반환 +2. intervals를 시작점 기준으로 정렬 +3. prev_end 초기화 (첫 번째 미팅의 종료 시간) +4. 두 번째 미팅부터 순회하면서: + - 만약 현재 시작점 (미팅 시작 시간)이 이전 미팅의 종료 시간보다 작으면 false 반환 + - 그렇지 않으면 prev_end를 현재 미팅의 종료 시간으로 업데이트 +5. 모든 미팅을 검사한 후에도 충돌이 없으면 true 반환 +""" +from typing import List + +class Interval: + def __init__(self, start, end): + self.start = start + self.end = end + +class Solution: + """ + @param intervals: an array of meeting time intervals + @return: if a person could attend all meetings + """ + def can_attend_meetings(self, intervals: List[Interval]) -> bool: + if not intervals: + return True + + intervals.sort(key=lambda x: x.start) + + prev_end = intervals[0].end + + for interval in intervals[1:]: + + if interval.start < prev_end: + return False + prev_end = interval.end + + return True +