问题:
给定一个数组arr,和一个数num,请把小于num的数放在数组的 左边,等于num的数放在数组的中间,大于num的数放在数组的 右边。
要求额外空间复杂度O(1),时间复杂度O(N)
思路:
从第一个数开始逐个与num比较如果小于num则和小于num区域的下一个位置的数交换,小于num区域扩大1,也就是less加一,cur也加1向后移动一个,指向下一个需要比较的数,如果大于num则将cur指向的数和大于num区域的前一个位置的数交换,大于num区域扩大一,也就是more–,但是cur不动,将交换过来的数再与num进行比较,如果cur指向的数等于num,则位置不动,cue在指向下一个数
假设给定一组数据 5,3,5,2,8,7,4
数组的下标为0,1,2,3,4,5,6 num = 5
设置三个个变量一个为less,指向下标-1位置,另一个为more指向下标为7的位置,也就是arr.length位置,cur指向数组第一个数,也就是需要和num比较的数,0 - less为小于num的区域,more的右边为大于num区域,中间为等于num区域,对于第一个数5 = num,所以5的位置不动,cur向后移动一个,
数据:5,3,5,2,8,7,4
第二个数3 < num,所以3和5交换位置,小于num的区域扩大1,也就是less加一,此时小于num区域中有一个值为3,cur向后移动一个,
数据:3,5,5,2,8,7,4
第三个数5 = num,所以位置不动,cur向后移动一个,
数据:3,5,5,2,8,7,4
第四个数2 < num,所以2和小于num区域的下一个数交换位置,然后小于num区域扩大1,cur向后移动一个,此时小于num区域有两个数3和2,
数据:3,2,5,5,8,7,4
第5个数8 > num,让8和more位置前面位置4交换,more减一,也就是大于num的范围扩大1,此时大于num区域的值为8,
数据:3,2,5,5,4,7,8
此时cur位置不动仍然指向4,比较4和num的大小,因为4 < num,所以将4和小于num区域的下一个数5交换,cur向后移动一个,
数据:3,2,4,5,5,7,8
第六个数7 > num 所以让7和大于num区域前面位置的数交换,也就是和他本身进行交换,大于num区域扩大1,也就是more减一,因为more = num,也可以说因为此时已经划分好数据所属的区域,所以结束,
数据:3,2,4,5,5,7,8
代码实现:
public static void partition(int[] arr, int l, int r, int num) {
int less = l - 1;
int more = r + 1;
int cur = l;
while (cur < more) {
if (arr[cur] < num) {
swap(arr, ++less, cur++);
} else if (arr[cur] > num) {
swap(arr, --more, cur);
} else {
cur++;
}
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}