目录
一,题目描述
英文描述
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 int partation (int[] nums, int l, int r) {
int index = (int) Math.random() * (l - r) + l;// 生成[l, r)随机数
int pivot = nums[index];
index = l;
swap(nums, l, index);// 将哨兵与排序区间的首个元素进行交换
// 类似于插入排序的方法,将小于pivot的元素插入到已排好序的数组区间中
for (int i = l + 1; i <= r; i++) {
if (nums[i] < pivot) {
index++;
swap(nums, index, i);
}
}
swap(nums, l, index);
return index;
}
public void quickSort(int[] nums, int l, int r) {
if (l < r) {
int index = partation(nums, l, r);
quickSort(nums, l, index - 1);
quickSort(nums, index + 1, r);
}
}
public int[] sortArray(int[] nums) {
quickSort(nums, 0, nums.length - 1);// !!!否则nums[r]会越界
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 void merge(int[] nums, int l, int r) {
int[] array = new int[r - l + 1]; // 创建新的数组存放合并的结果
int mid = (l + r) / 2, i = l, j = mid + 1, index = 0;
while (i <= mid && j <= r) { // 合并 !!!注意边界
if (nums[i] < nums[j]) array[index++] = nums[i++];
else array[index++] = nums[j++];
}
while (i <= mid) array[index++] = nums[i++]; // 拷贝剩余的部分
while (j <= r) array[index++] = nums[j++]; // 拷贝剩余的部分 !!!注意边界
for (i = l, index = 0; i <= r; i++) { // !!!注意边界
nums[i] = array[index++];
}
}
public void mergeSort(int[] nums, int l, int r) {
int mid = (l + r) / 2;
if (l < mid) mergeSort(nums, l, mid);
if (mid + 1 < r) mergeSort(nums, mid + 1, r);
merge(nums, l, r);
}
public int[] sortArray(int[] nums) {
mergeSort(nums, 0, nums.length - 1); // !!!注意边界
return nums;
}
}
四,解题过程
第一博
设置随机哨兵的快速排序(细节调了将近50min。。。)
第二搏
堆排序,之前实现过类似的结构,这里比较轻松
第三搏
归并排序,细节细节!边界一定要搞清楚