[리트코드] 11 - Container With Most Water
2026년 07월 15일
1
11. Container With Most Water
Medium
You are given an integer array
height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).
Find two lines that together with the x-axis form a container, such that the container contains the most water.
Return the maximum amount of water a container can store.
Notice that you may not slant the container.
Example 1:
Input: height = [1,8,6,2,5,4,8,3,7] Output: 49 Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
Example 2:
Input: height = [1,1] Output: 1
Constraints:
n == height.length2 <= n <= 1050 <= height[i] <= 104
분류
배열, 투 포인터, 그리디
문제 풀이
문제 분석
이 문제는 수직선들의 높이를 나타내는 정수 배열 height가 주어졌을 때, 두 개의 선을 선택하여 x축과 함께 컨테이너를 만들었을 때 담을 수 있는 물의 최대량을 구하는 문제입니다.
- 입력: 길이가
n인 정수 배열height(2 ≤ n ≤ 100,000, 0 ≤ height[i] ≤ 10,000) - 출력: 컨테이너가 담을 수 있는 최대 물의 양 (정수)
- 제약 조건: 컨테이너는 기울일 수 없으므로, 물의 높이는 두 선 중 낮은 쪽의 높이로 결정됩니다. 너비는 두 선의 인덱스 차이입니다. 즉,
i,j를 선택했을 때 면적 =(j - i) * min(height[i], height[j])입니다.
접근 방법
이 문제를 해결하기 위해 투 포인터(Two Pointer) 알고리즘과 탐욕법(Greedy) 아이디어를 사용했습니다.
- 이유: 배열의 양 끝에서 시작하여 안쪽으로 포인터를 이동시키면서 최대 면적을 갱신합니다. 브루트 포스(모든 쌍 확인)는 O(N²)로 시간 초과가 발생하므로, O(N)에 풀 수 있는 투 포인터가 필수적입니다.
- 핵심 통찰: 현재 두 포인터가 가리키는 선 중 높이가 낮은 쪽 포인터를 이동시켜야만 더 큰 면적을 기대할 수 있습니다. 높은 쪽을 이동시키면 너비만 줄어들고 높이는 여전히 낮은 쪽에 의해 제한되기 때문입니다.
구현 설명
1. 변수 초기화
answer: 최대 면적을 저장할 변수, 0으로 초기화합니다.left: 배열의 시작 인덱스(0)를 가리키는 왼쪽 포인터입니다.right: 배열의 마지막 인덱스(len(height) - 1)를 가리키는 오른쪽 포인터입니다.
2. 반복문으로 포인터 이동하며 최대 면적 갱신
while left < right:조건으로 두 포인터가 만나기 전까지 반복합니다.- 현재 컨테이너의 면적은
(right - left) * min(height[left], height[right])로 계산합니다. answer = max(answer, 현재_면적)을 통해 지금까지의 최대값을 유지합니다.
3. 높이가 낮은 쪽 포인터 이동 (탐욕적 선택)
if height[left] > height[right]:이면 오른쪽 선이 더 낮으므로right -= 1하여 오른쪽 포인터를 왼쪽으로 한 칸 이동시킵니다.else:(왼쪽 선이 낮거나 같으면)left += 1하여 왼쪽 포인터를 오른쪽으로 한 칸 이동시킵니다.- 이동 이유: 낮은 쪽을 움직여야만 더 높은 선을 만날 가능성이 생겨 면적이 커질 수 있습니다. 높은 쪽을 움직이면 너비만 줄어들고 높이는 변하지 않거나 더 낮아져서 면적이 절대 커질 수 없습니다.
4. 결과 반환
- 반복문이 종료되면(
left >= right) 모든 유효한 쌍을 확인한 것이므로 최종answer를 반환합니다.
⏱복잡도 분석
- 시간 복잡도: O(N)
- 두 포인터(
left,right)가 각각 배열의 양 끝에서 시작하여 중앙으로 이동하며 최대 한 번씩만 방문합니다. 전체 원소 수N에 비례하는 연산만 수행하므로 선형 시간입니다.
- 두 포인터(
- 공간 복잡도: O(1)
- 포인터 변수(
left,right)와 최대값 저장 변수(answer) 등 상수 개수의 변수만 사용하므로 입력 크기와 무관하게 일정한 메모리를 사용합니다.
- 포인터 변수(
핵심 포인트
- 투 포인터 전략: 양 끝에서 시작해 안쪽으로 좁혀오며 탐색 범위를 효율적으로 줄입니다.
- 낮은 쪽 포인터 이동 원칙: 현재 컨테이너의 높이는 낮은 쪽에 의해 결정되므로, 높은 쪽을 이동해봤자 높이는 높아지지 않습니다. 낮은 쪽을 이동해야 더 높은 선을 만나 면적이 커질 '가능성'이 생깁니다.
- 탐욕법의 정당성: 지역적으로 최적의 선택(낮은 쪽 이동)을 반복해도 전역 최적해(최대 면적)를 놓치지 않음을 수학적으로 보장할 수 있습니다. (높은 쪽을 고정하고 낮은 쪽만 움직여도, 버려지는 경우들은 이미 현재 면적보다 작거나 같음이 증명됨)
풀이 코드
class Solution:
def maxArea(self, height: List[int]) -> int:
answer = 0
left = 0
right = len(height) - 1
while left < right:
answer = max(answer,(right-left) * min(height[left],height[right]))
if height[left] > height[right]:
right -= 1
else:
left += 1
return answer
# 100000
댓글을 불러오는 중...