前言

在比较排序的算法中,快速排序的性能最佳,时间复杂度是O(N*logN).因此,在使用比较排序时,时间复杂度的下限就是O(N*logN)。而桶排序的时间复杂度是O(N+C),因为它的实现并不是基于比较实现的,而是基于映射函数实现的。

桶排序

桶排序工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。

桶排序利用函数的映射关系,减少了几乎所有的比较工作。实际上,桶排序的f(k)值的计算,其作用就相当于快排中划分,已经把大量数据分割成了基本有序的数据块(桶)。然后只需要对桶中的少量数据做先进的比较排序即可。

时间复杂度和空间复杂度分析

    对于N个待排数据,M个桶,平均每个桶[N/M]个数据的桶排序平均时间复杂度为:
               O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)
    当N=M时,即极限情况下每个桶只有一个数据时。桶排序的最好效率能够达到O(N)。
 
    空间负载度:O(N+M)
 
下面以leetcode164. Maximum Gap为例具体讲解桶排序的实现
   题目要求:
   Given an unsorted array, find the maximum difference between the successive elements in its sorted form.

Try to solve it in linear time/space.  //题目要求我们使用线性的时间

Return 0 if the array contains less than 2 elements.

You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.

解题思路:

首先对数组进行桶排序,然后找出最大的gap。

首先明确,最大的gap肯定是后桶的最小值减去前桶的最大值,注意此处说的桶均为有效桶,即不包括空桶。

因此无需进行桶内排序,仅需记录每个有效桶的最大值和最小值即可。

为何最大的gap肯定是后桶的最小值减去前桶的最大值?

假设有数组x[1...n],其中最大的元素为max,最小元素为min,将左闭右开的实数区间[min,max)划分为n-1个等长的子区间(桶),每个子区间也是左闭右开的,我们用len来表示每个子区间的长度。除去max和min,剩下的n-2个数,每个数都属于其中一个桶。对于同一个桶的两个数,因为桶是左闭右开的,所以他们的距离肯定是小于len的。然后,关键的一点是,n-2个数放进n-1个桶,由抽屉原理可以知道,肯定有一个桶是空的,所以,距离最远的相邻的两个数,肯定是属于两个不同的桶。于是,我们可以把每个桶都扫描一次,相邻最远的两个数,必定其中一个是某个桶里的最大值,另一个是另一个桶里的最小值。

代码:

public class Solution {
public int maximumGap(int[] num) {
if(num == null || num.length<2){
return 0;
}
int maxval = Integer.MIN_VALUE;
int minval = Integer.MAX_VALUE;
//求解数组最值
for(int i=0; i<num.length; i++){
if(num[i]>maxval) maxval = num[i];
if(num[i]<minval) minval = num[i];
} //数组内的元素值相同
if(minval==maxval){
return 0;
} //数组仅有两个元素
if(num.length==2){
return maxval-minval;
} int len = (int)Math.ceil((double)(maxval-minval)/(num.length-1)); //求解桶间差值,向上取整
int n = (maxval-minval)/len; int maxBuk[] = new int[n+1];
int minBuk[] = new int[n+1]; Arrays.fill(maxBuk,Integer.MIN_VALUE);
Arrays.fill(minBuk,Integer.MAX_VALUE); //桶映射
for(int val:num){
int temp = (val-minval)/len;
maxBuk[temp] = Math.max(val,maxBuk[temp]);
minBuk[temp] = Math.min(val,minBuk[temp]);
} //求解最大gap,最大差值位于后桶的min-前桶的max
int gap = 0;
int pre = maxBuk[0];
for(int i=1; i<=n; i++){
if(maxBuk[i]==Integer.MIN_VALUE && minBuk[i]==Integer.MAX_VALUE){ //忽略空桶
continue;
}
gap = Math.max(gap,minBuk[i]-pre);
pre = maxBuk[i];
} return gap; }
}

线性时间的排序算法--桶排序(以leetcode164. Maximum Gap为例讲解)的更多相关文章

  1. 使用 js 实现十大排序算法: 桶排序

    使用 js 实现十大排序算法: 桶排序 桶排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  2. Java排序算法——桶排序

    文字部分为转载:http://hxraid.iteye.com/blog/647759 对N个关键字进行桶排序的时间复杂度分为两个部分: (1) 循环计算每个关键字的桶映射函数,这个时间复杂度是O(N ...

  3. 排序算法-桶排序(Java)

    package com.rao.sort; import java.util.*; /** * @author Srao * @className BucketSort * @date 2019/12 ...

  4. 十大经典排序算法+sort排序

    本文转自:十大经典排序算法,其中有动图+代码详解,本文简单介绍+个人理解. 排序算法 经典的算法问题,也是面试过程中经常被问到的问题.排序算法简单分类如下: 这些排序算法的时间复杂度等参数如下: 其中 ...

  5. 计数排序和桶排序(Java实现)

    目录 比较和非比较的区别 计数排序 计数排序适用数据范围 过程分析 桶排序 网络流传桶排序算法勘误 桶排序适用数据范围 过程分析 比较和非比较的区别 常见的快速排序.归并排序.堆排序.冒泡排序等属于比 ...

  6. 计数排序与桶排序python实现

    计数排序与桶排序python实现 计数排序 计数排序原理: 找到给定序列的最小值与最大值 创建一个长度为最大值-最小值+1的数组,初始化都为0 然后遍历原序列,并为数组中索引为当前值-最小值的值+1 ...

  7. 【JS面试向】选择排序、桶排序、冒泡排序和快速排序简介

    新年伊始,又到了金三银四的时候了.面对前端越来越多的算法面试题,我简单的整理了一下几种比较常见的数组排序方式,分别介绍其基本原理和优劣势.(ps:才疏学浅,希望大家可以在issues下面指出问题) 选 ...

  8. 经典排序算法 - 高速排序Quick sort

    经典排序算法 - 高速排序Quick sort 原理,通过一趟扫描将要排序的数据切割成独立的两部分,当中一部分的全部数据都比另外一部分的全部数据都要小,然后再按此方法对这两部分数据分别进行高速排序,整 ...

  9. 排序算法--希尔排序(Shell Sort)_C#程序实现

    排序算法--希尔排序(Shell Sort)_C#程序实现 排序(Sort)是计算机程序设计中的一种重要操作,也是日常生活中经常遇到的问题.例如,字典中的单词是以字母的顺序排列,否则,使用起来非常困难 ...

随机推荐

  1. static的本质

    通过反编译发现,static的本质是abstract sealed.因此,无法继承System.Math类,因为它是static的.

  2. js中操作数组的一些方法【转】

    增 push   在数组的末尾添加一个或多个元素,并返回新的长度.  array.push(1,2,3.........) unshift  在数组的开头添加一个或多个元素,并返回新的长度. arra ...

  3. 详解CALayer 和 UIView的区别和联系

    详解CALayer 和 UIView的区别和联系   前言 前面发了一篇iOS 面试的文章,在说到 UIView 和 CALayer 的区别和联系的时候,被喵神指出没有切中要点,所以这里就 CALay ...

  4. OpenCV 3.1 StereoBM 获取正确视差Dispariy

    OpenCV更新到3.0版本后,Stereo模块变化的挺多的,首先去掉了StereoBMState和StereoSGBMState这两个专门控制BM和SGBM算法参数的类,而且StereoBM不能直接 ...

  5. PCL Show Point Cloud 显示点云

    在使用PCL库的时候,经常需要显示点云,可以用下面这段代码: #include <pcl/visualization/cloud_viewer.h> pcl::PointCloud< ...

  6. BigDecimal 转换类型

    使用BigDecimal类来进行计算的时候,主要分为以下步骤: 1.用float或者double变量构建BigDecimal对象. 2.通过调用BigDecimal的加,减,乘,除等相应的方法进行算术 ...

  7. AsyncTask的使用

    简单的AnsyTask的使用demo 1.定义一个模拟网络操作的类 package com.example.administrator.myapplication; /** * Created by ...

  8. 对JS原型的一些理解

    一.首先给出一道经典的原型题目: var F = function(){}; Object.prototype.a = function(){}; Function.prototype.b = fun ...

  9. js 检查是否为手机端

    let isMobile = function(){ let userAgentInfo = navigator.userAgent; let Agents = new Array("And ...

  10. JAVA面向对象程序设计——实验报告