Code › algorithm-study
LeetCode 11 - Container With Most Water
양쪽 높이 중 작은 값을 기준으로 포인터를 이동하는 two pointers Python 풀이
두 수직선 사이에 담을 수 있는 물의 최대 넓이를 구하는 Medium 문제다. 모든 쌍을 확인하면 간단하지만 시간 복잡도가 O(n²)이 되므로, 양 끝에서 시작하는 two pointers로 탐색 범위를 줄였다.
문제 링크 & 설명
- 문제 링크: 11. Container With Most Water
- 요약: 각 위치의 높이가 담긴 배열에서 두 선을 골라, 두 선과 x축이 만드는 용기의 최대 넓이를 구한다.
두 선의 거리는 가로 길이가 되고, 물의 높이는 둘 중 더 낮은 선을 넘을 수 없다. 따라서 left와 right를 골랐을 때 넓이는 (right - left) * min(height[left], height[right])로 계산한다.
접근 방법
left는 배열의 처음, right는 마지막에서 시작한다. 현재 넓이를 계산해 최댓값을 갱신한 다음 두 높이 중 더 낮은 쪽의 포인터를 안으로 옮긴다.
area = min(height[left], height[right]) * (right - left)
max_area = max(max_area, area)
if height[left] < height[right]:
left += 1
else:
right -= 1
더 높은 쪽을 옮겨도 현재 넓이를 제한하는 낮은 높이는 그대로 남고 가로 길이만 줄어든다. 반면 낮은 쪽을 옮기면 가로 길이는 줄어들지만, 더 높은 선을 만나 물의 높이가 커질 가능성이 생긴다. 이 기준 덕분에 모든 조합을 만들지 않고도 한 번의 순회로 답을 찾을 수 있다.
복잡도 분석
- 시간 복잡도: O(n)
- 매 반복마다 left 또는 right가 한 칸 이동하므로 각 위치를 최대 한 번씩 확인한다.
- 공간 복잡도: O(1)
- 두 포인터와 최대 넓이를 저장하는 변수만 사용한다.
구현 코드
from typing import List
class Solution:
def maxArea(self, height: List[int]) -> int:
left = 0
right = len(height) - 1
max_area = 0
while left < right:
area = min(height[left], height[right]) * (right - left)
max_area = max(max_area, area)
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_area
요약 및 회고
이 문제에서 two pointers를 움직이는 기준은 현재 넓이를 제한하는 쪽이 어디인지에 달려 있었다. 낮은 선을 남겨둔 채 가로 길이만 줄이는 선택은 더 큰 넓이를 만들 수 없으므로 바로 제외할 수 있다. 포인터 이동 규칙을 외우기보다, 어떤 값이 현재 결과의 상한을 정하는지 확인하는 편이 훨씬 이해하기 쉬웠다.