目录
一,题目描述
英文描述
Given an array of integers
nums
, sort the array in ascending order.
中文描述
给你一个整数数组
nums
,请你将该数组升序排列。
示例与说明
提示:
1 <= nums.length <= 50000
-50000 <= nums[i] <= 50000
二,解题思路
快速排序
普通的快速排序(默认将哨兵设置为第一个或者最后一个元素)会超时,这里采用官方题解中的方法,设置随机哨兵pivot。
int index = (int) Math.random() * (l - r) + l;// 生成[l, r)之间的随机数
int pivot = nums[index];
堆排序
将数组中的元素一个个添加入堆中,执行siftUp操作;
将堆顶元素与堆中末尾元素调换,边界减一,自上而下调整堆;
当堆中元素为空,数组完成排序。
归并排序
经典的递归思想。
将数组拆成两部分,这两部分均调用MergeSort方法,可以看作已经排好序,接下来只需要进行合并有序数组的操作。
这里的空间复杂度为O(N),因为合并有序数组时,额外创建了一块区域,用来存放合并的结果,最后将结果拷贝至原数组中。(若直接在原数组中进行合并操作,过程较为复杂)
三,AC代码
Java
快速排序(随机哨兵)
class Solution {
public void swap (int[] nums, int a, int b) {
int tem = nums[a];
nums[a] = nums[b];
nums[b] = tem;
}
public static void quickSort(int[] array, int left, int right) {
if (right - left < 2) return;
int index = partation(array, left, right);
quickSort(array, left, index);
quickSort(array, index, right);
}
public static int partation(int[] array, int left, int right) {
int index = (int) (Math.random() * (right - left) + left);// !!!获得随机哨兵位置
System.out.println("#" + index);
int pivot = array[index];// 记录哨兵值
swap(array, left, index);// 将哨兵与待排序区间首个元素交换
index = left;
for(int i = left + 1; i < right; i++) {
if (array[i] < pivot) {
swap(array, ++index, i);
}
}
swap(array, left, index);// 将哨兵与已分区区间的最后一个元素交换
return index;
}
public int[] sortArray(int[] nums) {
quickSort(nums, 0, nums.length);//
return nums;
}
}
堆排序
class Solution {
public void swap (int[] nums, int a, int b) {
int tem = nums[a];
nums[a] = nums[b];
nums[b] = tem;
}
public void siftUp (int[] nums, int index) {
int fatherIndex = (index - 1) / 2;
while (fatherIndex >= 0 && nums[index] > nums[fatherIndex]) {
swap(nums, fatherIndex, index);
index = fatherIndex;
fatherIndex = (index - 1) / 2;
}
}
public void siftDown (int[] nums, int index, int border) {
int childIndex = index * 2 + 1;
while (childIndex < border) {
if (childIndex + 1 < border && nums[childIndex + 1] > nums[childIndex]) {
childIndex++;
}
if (nums[index] > nums[childIndex]) break;// 该节点大于任意子节点
swap(nums, index, childIndex);
index = childIndex;
childIndex = index * 2 + 1;
}
}
public void heapSort(int[] nums) {
for (int i = 0; i < nums.length; i++) {
siftUp(nums, i);// 构建大根堆
}
for (int i = nums.length - 1; i > 0; i--) {
swap(nums, 0, i);// 将堆顶元素调整到数组末尾
siftDown(nums, 0, i);// 自上向下调整堆
}
}
public int[] sortArray(int[] nums) {
heapSort(nums);
return nums;
}
}
归并排序
class Solution {
public static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
for (int i = 0, j = 0, index = 0; index < left.length + right.length; index++) {
if (i >= left.length) {
result[index] = right[j++];
} else if (j >= right.length) {
result[index] = left[i++];
} else if (left[i] < right[j]) {
result[index] = left[i++];
} else {
result[index] = right[j++];
}
}
return result;
}
public static int[] mergeSort(int[] array, int l, int r) {
if (r - l < 2) return array;
int mid = (l + r) / 2;
int[] left = Arrays.copyOfRange(array, l, mid);
int[] right = Arrays.copyOfRange(array, mid, r);
return merge(mergeSort(left, 0, left.length), mergeSort(right, 0, right.length));
}
public int[] sortArray(int[] nums) {
mergeSort(nums, 0, nums.length); // !!!注意边界
return nums;
}
}
四,解题过程
第一博
设置随机哨兵的快速排序(细节调了将近50min。。。)
第二搏
堆排序,之前实现过类似的结构,这里比较轻松
第三搏
归并排序,细节细节!边界一定要搞清楚