From 64bd1c3283e69f35db06fffcde642bb84b7f138b Mon Sep 17 00:00:00 2001 From: woo Date: Mon, 10 Aug 2026 09:23:07 +0900 Subject: [PATCH 1/5] [alphaorderly] WEEK 08 Solutions --- clone-graph/alphaorderly.py | 32 ++++++ longest-common-subsequence/alphaorderly.py | 34 ++++++ .../alphaorderly.py | 102 ++++++++++++++++++ palindromic-substrings/alphaorderly.py | 39 +++++++ reverse-bits/alphaorderly.py | 19 ++++ 5 files changed, 226 insertions(+) create mode 100644 clone-graph/alphaorderly.py create mode 100644 longest-common-subsequence/alphaorderly.py create mode 100644 longest-repeating-character-replacement/alphaorderly.py create mode 100644 palindromic-substrings/alphaorderly.py create mode 100644 reverse-bits/alphaorderly.py diff --git a/clone-graph/alphaorderly.py b/clone-graph/alphaorderly.py new file mode 100644 index 0000000000..b46729e32b --- /dev/null +++ b/clone-graph/alphaorderly.py @@ -0,0 +1,32 @@ +""" +시간복잡도 : O(V + E) +공간복잡도 : O(V) + +1. made 딕셔너리를 초기화한다. +2. copy_node 함수를 정의한다. +3. copy_node 함수는 target 노드를 복사한 후 반환한다. +4. 이미 복사한 노드는 made에서 재사용한다. +5. 복사한 노드의 이웃들 또한 copy_node를 이용해 재귀적으로 복사한다. +6. 최종적으로 복제된 그래프의 시작 노드를 반환한다. +""" +class Solution: + def cloneGraph(self, node: Optional["Node"]) -> Optional["Node"]: + + made = dict() + + def copy_node(target: Node) -> Node: + if not target: + return None + + copied = Node(target.val) + made[target.val] = copied + + for nei in target.neighbors: + if nei.val in made: + copied.neighbors.append(made[nei.val]) + else: + copied.neighbors.append(copy_node(nei)) + + return copied + + return copy_node(node) diff --git a/longest-common-subsequence/alphaorderly.py b/longest-common-subsequence/alphaorderly.py new file mode 100644 index 0000000000..3104e1ed80 --- /dev/null +++ b/longest-common-subsequence/alphaorderly.py @@ -0,0 +1,34 @@ +""" +시간복잡도 : O(T1 * T2) +공간복잡도 : O(T1) # T1에 짧은 문자열을 설정했기에 공간복잡도는 T1이 된다. + +1. text1과 text2 중 더 짧은 쪽을 text1으로 설정한다. +2. T1과 T2를 각각 text1과 text2의 길이로 설정한다. +3. dp 배열을 T1 + 1 크기로 0으로 초기화한다. +4. text2의 각 문자(i)를 순회하면서 비교한다. +5. new_dp 배열을 T1 + 1 크기로 0으로 초기화한다. +6. text1의 각 문자(j)에 대해 순회하면서 비교한다. +7. text2[i - 1]과 text1[j - 1]가 같으면, new_dp[j]를 dp[j - 1] + 1로 설정한다. +8. 다르면, new_dp[j]를 max(new_dp[j - 1], dp[j])로 설정한다. +9. dp를 new_dp로 갱신하고, 마지막 원소를 반환한다. +""" +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + if len(text1) > len(text2): + text1, text2 = text1, text2 + + T1, T2 = len(text1), len(text2) + dp = [0] * (T1 + 1) + + for i in range(1, T2 + 1): + new_dp = [0] * (T1 + 1) + + for j in range(1, T1 + 1): + if text2[i - 1] == text1[j - 1]: + new_dp[j] = dp[j - 1] + 1 + else: + new_dp[j] = max(new_dp[j - 1], dp[j]) + + dp = new_dp + + return dp[-1] diff --git a/longest-repeating-character-replacement/alphaorderly.py b/longest-repeating-character-replacement/alphaorderly.py new file mode 100644 index 0000000000..a13102ac19 --- /dev/null +++ b/longest-repeating-character-replacement/alphaorderly.py @@ -0,0 +1,102 @@ +""" +시간복잡도 : O(N) +공간복잡도 : O(1) + +1. freq 딕셔너리를 초기화한다. +2. s의 각 문자(value)에 대해 루프를 돈다. +3. freq[value]를 1 증가시킨다. +4. maxima를 현재 윈도우에서 가장 빈도가 높은 문자 빈도로 갱신한다. +5. 윈도우 크기에서 maxima의 값만큼을 뺀 값이 k보다 크면, +6. freq[s[left]]를 1 감소시키고 left를 1 증가시킨다. +7. ans를 윈도우의 최대 길이로 갱신한다. +8. 마지막으로 ans를 반환한다. +""" +class Solution: + def characterReplacement(self, s: str, k: int) -> int: + freq = defaultdict(int) + # maxima : 현재 윈도우 내에서 가장 많이 등장한 문자의 빈도수 + maxima = left = ans = 0 + + for right, value in enumerate(s): + freq[value] += 1 + maxima = max(maxima, freq[value]) + + while (right - left + 1) - maxima > k: + freq[s[left]] -= 1 + left += 1 + + ans = max(ans, right - left + 1) + + return ans + +""" +시간복잡도 : O(log N) +공간복잡도 : O(N) + +### 세그먼트 트리 구현 ### (윈도우 내 전체만 사용하므로 query 구현 없음) + +#### 세그먼트 트리 원리 +- 각 알파벳 빈도 합과 빈도가 가장 높은 문자의 빈도를 저장하는 세그먼트 트리를 사용한다. + +#### 코드 설명 +- window.update로 알파벳 개수를 갱신하며, +- window.tree[1][0]에서 현재 윈도우 내 전체 문자 수, +- window.tree[1][1]에서 윈도우 내 등장 빈도가 가장 높은 문자의 개수를 구한다. +- 윈도우 크기 - 최대 빈도가 k를 초과하면 left를 옮기며 윈도우를 줄인다. + +> 불필요하게 복잡한 구현이지만, 세그먼트 트리를 공부하기엔 좋은 예제가 될 수 있다. +""" +class SegTree: + def __init__(self): + # [문자 개수 합, 최대값] + self.tree = [[0, 0] for _ in range(26 * 4 + 1)] + + def _update( + self, + node_index: int, + target_index: int, + target_update: int, + seg_left: int, + seg_right: int, + ): + if seg_left == seg_right: + self.tree[node_index][0] += target_update + self.tree[node_index][1] += target_update + return + + mid = (seg_left + seg_right) // 2 + + if target_index <= mid: + self._update(node_index * 2, target_index, target_update, seg_left, mid) + else: + self._update( + node_index * 2 + 1, target_index, target_update, mid + 1, seg_right + ) + + self.tree[node_index][0] = ( + self.tree[node_index * 2][0] + self.tree[node_index * 2 + 1][0] + ) + self.tree[node_index][1] = max( + self.tree[node_index * 2][1], self.tree[node_index * 2 + 1][1] + ) + + def update(self, target: str, update: int): + self._update(1, ord(target) - ord("A"), update, 0, 25) + + +class Solution: + def characterReplacement(self, s: str, k: int) -> int: + left = 0 + window = SegTree() + ans = 0 + + for right, value in enumerate(s): + window.update(value, 1) + + while window.tree[1][0] > 0 and window.tree[1][0] - window.tree[1][1] > k: + window.update(s[left], -1) + left += 1 + + ans = max(ans, right - left + 1) + + return ans diff --git a/palindromic-substrings/alphaorderly.py b/palindromic-substrings/alphaorderly.py new file mode 100644 index 0000000000..1d84b3236b --- /dev/null +++ b/palindromic-substrings/alphaorderly.py @@ -0,0 +1,39 @@ +""" +시간복잡도 : O(N^2) +공간복잡도 : O(1) + +1. n을 s의 길이로 설정한다. +2. count를 0으로 초기화한다. +3. 각 문자를 중심(center)으로 확장하여 홀수 길이의 팰린드롬을 센다. + - radius를 0부터 시작해, center - radius >= 0, center + radius < n 이고 s[center - radius] == s[center + radius]인 동안 count를 1 증가, radius += 1 한다. +4. 각 문자 쌍(center, center+1)을 중심으로 확장하여 짝수 길이의 팰린드롬을 센다. + - radius를 0부터 시작해, center - radius >= 0, center + radius + 1 < n 이고 s[center - radius] == s[center + radius + 1]인 동안 count를 1 증가, radius += 1 한다. +5. 총 팰린드롬 부분 문자열 개수인 count를 반환한다. +""" +class Solution: + def countSubstrings(self, s: str) -> int: + n = len(s) + count = 0 + + for center in range(n): + radius = 0 + # 홀수 길이 팰린드롬 (center를 기준) + while ( + center - radius >= 0 + and center + radius < n + and s[center - radius] == s[center + radius] + ): + count += 1 + radius += 1 + + radius = 0 + # 짝수 길이 팰린드롬 (center, center+1을 기준) + while ( + center - radius >= 0 + and center + radius + 1 < n + and s[center - radius] == s[center + radius + 1] + ): + count += 1 + radius += 1 + + return count diff --git a/reverse-bits/alphaorderly.py b/reverse-bits/alphaorderly.py new file mode 100644 index 0000000000..392b491da7 --- /dev/null +++ b/reverse-bits/alphaorderly.py @@ -0,0 +1,19 @@ +""" +시간복잡도: O(1) # 32번만 반복하므로 항상 상수 시간 복잡도임 +공간복잡도: O(1) + +1. ans를 0으로 초기화한다. +3. ans를 왼쪽으로 1비트 시프트한 후, n의 마지막 비트를 OR 연산한다. +4. n을 오른쪽으로 1비트 시프트한다. +- 3, 4 과정을 32번 반복한다. +5. ans를 반환한다. +""" +class Solution: + def reverseBits(self, n: int) -> int: + ans = 0 + + for _ in range(32): + ans = (ans << 1) | (n & 1) + n >>= 1 + + return ans From c112ef379d6e2322483ce8910e5413ad453541c8 Mon Sep 17 00:00:00 2001 From: woo Date: Mon, 10 Aug 2026 09:28:36 +0900 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20=EC=A3=BC=EC=84=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alphaorderly.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/longest-repeating-character-replacement/alphaorderly.py b/longest-repeating-character-replacement/alphaorderly.py index a13102ac19..8fa6483ca1 100644 --- a/longest-repeating-character-replacement/alphaorderly.py +++ b/longest-repeating-character-replacement/alphaorderly.py @@ -30,21 +30,25 @@ def characterReplacement(self, s: str, k: int) -> int: return ans """ -시간복잡도 : O(log N) -공간복잡도 : O(N) - -### 세그먼트 트리 구현 ### (윈도우 내 전체만 사용하므로 query 구현 없음) - -#### 세그먼트 트리 원리 -- 각 알파벳 빈도 합과 빈도가 가장 높은 문자의 빈도를 저장하는 세그먼트 트리를 사용한다. - -#### 코드 설명 -- window.update로 알파벳 개수를 갱신하며, -- window.tree[1][0]에서 현재 윈도우 내 전체 문자 수, -- window.tree[1][1]에서 윈도우 내 등장 빈도가 가장 높은 문자의 개수를 구한다. -- 윈도우 크기 - 최대 빈도가 k를 초과하면 left를 옮기며 윈도우를 줄인다. - -> 불필요하게 복잡한 구현이지만, 세그먼트 트리를 공부하기엔 좋은 예제가 될 수 있다. +시간복잡도: O(NlogN) + - 세그먼트 트리 한 번 업데이트: O(logN) + - 슬라이딩 윈도우 오른쪽 포인터 한 번씩 전진: O(N) +공간복잡도: O(N) + - 세그먼트 트리 크기: O(N) (알파벳 26개에 대해 4N+1 노드) + +[세그먼트 트리 개요] +- 각 알파벳(A~Z)의 빈도수를 표현하는 세그먼트 트리를 구현함. +- 각 트리 노드는 구간 내 현재 알파벳 빈도 총합과 그 구간 내 최빈값(가장 많이 등장한 알파벳의 빈도)을 저장함. +- 이진 트리 구조로 각 알파벳 인덱스를 리프 노드(0~25)에 매핑. + +[핵심 동작 설명] +- window.update(문자, ±1): 현재 윈도우에 새 문자를 추가/제거할 때 해당 알파벳의 빈도수를 O(logN)에 갱신. +- window.tree[1][0]: 세그먼트 트리 루트의 첫 번째 값으로, 현재 윈도우 내 전체 문자 개수(윈도우 길이)를 의미. +- window.tree[1][1]: 루트의 두 번째 값으로, 현재 윈도우 내에서 가장 많이 등장한 문자의 등장 횟수를 의미. +- (윈도우 전체길이 - 최빈값) > k 를 만족할 때까지 왼쪽 포인터를 옮기며(=왼쪽 문자 제거), 윈도우가 k개 이하의 문자만 바꾸면 모두 동일하게 만들 수 있는 범위로 축소. +- 매 반복마다 ans를 최대 윈도우 크기로 갱신. + +※ 세그먼트 트리 사용은 이 문제에 최적해는 아니나, 자료구조 학습에는 좋은 연습 예제. """ class SegTree: def __init__(self): From 34105e6eb1040d798f9292ad91b1b9faf2b0ec1b Mon Sep 17 00:00:00 2001 From: woo Date: Mon, 10 Aug 2026 09:36:25 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=ED=95=84=EC=9A=94=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95=20(08)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- longest-repeating-character-replacement/alphaorderly.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/longest-repeating-character-replacement/alphaorderly.py b/longest-repeating-character-replacement/alphaorderly.py index 8fa6483ca1..dec52c0c4b 100644 --- a/longest-repeating-character-replacement/alphaorderly.py +++ b/longest-repeating-character-replacement/alphaorderly.py @@ -52,7 +52,7 @@ def characterReplacement(self, s: str, k: int) -> int: """ class SegTree: def __init__(self): - # [문자 개수 합, 최대값] + # summation, largest self.tree = [[0, 0] for _ in range(26 * 4 + 1)] def _update( @@ -97,7 +97,7 @@ def characterReplacement(self, s: str, k: int) -> int: for right, value in enumerate(s): window.update(value, 1) - while window.tree[1][0] > 0 and window.tree[1][0] - window.tree[1][1] > k: + while window.tree[1][0] - window.tree[1][1] > k: window.update(s[left], -1) left += 1 From 375d1fe0b2ae14faed9a5367bd6f2a1bc15458a1 Mon Sep 17 00:00:00 2001 From: woo Date: Tue, 11 Aug 2026 16:09:34 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=EC=9D=B4=EC=83=81=ED=95=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- longest-common-subsequence/alphaorderly.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/longest-common-subsequence/alphaorderly.py b/longest-common-subsequence/alphaorderly.py index 3104e1ed80..5ccd6db53c 100644 --- a/longest-common-subsequence/alphaorderly.py +++ b/longest-common-subsequence/alphaorderly.py @@ -15,7 +15,7 @@ class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: if len(text1) > len(text2): - text1, text2 = text1, text2 + text1, text2 = text2, text1 T1, T2 = len(text1), len(text2) dp = [0] * (T1 + 1) From cdb9b504194d8ba338a1354f055182961de44b85 Mon Sep 17 00:00:00 2001 From: woo Date: Sat, 15 Aug 2026 23:51:54 +0900 Subject: [PATCH 5/5] [alphaorderly] WEEK 09 Solutions --- linked-list-cycle/alphaorderly.py | 35 ++++++++++ maximum-product-subarray/alphaorderly.py | 32 +++++++++ minimum-window-substring/alphaorderly.py | 64 +++++++++++++++++ pacific-atlantic-water-flow/alphaorderly.py | 76 +++++++++++++++++++++ sum-of-two-integers/alphaorderly.py | 39 +++++++++++ 5 files changed, 246 insertions(+) create mode 100644 linked-list-cycle/alphaorderly.py create mode 100644 maximum-product-subarray/alphaorderly.py create mode 100644 minimum-window-substring/alphaorderly.py create mode 100644 pacific-atlantic-water-flow/alphaorderly.py create mode 100644 sum-of-two-integers/alphaorderly.py diff --git a/linked-list-cycle/alphaorderly.py b/linked-list-cycle/alphaorderly.py new file mode 100644 index 0000000000..cf25087094 --- /dev/null +++ b/linked-list-cycle/alphaorderly.py @@ -0,0 +1,35 @@ + +""" +시간복잡도: O(n) +공간복잡도: O(1) + +1. 토끼와 거북이를 초기화한다. + - 토끼 : 두 칸씩 이동 + - 거북이 : 한 칸씩 이동 +2. 토끼와 거북이가 만날 때까지 이동한다. +3. 토끼와 거북이가 만나면 사이클이 있다고 판단한다. +4. 토끼와 거북이가 만나지 않으면 사이클이 없다고 판단한다. + +# 원리 # +- 사이클이 존재하지 않는다면 토끼와 거북이는 결국 끝에 도달한다. +- 사이클이 존재한다면 토끼와 거북이는 결국 사이클 내에서 만난다. +""" +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + +class Solution: + def hasCycle(self, head: Optional[ListNode]) -> bool: + hare = head + tortoise = head + + while hare and hare.next: + hare = hare.next.next + tortoise = tortoise.next + + if hare is tortoise: + return True + + return False diff --git a/maximum-product-subarray/alphaorderly.py b/maximum-product-subarray/alphaorderly.py new file mode 100644 index 0000000000..18ef35418c --- /dev/null +++ b/maximum-product-subarray/alphaorderly.py @@ -0,0 +1,32 @@ +""" +시간복잡도: O(n) +공간복잡도: O(1) + +- 만약 현재 숫자가 음수라면, 양수 최대값(pos)과 음수 최소값(neg)을 서로 교환한다. + - 이유: 음수 * 음수 = 양수이므로, 음수를 만나면 최대값/최소값 후보가 바뀔 수 있다. +- pos와 neg를 nums의 첫 번째 값으로 초기화한다. + - pos: 현재까지의 양수 곱셈 최대값 + - neg: 현재까지의 음수 곱셈 최소값 +- ans를 nums의 첫 번째 값으로 초기화한다. + - ans: 현재까지의 최대 곱셈 결과 +- nums의 두 번째 원소부터 끝까지 pos와 neg를 갱신한다. + - pos는 현재 숫자와 pos*현재 숫자 중 큰 값 + - neg는 현재 숫자와 neg*현재 숫자 중 작은 값 +- ans를 pos와 비교하여 최대값으로 갱신한다. +- 반복이 끝나면 ans를 반환한다. +""" +class Solution: + def maxProduct(self, nums: List[int]) -> int: + pos = neg = ans = nums[0] + N = len(nums) + + for i in range(1, N): + if nums[i] < 0: + neg, pos = pos, neg + + pos = max(nums[i], nums[i] * pos) + neg = min(nums[i], nums[i] * neg) + + ans = max(ans, pos) + + return ans diff --git a/minimum-window-substring/alphaorderly.py b/minimum-window-substring/alphaorderly.py new file mode 100644 index 0000000000..264680a8e5 --- /dev/null +++ b/minimum-window-substring/alphaorderly.py @@ -0,0 +1,64 @@ +""" + +시간복잡도: O(n) +공간복잡도: O(1) + +슬라이딩 윈도우 기법을 사용해 문자열 s에서 t의 모든 문자를 포함하는 최소 윈도우를 찾는다. + +Window 클래스는 타겟 문자열(t)에 구성된 각 문자별 필요한 개수를 카운트하고, +윈도우 내 해당 문자 개수를 관리하며, 현재 윈도우가 타겟을 만족하는지(check) 확인한다. + +add 메서드는 윈도우에 문자를 추가하여 개수를 갱신하고, + - 타겟의 문자 갯수와 같아지면 key_count를 증가시킨다. +remove 메서드는 윈도우에서 문자를 제거하여 개수를 줄인다. + - 타겟의 문자 갯수보다 작아지면 key_count를 감소시킨다. + +check 메서드는 윈도우에 타겟 문자가 필요한 만큼 모두 포함되어 있는지 검사한다. + - key_count와 target_count가 같으면 True를 반환한다. +""" +class Window: + def __init__(self, target: str): + self.target = Counter(target) + self.window = defaultdict(int) + + self.key_count = 0 + self.target_count = len(self.target) + + def check(self): + return self.key_count == self.target_count + + def add(self, ch: str): + self.window[ch] += 1 + + if self.window[ch] == self.target[ch]: + self.key_count += 1 + + def remove(self, ch: str): + self.window[ch] -= 1 + if self.window[ch] < self.target[ch]: + self.key_count -= 1 + + +class Solution: + def minWindow(self, s: str, t: str) -> str: + window = Window(t) + left = 0 + ans = (-float("inf"), float("inf")) + + for right, value in enumerate(s): + + window.add(value) + if not window.check(): + continue + + while window.check(): + window.remove(s[left]) + left += 1 + + if ans[1] - ans[0] > right - left: + ans = (left - 1, right) + + if ans[0] == -float("inf"): + return "" + + return s[ans[0] : ans[1] + 1] diff --git a/pacific-atlantic-water-flow/alphaorderly.py b/pacific-atlantic-water-flow/alphaorderly.py new file mode 100644 index 0000000000..dab1852476 --- /dev/null +++ b/pacific-atlantic-water-flow/alphaorderly.py @@ -0,0 +1,76 @@ +""" +시간복잡도: O(m * n) +공간복잡도: O(m * n) + +1. 태평양과 대서양 각각에서 물이 도달할 수 있는 위치를 기록할 2차원 배열(check)을 만든다. +2. 태평양과 맞닿은 칸들(왼쪽 열과 위쪽 행)에는 태평양 도달 가능(값 1), 대서양과 맞닿은 칸들(오른쪽 열과 아래쪽 행)에는 대서양 도달 가능(값 2) 표시를 한다. + - 1: 태평양, 2: 대서양 — 2진수로는 각각 01, 10이라는 의미임. +3. 각 바다에 인접한 칸들에서 시작해, BFS를 이용해 도달 가능한 모든 칸을 확장한다. + - 인접한 칸으로 이동할 때, 항상 지금 칸보다 높이가 같거나 더 높은 칸으로만 물이 흐를 수 있다(즉, 물이 거슬러 흐르는 조건). + - 이미 같은 바다에서 방문한 적이 있는 칸은 건너뛴다. + - 새로운 위치에 도달할 때마다 check 배열을 갱신하고 큐에 추가한다. +4. 태평양과 대서양에서 모두 도달 가능한 칸(값이 3이 된 칸)을 답으로 모아 반환한다. + +# 비트마스킹 기법 사용 원리 # +- 태평양과 대서양 두 바다에서 도달 가능한 칸을 표시하기 위해 비트마스킹 기법을 사용한다. +- 각 칸에 대해, 1비트(01)는 태평양(Pacific), 2비트(10)는 대서양(Atlantic) 도달 가능을 의미한다. +- 예를 들어 각 칸의 값이 1이면 태평양, 2이면 대서양, 3이면 두 바다 모두에 도달 가능한 칸임을 나타낸다. +- bfs/dfs로 인접 칸(상하좌우)로 확장할 때, 이미 해당 바다의 비트가 켜져 있으면 방문하지 않는다. +""" +class Solution: + def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: + ROW = len(heights) + COL = len(heights[0]) + DIR = [ + [1, 0], + [0, 1], + [-1, 0], + [0, -1] + ] + + check = [[0] * COL for _ in range(ROW)] + + for r in range(ROW): + check[r][0] |= 1 + check[r][COL - 1] |= 2 + + for c in range(COL): + check[0][c] |= 1 + check[ROW - 1][c] |= 2 + + queue = deque([]) + + for r in range(ROW): + for c in range(COL): + if check[r][c] != 0: + queue.append((r, c)) + + def bound(row: int, col: int) -> bool: + return 0 <= row < ROW and 0 <= col < COL + + while queue: + r, c = queue.popleft() + + for dr, dc in DIR: + tr, tc = r + dr, c + dc + + if not bound(tr, tc): + continue + + if heights[tr][tc] < heights[r][c]: + continue + + if check[tr][tc] | check[r][c] == check[tr][tc]: + continue + + check[tr][tc] |= check[r][c] + queue.append((tr, tc)) + + ans = [] + + for r in range(ROW): + for c in range(COL): + if check[r][c] == 3: + ans.append([r, c]) + + return ans diff --git a/sum-of-two-integers/alphaorderly.py b/sum-of-two-integers/alphaorderly.py new file mode 100644 index 0000000000..13e68ba20f --- /dev/null +++ b/sum-of-two-integers/alphaorderly.py @@ -0,0 +1,39 @@ +""" +시간복잡도: O(1) +공간복잡도: O(1) + +16비트 정수 범위에서 각 비트를 하나씩 확인하며 덧셈을 수행한다. + +각 비트의 합은 XOR 연산으로 구하고, +올림수(carry)는 두 비트 이상이 1인 경우를 OR 연산으로 계산한다. + - 전가산기 원리 적용 + +계산된 각 비트는 ans의 해당 위치에 저장한다. + +Python의 int는 고정된 비트 폭을 가지지 않으므로, +최종 결과의 최상위 비트가 1인 경우에는 16비트 음수로 직접 변환한다. + +MASK와 XOR하여 16비트 범위 안에서 비트를 반전한 뒤, +~ 연산을 적용하여 Python의 음수 정수 형태로 변환한다. +""" +class Solution: + def getSum(self, a: int, b: int) -> int: + MASK = 0xFFFF + CHECK = 0x8000 + + ans = carry = left = 0 + for i in range(16): + a_bit = a & 1 + b_bit = b & 1 + + left = a_bit ^ b_bit ^ carry + carry = (a_bit & b_bit) | (b_bit & carry) | (a_bit & carry) + + ans |= left * 2**i + a >>= 1 + b >>= 1 + + if ans & CHECK == 0: + return ans + else: + return ~(MASK ^ ans)