LeetCode_Sorting_912. Sort an Array 排序数组【快速排序,堆排序,归并排序】【java】【中等】

目录

一,题目描述

英文描述

中文描述

示例与说明

二,解题思路

快速排序

堆排序

归并排序

三,AC代码

Java

快速排序(随机哨兵)

堆排序

归并排序

四,解题过程

第一博

第二搏

第三搏


一,题目描述

英文描述

Given an array of integers nums, sort the array in ascending order.

中文描述

给你一个整数数组 nums,请你将该数组升序排列。

示例与说明

提示:

  1. 1 <= nums.length <= 50000
  2. -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。。。)

第二搏

堆排序,之前实现过类似的结构,这里比较轻松

第三搏

归并排序,细节细节!边界一定要搞清楚

Guess you like

Origin blog.csdn.net/qq_41528502/article/details/121454388