【算法题】荷兰国旗问题[力扣75题颜色分类] - JAVA
一、题目
二、文字解释
1.1 前言
本题是经典的「荷兰国旗问题」,由计算机科学家 Edsger W. Dijkstra 首先提出。如同图中所示的荷兰国旗,其由红、白、蓝三色水平排列组成。在算法领域,该问题可类比为将一个由特定的三种元素(可抽象对应红、白、蓝)组成的数组,通过特定算法实现元素的有序排列,使得相同元素相邻,且按照类似荷兰国旗颜色顺序的规则分布。
1.2 三指针算法实现
Java 代码实现
public class Solution {public void sortColors(int[] nums) {int low = 0;int mid = 0;int high = nums.length - 1;while (mid <= high) {if (nums[mid] == 0) {// 交换 nums[low] 和 nums[mid]int temp = nums[low];nums[low] = nums[mid];nums[mid] = temp;low++;mid++;} else if (nums[mid] == 1) {mid++;} else { // nums[mid] == 2// 交换 nums[mid] 和 nums[high]int temp = nums[mid];nums[mid] = nums[high];nums[high] = temp;high--;}}}
}
1.3 实现细节
- 三指针定义:
low
:指向 0 元素的右边界,区间[0, low-1]
中所有元素均为 0。mid
:当前遍历的指针,负责检查并处理每个元素。high
:指向 2 元素的左边界,区间[high+1, n-1]
中所有元素均为 2。
- 交换逻辑:
- 当
nums[mid] == 0
时:- 将
nums[low]
和nums[mid]
交换,然后low++
和mid++
。 - 这确保了所有 0 都被移动到数组左侧。
- 将
- 当
nums[mid] == 1
时:- 无需交换,直接
mid++
,因为 1 应该保持在中间位置。
- 无需交换,直接
- 当
nums[mid] == 2
时:- 将
nums[mid]
和nums[high]
交换,然后high--
。 - 注意此时
mid
不移动,因为交换后的元素需要重新检查。
- 将
- 当
- 循环条件:
mid <= high
,确保遍历到所有未处理的元素。- 当
mid > high
时,所有元素都已完成归类。
1.4 运行过程(以 [2,0,2,1,1,0]
为例)
- 初始状态:
low=0, mid=0, high=5
,数组:[2,0,2,1,1,0]
nums[mid]=2
:执行交换操作,nums[0]
与nums[5]
交换- 交换后数组:
[0,0,2,1,1,2]
,high=4
- 交换后数组:
nums[mid]=0
:执行交换操作,nums[0]
与nums[0]
交换(实际不变)- 数组保持:
[0,0,2,1,1,2]
,low=1, mid=1
- 数组保持:
nums[mid]=0
:执行交换操作,nums[1]
与nums[1]
交换(实际不变)- 数组保持:
[0,0,2,1,1,2]
,low=2, mid=2
- 数组保持:
nums[mid]=2
:执行交换操作,nums[2]
与nums[4]
交换- 交换后数组:
[0,0,1,1,2,2]
,high=3
- 交换后数组:
nums[mid]=1
:执行mid++
- 数组保持:
[0,0,1,1,2,2]
,mid=3
- 数组保持:
nums[mid]=1
:执行mid++
- 数组保持:
[0,0,1,1,2,2]
,mid=4
- 数组保持:
- 此时
mid=4 > high=3
,算法终止。
1.5 时间与空间复杂度
- 时间复杂度:O(n)
- 算法只需对数组进行一次遍历,每个元素最多被交换一次。
- 所有操作都是常数时间的简单比较和交换。
- 空间复杂度:O(1)
- 算法只使用了三个指针变量和一个临时变量进行交换。
- 属于原地排序算法,不需要额外的空间。