题意
给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度为O(1),时间复杂度为O(N)
代码如下:
package Sort_learning;
public class NetherlandsFlag {
public static int[] partition(int[] arr, int L, int R, int num) { //区间【L,R】是不确定的,即为待定区域,num为你想要用来分隔开待定区域的数
int less = L - 1; //less为待定区域最左边的前一个位置的数
int more = R + 1;//more为待定区域最右边的后一位置的数
int cur = L;//cur从待定区域最左边开始遍历待定区域
while(cur < more) { //循环结束条件:cur > more 此时,遍历完成
if(arr[cur] < num) { //当遍历位置上的数比给定的num小时,交换arr与小于区域的下一个位置的数,然后给小于区域扩大一个位置:用cur++(因为此时cur左边待定区域已确定与num相等)
swap(arr, ++less, cur++);
}else if(arr[cur] > num) { //当遍历位置上的数比给定的数大时,交换arr与大于区域的前一个位置上的数,然后cur不变(因为cur是从待定区域交换过来的,因此cur与num的大小关系还没确定,故cur位置还要与num比较)
swap(arr, --more, cur);
}else // =num时
cur++;
}return new int[] {less + 1, more - 1};
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
也就是说,给定一个待定区域,我们在遍历的过程中,
- 遇到等于的就往下走了。
- 遇到小于就往小于区域发货,把等于区域的拿过来(这说明不用确定cur位置上的数,因此此时不仅要left++,而且cur++),让小于区域扩一个位置,实际上就是小于区区域的推着等于区域往右跑。
- 遇到大于num区域的数时,只是要放到最右侧大于区域里面,但中间还有个待定区啊,这时拿出来的是待定区域的位置(这说明cur位置上的数仍然还是要确定的,因此此时right++,而cur不变)。
所以这就是为什么当你发现一个数小于num的时候,你把这个小于的数扔到小于区域里面,你换回来的一定是等于区域,要么就是你等于区域没有,小于区域自己跟自己交换,小于区域扩一个位置,不管是哪一种你都不用再重复考察cur位置上的数。
觉得写得不错的,点个关注,再点个赞,给你分享更多干货。
关注我的微信公众号,更多干货等你白票!