引子
我在北京的一个现任职京东零售的一个朋友,最近投了阿里巴巴的简历,面试官一面就考察了一道算法题,我与他交流了一下,发现一道荷兰国旗的问题。
假如有一个数组,里面的元素由红、白、蓝三个颜色组成,请你写出一个算法,使数组的元素按照红、白、蓝顺序分布。
至于为什么叫荷兰国旗,你对比一下,荷兰国旗的三色分布就知道了。
遗憾的是,我这个朋友没有答出来,于是和阿里失之交臂。
思路
见到这种题,首先第一反应就是是不是能在一次遍历搞定,就是时间复杂度在O(n)解决。
先把这个问题简单化一点,如果这个数组只有两个颜色,红色和蓝色,那么你会不会。
我们可以定义左右两个指针,分别放到数组的两边。
然后,左指针向右移动,直到遇到蓝色的元素,右指针向左移动,直到遇到红色的元素。
然后交换两个元素。
左右指针继续移动,直到左指针的索引小于右指针,完成。
如果这个问题清楚了,举一反三,三色的问题,我们可以用三个指针来搞定。
首先,我们定义三个指针start、mid、end,分别在数组的索引-1、0和arr.length处。
判断mid节点的颜色,这时候有三种情况
- 如果mid节点是白色的,mid节点向左移,不做任何操作。
- 如果mid节点是红色,与start++节点置换,并向左移。
- 如果mid节点是蓝色,与end–节点置换,并向左移。
整体置换的步骤如下,如果不理解建议多看两遍动画。
代码
这里面0代表红色,1代表白色,2代表红色
private static void helper(int[] arr) {
int start = -1;
int end = arr.length;
int mid = 0;
while (mid < end) {
if (arr[mid] == 1) {
mid++;
continue;
}
if (arr[mid] == 0) {
arr[mid++] = arr[++start];
arr[start] = 0;
continue;
}
if (arr[mid] == 2) {
arr[mid] = arr[--end];
arr[end] = 2;
}
}
}