class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
red, white, blue = 0, 0, len(nums)
while white < blue:
if nums[white] < 1:
nums[red], nums[white] = nums[white], nums[red]
white += 1
red += 1
elif nums[white] > 1:
blue -= 1
nums[white], nums[blue] = nums[blue], nums[white]
else:
white += 1
이 문제는 다익스트라가 1976년에 제안한 '네덜란드 국기 문제(Dutch National Flag Problem)' 문제와 동일한 문제로, 퀵 정렬의 개선 아이디어와도 관련이 깊다.
네덜란드 국기의 색깔인 붉은색(위), 흰색(중앙), 파란색(아래)을 세 부분으로 대입해 분할하는 것이다.
<네덜란드 국기 문제의 수도코드>
three-way-partition(A: array of values, mid: value):
i <- 0
j <- 0
k <- size of A
while j < k:
if A[j] < mid:
swap A[i] and A[j]
i <- i + 1
j <- j + 1
else if A[j] > mid:
k <- k - 1
swap A[j] and A[k]
else:
j <- j + 1
이 수도코드는 i
, k
를 양쪽 포인터로 두고 j
가 이동하면서 mid
값을 기준으로 스왑하는 형태로 구현되어 있다.
수도코드 알고리즘의 변수명을 각각의 국기 색깔에 대입해 i
를 red
로 k
를 blue
로, j
는 white
로 하고, 중앙 값을 지칭하는 mid
는 원래의 값인 1
로 변경해 본다.
예제의 입력값에서 보든 각각의 실제 값은 [0,1,2]로 정한다.
이 정렬을 도식화하면 다음과 같다.
이 그림에서 시작 시점에는 red
, white
모두 0에서 시작하고 blue
는 배열의 길이가 된다.
배열은 0부터 시작하므로 처음에 blue
는 배열 인덱스의 바깥에 있다.
비교가 시작되면서 1
을 기준으로 작은 값은 왼쪽으로, 큰 값은 오른쪽으로 스왑된다.
red
와 blue
는 각각 오른쪽과 왼쪽으로 이동하면서 간격이 점점 좁아지는 형태가 된다.투 포인터 풀이와 유사하며, 그 사이에 포인터가 하나 더 존재한다고 볼 수 있다.
white
와 blue
사이는 계속 비교가 진행된다.
마지막으로 비교가 완료될 때 red
는 1
보다 작은 인덱스인 +1
지점, blue
는 1
보다 큰 인덱스의 처음의 가리키게 되며
white
와 blue
가 겹쳐지면서 비교가 완료된다.
mid
변수를 값 1
로 직접 대입해서 풀이했다는 차이만 있을 뿐, 알고리즘은 완전히 동일하다.