02_array_string.py

Download
python 265 lines 7.8 KB
  1"""
  2ํˆฌ ํฌ์ธํ„ฐ (Two Pointer) ๊ธฐ๋ฒ•
  3Two Pointer Technique
  4
  5๋‘ ๊ฐœ์˜ ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด/๋ฆฌ์ŠคํŠธ ๋ฌธ์ œ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  6"""
  7
  8from typing import List, Tuple, Optional
  9
 10
 11# =============================================================================
 12# 1. ๋‘ ์ˆ˜์˜ ํ•ฉ (์ •๋ ฌ๋œ ๋ฐฐ์—ด)
 13# =============================================================================
 14def two_sum_sorted(arr: List[int], target: int) -> Optional[Tuple[int, int]]:
 15    """
 16    ์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ํ•ฉ์ด target์ธ ๋‘ ์ˆ˜์˜ ์ธ๋ฑ์Šค ์ฐพ๊ธฐ
 17    ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
 18    """
 19    left, right = 0, len(arr) - 1
 20
 21    while left < right:
 22        current_sum = arr[left] + arr[right]
 23
 24        if current_sum == target:
 25            return (left, right)
 26        elif current_sum < target:
 27            left += 1  # ํ•ฉ์ด ์ž‘์œผ๋ฉด ์™ผ์ชฝ ํฌ์ธํ„ฐ๋ฅผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ
 28        else:
 29            right -= 1  # ํ•ฉ์ด ํฌ๋ฉด ์˜ค๋ฅธ์ชฝ ํฌ์ธํ„ฐ๋ฅผ ์™ผ์ชฝ์œผ๋กœ
 30
 31    return None
 32
 33
 34# =============================================================================
 35# 2. ์„ธ ์ˆ˜์˜ ํ•ฉ (3Sum)
 36# =============================================================================
 37def three_sum(arr: List[int]) -> List[List[int]]:
 38    """
 39    ํ•ฉ์ด 0์ธ ์„ธ ์ˆ˜์˜ ์กฐํ•ฉ ๋ชจ๋‘ ์ฐพ๊ธฐ (์ค‘๋ณต ์ œ๊ฑฐ)
 40    ์‹œ๊ฐ„๋ณต์žก๋„: O(nยฒ), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
 41    """
 42    arr.sort()
 43    result = []
 44    n = len(arr)
 45
 46    for i in range(n - 2):
 47        # ์ค‘๋ณต ๊ฑด๋„ˆ๋›ฐ๊ธฐ
 48        if i > 0 and arr[i] == arr[i - 1]:
 49            continue
 50
 51        left, right = i + 1, n - 1
 52
 53        while left < right:
 54            total = arr[i] + arr[left] + arr[right]
 55
 56            if total == 0:
 57                result.append([arr[i], arr[left], arr[right]])
 58                # ์ค‘๋ณต ๊ฑด๋„ˆ๋›ฐ๊ธฐ
 59                while left < right and arr[left] == arr[left + 1]:
 60                    left += 1
 61                while left < right and arr[right] == arr[right - 1]:
 62                    right -= 1
 63                left += 1
 64                right -= 1
 65            elif total < 0:
 66                left += 1
 67            else:
 68                right -= 1
 69
 70    return result
 71
 72
 73# =============================================================================
 74# 3. ๋ฌผ ๋‹ด๊ธฐ (Container With Most Water)
 75# =============================================================================
 76def max_water(heights: List[int]) -> int:
 77    """
 78    ๋‘ ๋ฒฝ ์‚ฌ์ด์— ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ๋ฌผ์˜ ์–‘
 79    ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
 80    """
 81    left, right = 0, len(heights) - 1
 82    max_area = 0
 83
 84    while left < right:
 85        # ํ˜„์žฌ ๋ฉด์  ๊ณ„์‚ฐ
 86        width = right - left
 87        height = min(heights[left], heights[right])
 88        area = width * height
 89        max_area = max(max_area, area)
 90
 91        # ๋” ๋‚ฎ์€ ์ชฝ์˜ ํฌ์ธํ„ฐ ์ด๋™
 92        if heights[left] < heights[right]:
 93            left += 1
 94        else:
 95            right -= 1
 96
 97    return max_area
 98
 99
100# =============================================================================
101# 4. ์ •๋ ฌ๋œ ๋‘ ๋ฐฐ์—ด ํ•ฉ๋ณ‘
102# =============================================================================
103def merge_sorted_arrays(arr1: List[int], arr2: List[int]) -> List[int]:
104    """
105    ์ •๋ ฌ๋œ ๋‘ ๋ฐฐ์—ด์„ ํ•˜๋‚˜์˜ ์ •๋ ฌ๋œ ๋ฐฐ์—ด๋กœ ํ•ฉ๋ณ‘
106    ์‹œ๊ฐ„๋ณต์žก๋„: O(n + m), ๊ณต๊ฐ„๋ณต์žก๋„: O(n + m)
107    """
108    result = []
109    i, j = 0, 0
110
111    while i < len(arr1) and j < len(arr2):
112        if arr1[i] <= arr2[j]:
113            result.append(arr1[i])
114            i += 1
115        else:
116            result.append(arr2[j])
117            j += 1
118
119    # ๋‚จ์€ ์š”์†Œ ์ถ”๊ฐ€
120    result.extend(arr1[i:])
121    result.extend(arr2[j:])
122
123    return result
124
125
126# =============================================================================
127# 5. ์ค‘๋ณต ์ œ๊ฑฐ (์ •๋ ฌ๋œ ๋ฐฐ์—ด)
128# =============================================================================
129def remove_duplicates(arr: List[int]) -> int:
130    """
131    ์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ์ค‘๋ณต ์ œ๊ฑฐ (in-place)
132    ๋ฐ˜ํ™˜๊ฐ’: ๊ณ ์œ ํ•œ ์š”์†Œ์˜ ๊ฐœ์ˆ˜
133    ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
134    """
135    if not arr:
136        return 0
137
138    write_idx = 1  # ๋‹ค์Œ ๊ณ ์œ  ๊ฐ’์„ ์“ธ ์œ„์น˜
139
140    for read_idx in range(1, len(arr)):
141        if arr[read_idx] != arr[write_idx - 1]:
142            arr[write_idx] = arr[read_idx]
143            write_idx += 1
144
145    return write_idx
146
147
148# =============================================================================
149# 6. ํšŒ๋ฌธ ๊ฒ€์‚ฌ (Palindrome)
150# =============================================================================
151def is_palindrome(s: str) -> bool:
152    """
153    ๋ฌธ์ž์—ด์ด ํšŒ๋ฌธ์ธ์ง€ ๊ฒ€์‚ฌ (์•ŒํŒŒ๋ฒณ/์ˆซ์ž๋งŒ ๋น„๊ต)
154    ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
155    """
156    left, right = 0, len(s) - 1
157
158    while left < right:
159        # ์•ŒํŒŒ๋ฒณ/์ˆซ์ž๊ฐ€ ์•„๋‹ˆ๋ฉด ๊ฑด๋„ˆ๋›ฐ๊ธฐ
160        while left < right and not s[left].isalnum():
161            left += 1
162        while left < right and not s[right].isalnum():
163            right -= 1
164
165        if s[left].lower() != s[right].lower():
166            return False
167
168        left += 1
169        right -= 1
170
171    return True
172
173
174# =============================================================================
175# 7. ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ (์ตœ๋Œ€ ํ•ฉ)
176# =============================================================================
177def max_sum_subarray(arr: List[int], k: int) -> int:
178    """
179    ํฌ๊ธฐ k์ธ ์—ฐ์† ๋ถ€๋ถ„ ๋ฐฐ์—ด์˜ ์ตœ๋Œ€ ํ•ฉ
180    ์‹œ๊ฐ„๋ณต์žก๋„: O(n), ๊ณต๊ฐ„๋ณต์žก๋„: O(1)
181    """
182    if len(arr) < k:
183        return 0
184
185    # ์ดˆ๊ธฐ ์œˆ๋„์šฐ ํ•ฉ
186    window_sum = sum(arr[:k])
187    max_sum = window_sum
188
189    # ์œˆ๋„์šฐ ์Šฌ๋ผ์ด๋”ฉ
190    for i in range(k, len(arr)):
191        window_sum = window_sum - arr[i - k] + arr[i]
192        max_sum = max(max_sum, window_sum)
193
194    return max_sum
195
196
197# =============================================================================
198# ํ…Œ์ŠคํŠธ
199# =============================================================================
200def main():
201    print("=" * 60)
202    print("ํˆฌ ํฌ์ธํ„ฐ (Two Pointer) ๊ธฐ๋ฒ• ์˜ˆ์ œ")
203    print("=" * 60)
204
205    # 1. ๋‘ ์ˆ˜์˜ ํ•ฉ
206    print("\n[1] ๋‘ ์ˆ˜์˜ ํ•ฉ (์ •๋ ฌ๋œ ๋ฐฐ์—ด)")
207    arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
208    target = 10
209    result = two_sum_sorted(arr, target)
210    print(f"    ๋ฐฐ์—ด: {arr}")
211    print(f"    ํƒ€๊ฒŸ: {target}")
212    print(f"    ๊ฒฐ๊ณผ: ์ธ๋ฑ์Šค {result} -> {arr[result[0]]} + {arr[result[1]]} = {target}")
213
214    # 2. ์„ธ ์ˆ˜์˜ ํ•ฉ
215    print("\n[2] ์„ธ ์ˆ˜์˜ ํ•ฉ (3Sum)")
216    arr = [-1, 0, 1, 2, -1, -4]
217    result = three_sum(arr)
218    print(f"    ๋ฐฐ์—ด: {arr}")
219    print(f"    ํ•ฉ์ด 0์ธ ์กฐํ•ฉ: {result}")
220
221    # 3. ๋ฌผ ๋‹ด๊ธฐ
222    print("\n[3] ๋ฌผ ๋‹ด๊ธฐ (Container With Most Water)")
223    heights = [1, 8, 6, 2, 5, 4, 8, 3, 7]
224    result = max_water(heights)
225    print(f"    ๋†’์ด: {heights}")
226    print(f"    ์ตœ๋Œ€ ๋ฌผ์˜ ์–‘: {result}")
227
228    # 4. ์ •๋ ฌ๋œ ๋ฐฐ์—ด ํ•ฉ๋ณ‘
229    print("\n[4] ์ •๋ ฌ๋œ ๋‘ ๋ฐฐ์—ด ํ•ฉ๋ณ‘")
230    arr1 = [1, 3, 5, 7]
231    arr2 = [2, 4, 6, 8, 10]
232    result = merge_sorted_arrays(arr1, arr2)
233    print(f"    ๋ฐฐ์—ด1: {arr1}")
234    print(f"    ๋ฐฐ์—ด2: {arr2}")
235    print(f"    ํ•ฉ๋ณ‘ ๊ฒฐ๊ณผ: {result}")
236
237    # 5. ์ค‘๋ณต ์ œ๊ฑฐ
238    print("\n[5] ์ค‘๋ณต ์ œ๊ฑฐ (in-place)")
239    arr = [1, 1, 2, 2, 2, 3, 4, 4, 5]
240    count = remove_duplicates(arr)
241    print(f"    ์›๋ณธ: [1, 1, 2, 2, 2, 3, 4, 4, 5]")
242    print(f"    ๊ณ ์œ  ์š”์†Œ ๊ฐœ์ˆ˜: {count}")
243    print(f"    ๊ฒฐ๊ณผ ๋ฐฐ์—ด (์•ž {count}๊ฐœ): {arr[:count]}")
244
245    # 6. ํšŒ๋ฌธ ๊ฒ€์‚ฌ
246    print("\n[6] ํšŒ๋ฌธ ๊ฒ€์‚ฌ")
247    test_strings = ["A man, a plan, a canal: Panama", "race a car", "Was it a car or a cat I saw?"]
248    for s in test_strings:
249        result = is_palindrome(s)
250        print(f"    '{s}' -> {result}")
251
252    # 7. ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ
253    print("\n[7] ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ (ํฌ๊ธฐ k ์ตœ๋Œ€ ํ•ฉ)")
254    arr = [2, 1, 5, 1, 3, 2]
255    k = 3
256    result = max_sum_subarray(arr, k)
257    print(f"    ๋ฐฐ์—ด: {arr}, k={k}")
258    print(f"    ์ตœ๋Œ€ ํ•ฉ: {result}")
259
260    print("\n" + "=" * 60)
261
262
263if __name__ == "__main__":
264    main()