【题目】*912. 排序数组
给你一个整数数组 nums,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 50000
-50000 <= nums[i] <= 50000
【解题思路1】冒泡
虽然正确,但一般都会超时
class Solution {
public int[] sortArray(int[] nums) {
//冒泡排序
for(int i=0; i<nums.length; i++){
for(int j=i+1; j<nums.length; j++){
if(nums[i] > nums[j]){
swap(nums, i, j);
}
}
}
return nums;
}
public void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
【解题思路2】选择排序
每次选择 [ i, len-1 ] 区间的最小元素,用min保存下标,然后和 nums[i] 交换,使 [ 0, i ] 为有序区间。
class Solution {
public int[] sortArray(int[] nums) {
//选择排序
for(int i=0; i<nums.length; i++){
int min = i; //[i,len-1]最小元素的下标
for(int j=i+1; j<nums.length; j++){
if(nums[min] > nums[j]){
min = j;
}
}
swap(nums, i, min);
}
return nums;
}
public void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
【解题思路3】插入排序
class Solution {
public int[] sortArray(int[] nums) {
//插入排序
for(int i=1; i<nums.length; i++){
int temp = nums[i]; //暂存要插入的元素
int j = i;
while( j>0 && temp<nums[j-1]){
nums[j] = nums[j-1]; //如果要插入的元素小于当前元素,当前元素后移
j--;
}
nums[j] = temp; //找到要插入的位置,插入元素
}
return nums;
}
}
【解题思路4】快速排序
双指针
class Solution {
public int[] sortArray(int[] nums) {
int left = 0, right = nums.length - 1;
quickSearch(nums, left, right);
return nums;
}
// 快排
public void quickSearch(int[] nums, int left, int right) {
int part;
if(left < right) {
part = partition(nums, left, right);
quickSearch(nums, left, part - 1);
quickSearch(nums, part + 1, right);
}
}
// 划分,返回下标part,是的比nums[part]小的数都在j的左边,比nums[part]大的数都在j的右边
public int partition(int[] nums, int left, int right) {
int pivot = nums[left]; // 选择区间的最左端元素作为基准
while(left < right) {
while(left < right && nums[right] >= pivot) right--;
if(left < right) nums[left++] = nums[right];
while(left < right && nums[left] <= pivot) left++;
if(left < right) nums[right--] = nums[left];
}
nums[left] = pivot;
return left;
}
}
【解题思路5】归并排序
public class Solution {
public int[] sortArray(int[] nums) {
// 归并排序
int len = nums.length;
int[] temp = new int[len];
mergeSort(nums, 0, len - 1, temp);
return nums;
}
// 对数组 nums 的子区间 [left, right] 进行归并排序
// 数组 temp 用于合并两个有序数组的辅助数组,全局使用一份,避免多次创建和销毁
private void mergeSort(int[] nums, int left, int right, int[] temp) {
if(left == right) return;
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid, temp);
mergeSort(nums, mid + 1, right, temp);
// 如果数组的这个子区间本身有序,无需合并
if (nums[mid] <= nums[mid + 1]) {
return;
}
mergeOfTwoSortedArray(nums, left, mid, right, temp);
}
// 合并两个有序数组:先把值复制到临时数组,再合并回去
// [left, mid] 有序,[mid + 1, right] 有序
private void mergeOfTwoSortedArray(int[] nums, int left, int mid, int right, int[] temp) {
System.arraycopy(nums, left, temp, left, right + 1 - left);
int i = left;
int j = mid + 1;
for (int k = left; k <= right; k++) {
if (i == mid + 1) {
nums[k] = temp[j];
j++;
} else if (j == right + 1) {
nums[k] = temp[i];
i++;
} else if (temp[i] <= temp[j]) {
// 注意写成 < 就丢失了稳定性(相同元素原来靠前的排序以后依然靠前)
nums[k] = temp[i];
i++;
} else { // temp[i] > temp[j]
nums[k] = temp[j];
j++;
}
}
}
}
public class Solution {
private static final int INSERTION_SORT_THRESHOLD = 7;
public int[] sortArray(int[] nums) {
// 归并排序
int len = nums.length;
int[] temp = new int[len];
mergeSort(nums, 0, len - 1, temp);
return nums;
}
// 对数组 nums 的子区间 [left, right] 进行归并排序
// 数组 temp 用于合并两个有序数组的辅助数组,全局使用一份,避免多次创建和销毁
private void mergeSort(int[] nums, int left, int right, int[] temp) {
// 小区间使用插入排序
if (right - left <= INSERTION_SORT_THRESHOLD) {
insertionSort(nums, left, right);
return;
}
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid, temp);
mergeSort(nums, mid + 1, right, temp);
// 如果数组的这个子区间本身有序,无需合并
if (nums[mid] <= nums[mid + 1]) {
return;
}
mergeOfTwoSortedArray(nums, left, mid, right, temp);
}
// 对数组 arr 的子区间 [left, right] 使用插入排序
private void insertionSort(int[] arr, int left, int right) {
for (int i = left + 1; i <= right; i++) {
int temp = arr[i];
int j = i;
while (j > left && arr[j - 1] > temp) {
arr[j] = arr[j - 1];
j--;
}
arr[j] = temp;
}
}
// 合并两个有序数组:先把值复制到临时数组,再合并回去
// [left, mid] 有序,[mid + 1, right] 有序
private void mergeOfTwoSortedArray(int[] nums, int left, int mid, int right, int[] temp) {
System.arraycopy(nums, left, temp, left, right + 1 - left);
int i = left;
int j = mid + 1;
for (int k = left; k <= right; k++) {
if (i == mid + 1) {
nums[k] = temp[j];
j++;
} else if (j == right + 1) {
nums[k] = temp[i];
i++;
} else if (temp[i] <= temp[j]) {
// 注意写成 < 就丢失了稳定性(相同元素原来靠前的排序以后依然靠前)
nums[k] = temp[i];
i++;
} else { // temp[i] > temp[j]
nums[k] = temp[j];
j++;
}
}
}
}
【解题思路6】堆排序
public class Solution {
public int[] sortArray(int[] nums) {
int len = nums.length;
heapify(nums); // 将数组整理成堆
int i = len - 1;
while(i >= 1) { // 区间 [0, i] 堆有序
swap(nums, 0, i); // 把堆顶元素(当前最大)交换到数组末尾
i--;
siftDown(nums, 0, i); // 下标 0 位置下沉操作,使得区间 [0, i] 堆有序
}
return nums;
}
// 将数组整理成堆(堆有序)
private void heapify(int[] nums) {
int len = nums.length;
// 只需要从 i = (len - 1) / 2 这个位置开始逐层下移
for (int i = (len - 1) / 2; i >= 0; i--) {
siftDown(nums, i, len - 1);
}
}
// 当前下沉元素的下标, [0, end] 是 nums 的有效部分
private void siftDown(int[] nums, int k, int end) {
while (2 * k + 1 <= end) {
int j = 2 * k + 1;
if (j + 1 <= end && nums[j + 1] > nums[j]) {
j++;
}
if (nums[j] > nums[k]) {
swap(nums, j, k);
} else {
break;
}
k = j;
}
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}