最近在看左神的算法课,理解之后在此将代码记录下来
问题一:
给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)
问题二(荷兰国旗问题):
给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。
问题二代码:
/**
* 划分
* @param arr 待划分数组
* @param l 数组左边界
* @param r 数组右边界
* @param target 目标数
* @return 与目标数相等的在划分后数组中的范围
*/
private static int[] partition(int[] arr, int l, int r, int target) {
int less = l - 1;//小于目标数在数组中的边界,默认不存在
int more = r + 1;//大于目标数在数组中的边界,默认不存在
int cur = l;//数组当前位置索引
while (cur < more) {
if (arr[cur] < target) {//当前数 < 目标数
//把小于目标数的边界的下一个数与当前数交换//++less代表less+1之后,
//cur++代表cur+1之前
swap(arr, ++less, cur++);
} else if (arr[cur] > target) {//当前数 > 目标数
//把大于目标数的边界的前一个数与当前数交换,
// 交换完之后不确定当前数是否小于目标数,当前位置不变,进行下一轮
swap(arr, --more, cur);
} else {//当前数 = 目标数
cur++;
}
}
return new int[]{less + 1, more - 1};
}
/**
* 交换数组中i和j的位置
*
* @param arr 数组
* @param i i
* @param j j
*/
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
经典快排
将数组的最后一个数X作为基准,划分成左边均为小于等于X,右边均大于X的数组,然后保留X的位置,继续将X左边的数组和右边的数组进行同样的划分
注:这样每次只能排好一个数,并且如果X前面的值全部大于或小于X,这个时候时间复杂度为O(N^2)
代码
/**
* 经典快排
* @param arr 待排的数组
* @param l 数组左边界
* @param r 数组右边界
*/
private static void classicQuickSort(int[] arr, int l, int r) {
if (l < r) {
int partition = partition(arr, l, r);//把l->r组成的数组进行划分[<=x , x , >x],x为数组最后一个数
classicQuickSort(arr, l, partition - 1);//划分 <=x 部分
classicQuickSort(arr, partition + 1, r);//划分 >x 部分
}
}
/**
* 划分
*
* @param arr 待划分数组
* @param l 数组左边界
* @param r 数组右边界
* @return 待排数组最后一个数排完的位置
*/
private static int partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;
while (l < more) {
if (arr[l] <= arr[r]) {
swap(arr, l++, ++less);
} else {
swap(arr, l, --more);
}
}
swap(arr, more, r);
return more;
}
/**
* 交换数组中i和j的位置
*
* @param arr 数组
* @param i i
* @param j j
*/
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
随机快排
在数组中随机选择一个数,将其与数组最后一个数交换,然后把最后一个数X作为基准,划分为左边小于X,右边大于X的数组,然后保留等于X的部分,继续划分小于X和大于X的部分
注:这样每次可以将整个X排完整,并且最坏和最好的时间复杂度都是随机的
代码
/**
* 快速排序
*
* @param arr 待排的数组
* @param l 数组左边界
* @param r 数组右边界
*/
private static void quickSort(int[] arr, int l, int r) {
if (l < r) {
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);//将数组中任意位置中的数与最后一个数交换
int[] partition = partition(arr, l, r);//把l->r组成的数组进行划分[<x , x, >x],x为数组最后一个数
quickSort(arr, l, partition[0] - 1);//划分 <x 部分
quickSort(arr, partition[1] + 1, r);//划分 >x 部分
}
}
/**
* 划分
*
* @param arr 待划分数组
* @param l 数组左边界
* @param r 数组右边界
* @return 等于x部分在数组中的范围
*/
private static int[] partition(int[] arr, int l, int r) {
int less = l - 1;//指向<x的最大索引位
int more = r;//指向>x的最大索引位
while (l < more) {//当前位置小于>x的最大索引位
if (arr[l] < arr[r]) {//当前位置值<最后一个数
swap(arr, l++, ++less);//当前值与<x的索引位下一个值交换,当前位置+1
} else if (arr[l] > arr[r]) {//当前位置值>最后一个数
swap(arr, l, --more);//当前值与>x的索引位前一个值交换
} else {
l++;
}
}
//此时more指向的是>=最后一个数的边界
swap(arr, more++, r);//将more位置的数和最后一个数交换,more+1代表more为>x数组的左边界
return new int[]{less + 1, more - 1};
}
/**
* 交换数组中i和j的位置
*
* @param arr 数组
* @param i i
* @param j j
*/
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}