『Leetcode』十大排序的应用

十大排序应用

十种排序方法sort以及各方法的复杂度分析

1. 冒泡排序

75. 颜色分类
283. 移动零

75. 颜色分类-思路

不好的处理方法:冒泡排序 ,时间复杂度为O(n^2)。
在这里插入图片描述
注意本题,只有三色球,即只有0,1,2三个数进行从小到大不减排序。归为经典的荷兰国旗问题,题目本质是要我们将数分成三段——双指针处理。(思想:F3)


循环中的++ii++结果一样的原因,但是性能不一样:

在大量数据的时候++i的性能要比i++的性能好原因: i++由于是在使用当前值之后再+1,所以需要一个临时的变量来转存。 而++i则是在直接+1,省去了对内存的操作的环节,相对而言能够提高性能。


283. 移动零-思路

注意前提:题目给的数组是含有零元素,且非零元素有序。
D1:两次遍历。第一次记录非零元素个数n,顺便排序;第二次将[n+1,len-1]赋值为0;

class Solution {
    public void moveZeroes(int[] nums) {
        if(nums==null) return;
        int len=nums.length;
        int i,j=0;
        //第一次遍历,给非零元素排序
        for(i=0;i<len;i++){
            if(nums[i]!=0){
                nums[j++]=nums[i];
            }
        }
        //第二次遍历,给非零元素之后的空位赋值为0
        for(i=j;i<len;i++){
            nums[i]=0;
        }
    }
}

在这里插入图片描述

D2:一次遍历。设两个指针同时从下标为0开始,非零元素则i,j交换,0元素则不进行任何操作。

class Solution {
    public void moveZeroes(int[] nums) {
        int n=nums.length;
        int i=0,j=0;
       
       if(nums==null) {
			return;
		}

        for(i=0;i<n;i++){
            if(nums[i]!=0){
                swap(nums,i,j++);
            }
        }
    }
    public void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}

在这里插入图片描述

2. 选择排序

LC 912. 排序数组

3. 插入排序

LC 912. 排序数组
LC 147. 对链表进行插入排序

4. 希尔排序

LC 912. 排序数组
LC 506. 相对名次

5. 归并排序

LC 剑指Offer 51. 数组中的逆序对
LC 面试题10.01. 合并排序的数组

6. 快速排序

思想:

  • 选择基准值(一般将数组第一个数作为基准值);
  • 双指针分别从左右两边移动,左边寻找比基准值大的数,右边找比基准值小的数。 两者交换数值;
  • 左指针==右指针时,将 基准值 与 指针所指位置 交换数值;
  • 随后,将数组分成两部分,分别重复上述操作即可。

代码实现:

请添加图片描述
算法分析:
请添加图片描述

指针移动问题

注意:先移动右指针
原因:如果先移动左指针就导致每次交换基准值时,都将会把比基准值大的数移动到了左边数组的第一个数,导致左边数组的值不完全小于右边数组的值,递归快排都将出错。

例题:

LC 912. 排序数组
LC 169.多数元素

LC 215. 数组中的第K个最大元素

方案一:经典快排后得到一个从小到大递增数组,返回下标为len-k+1的数即为所求。
结果:超时。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int n=nums.length;
        QuickSort(nums,0,n-1);
        return nums[n-k];
    }
    public void QuickSort(int[] nums,int low,int high){
        if(low<high){
            int piont=Partition(nums,low,high);
            QuickSort(nums,0,piont-1);
            QuickSort(nums,piont+1,high);
        }
        
    }
    public int Partition(int[] nums,int low,int high){
        //找快排中的轴心
        int piont=nums[low];
        while(low<high){
            while(low<high && nums[high]>=piont){
                high--;
            }
            nums[low]=nums[high];
            while(low<high && nums[low]<=piont){
                low++;
            }
            nums[high]=nums[low];
        }
        nums[low]=piont;
        return low;

    }

 
}

方案二:快排改进。由此可以发现每次经过「划分」操作后,我们一定可以确定一个元素的最终位置,即 xxx 的最终位置为 q,并且保证 a[l⋯q−1] 中的每个元素小于等于 a[q],且 a[q] 小于等于 a[q+1⋯r]中的每个元素。所以只要某次划分的 q为倒数第 k 个下标的时候,我们就已经找到了答案。 我们只关心这一点,至于 a[l⋯q−1] 和 a[q+1⋯r]是否是有序的,我们不关心。(思想

我们知道快速排序的性能和「划分」出的子数组的长度密切相关。直观地理解如果每次规模为 n 的问题我们都划分成 1 和 n−1,每次递归的时候又向 n−1的集合中递归,这种情况是最坏的,时间代价是 O(n ^ 2)。

我们可以引入随机化 来加速这个过程,它的时间代价的期望是 O(n)。

顺序统计量:期望为线性时间的选择算法

(暂时没弄明白)
选择算法指的是:在一个长度为n的数列中找到第i 小或第i 大的元素。

一般选择问题看起来要比找最小值这样的简单问题更难。但令人惊奇的是,这两个问题的渐近运行时间却是相同的:Θ ( n )。参考文章将介绍一种解决选择问题的分治算法。
参考文章:https://blog.csdn.net/hy592070616/article/details/120470336
方案三:堆排序。

在这里插入图片描述

class HeapSort{
	public static int[] HeapSortMain(int[] arr) {
    	int len = arr.length;
    	buildMaxHeap(arr, len); //  将数组整理成堆
    	
		for (int i = len - 1; i > 0; i--) {
            swap(arr, 0, i);  // 把堆顶元素(当前最大)交换到数组末尾
            len--;			 // 逐步减少堆有序的部分
            heapify(arr, 0, len);		// 下标 0 位置下沉操作,使得区间 [0, i] 堆有序
        }
        
        return arr;
	}
	
	//将数组整理成堆(堆有序)
	private void buildMaxHeap(int[] arr, int len) {
        for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
            heapify(arr, i, len);
        }
    }
    
    // i为当前下沉元素的下标
	private void heapify(int[] arr, int i, int len) {
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        int largest = i;

        if (left < len && arr[left] > arr[largest]) {
            largest = left;
        }

        if (right < len && arr[right] > arr[largest]) {
            largest = right;
        }

        if (largest != i) {
            swap(arr, i, largest);
            heapify(arr, largest, len);
        }
    }
    
	private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

7. 堆排序

LC 215. 数组中的第K个最大元素

LC 剑指Offer 40.最小的k个数

4种解法秒杀TopK(快排/堆/二叉搜索树/计数排序)

8. 计数排序

LC 912. 排序数组
LC 1122. 数组的相对排序

9. 桶排序

LC 908.最小差值I
LC 164.最大间距

10. 基数排序

LC 164.最大间距
LC 561.数组拆分I

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值