题目:

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.

链接: http://leetcode.com/problems/maximum-gap/

题解:

给定未排序数组,求两个相邻元素间的差的最大值。想了一会不确定,于是去看了一眼Discuss的标题,果然是用Radix Sort。其实一开始看到题目里面所有数字都可以被表示为32-bit signed integer时,就应该要想到才对。 估计做法就是用Radix Sort,排序完毕后再扫描一边数组。正好加深一下对Radix Sort的理解和书写。要好好研究一下Key-indexed Counting,LSD,MSD和Bucket Sort。这道题用Bucket Sort的话就是把每个元素放入一个bucket中,然后计算非空bucket间的最大距离,原理都差不多。一刷用了LSD,代码大都参考Sedgewick大神,二刷的话要试一试MSD以及bucket sort。注意的一点是LSD处理最高8位bit时, 0 ~ 127为正, 128 ~ 255为负,所以要特殊处理一下accumulated count数组。做完这题以后就发现上过算法2真好...

LSD Radix Sort, Time Complexity - O(n),  Space Complexity - O(n)

public class Solution {
public int maximumGap(int[] nums) {
if(nums == null || nums.length < 2)
return 0;
lsdSort(nums);
int maxDiff = Integer.MIN_VALUE;
for(int i = 1; i < nums.length; i++)
maxDiff = Math.max(nums[i] - nums[i - 1], maxDiff); //may overflow
return maxDiff;
} private void lsdSort(int[] nums) {
int len = nums.length;
int[] aux = new int[nums.length];
int totalBits = 32;
int bitsPerByte = 8;
int window = totalBits / bitsPerByte;
int R = 1 << bitsPerByte; // R is radix
int mask = R - 1; // for(int d = 0; d < window; d++) { // for each window compared
int[] count = new int[R + 1]; for(int i = 0; i < len; i++) { // count least significant 8 bits of each num in nums
int c = (nums[i] >> (d * bitsPerByte)) & mask; // use mask to get least significant 8 bits
count[c + 1]++;
} for(int i = 0; i < R; i++) // count accumulated position for each nums
count[i + 1] += count[i]; if(d == window - 1) { // for most significant 8 bits, 0 ~ 127 is pos, 128 ~ 255 is neg, so 128 ~ 255 goes first
int shift1 = count[R] - count[R / 2];
int shift2 = count[R / 2];
for(int i = 0; i < R / 2; i++)
count[i] += shift1;
for(int i = R / 2; i < R; i++)
count[i] -= shift2;
} for(int i = 0; i < len; i++) { // move data
int c = (nums[i] >> (d * bitsPerByte)) & mask;
aux[count[c]++] = nums[i];
} for(int i = 0; i < len; i++) // copy back
nums[i] = aux[i];
} }
}

二刷:

依然使用了LSD radix sort,代码大都来自塞神的index counting。

  1. 我们把32位的数字分为4个batch,每个batch有8个digit,使用LSD的话我们是从最低一级的batch开始计算。这里我们要使用一个mask = 255,也就是二进制的11111111来找到每个batch。也要做一个auxiliary array - aux[] 用来保存临时结果
  2. 对于每个batch,我们都要做一次index counting sort,一共四次,从最低8位开始,到最高8位
    1. 每次确定了batch之后我们就可以创建buckets数组。这里buckets数组 count = new int[R + 1] , 这里的 + 1很重要
    2. 我们第一次遍历数组,根据最低8位,统计所有数字出现的频率,然后放入相应的bucket里,这里有个小trick很关键,我们虽然将低8位映射到从[0 - 255]这样的256个bucket里,但写入count数组的时候,我们有意把count[0]留下,把数字的count写到 [1 - 256]的bucket中。这样做的好处,要在后面才能看到,就是从经过aggregation后的count数组,将排序后的数字填入到aux[]数组中时。
    3. 然后,我们对统计好的数字和频率进行aggregation,利用count数组求一个accumulated count。经历过这一步以后,我们的count[i]代表的意思就是,有多少个数字应该被放在 i 之前的buckets里。
    4. 接下来,我们根据aggregation的结果,我们把这些数字填到aux[]里
    5. 最后把aux[]中的数字拷贝回nums中,继续计算下一个batch。 因为LSD的操作是stable的,所以我们进行完全部4个batch以后就会得到最终结果
  3. 这里要注意的一点是,32位数字最高8位digit的这个batch和其他三个不同。在这8位里0 ~ 127为正数,而128 ~ 255为负数。所以在这个batch里,计算完aggregation数组后,我们要做一个很巧妙的shift操作
    1. 先求出shift1 = count[R] - count[R / 2], 也就是在输入的nums[]中有多少个数字为负
    2. 再求出shift2 = count[R / 2], 输入的nums[]中有多少个正数
    3. 对于[0 - 127]的这些数字,他们都应该排在负数前面,所以我们对每一个count[i] 增加 shift1
    4. 对于[128 - 255]的这些数字,他们都应该排在正数后面,所以我们对每一个count[i] 减少 shift2
    5. 之后再根据新的count[]数组,把数字放入aux[]数组中,再拷贝回原数组nums[]里。

Java:

Time Complexity - O(n),  Space Complexity - O(n)

public class Solution {
public int maximumGap(int[] nums) { // LSD
LSDradix(nums);
int maxGap = 0;
for (int i = 1; i < nums.length; i++) maxGap = Math.max(maxGap, nums[i] - nums[i - 1]);
return maxGap;
} private void LSDradix(int[] nums) {
if (nums == null || nums.length == 0) return;
int batchSize = 8;
int batchNum = 32 / batchSize;
int R = 1 << batchSize; // radix, each bucket we consider only [0 - 255] , 256 numbers
int mask = R - 1; // 11111111, each batch 8 digits
int len = nums.length;
int[] aux = new int[len]; for (int d = 0; d < batchNum; d++) {
int[] count = new int[R + 1];
for (int num : nums) {
int idx = (num >> (d * batchSize)) & mask;
count[idx + 1]++; // index counting
}
for (int k = 1; k < count.length; k++) count[k] += count[k - 1]; // aggregation, find out the buckets boundaries
if (d == batchNum - 1) { // for first 8 digits 01111111 is max, 11111111 is min, we shift nums
int shift1 = count[R] - count[R / 2];
int shift2 = count[R / 2];
for (int k = 0; k < R / 2; k++) count[k] += shift1;
for (int k = R / 2; k < R; k++) count[k] -= shift2;
}
for (int num : nums) {
int idx = (num >> (d * batchSize)) & mask;
aux[count[idx]++] = num; // we place each num in each buckets, from the start slot of the bucket
}
for (int k = 0; k < len; k++) nums[k] = aux[k];
}
}
}

Reference:

https://www.cs.princeton.edu/~rs/AlgsDS07/18RadixSort.pdf

https://leetcode.com/discuss/18499/bucket-sort-java-solution-with-explanation-o-time-and-space

https://leetcode.com/discuss/18487/i-solved-it-using-radix-sort

https://leetcode.com/discuss/19951/use-average-gap-to-achieve-o-n-run-time-java-solution

https://leetcode.com/discuss/34289/pigeon-hole-principle

https://leetcode.com/discuss/53636/radix-sort-solution-in-java-with-explanation

164. Maximum Gap的更多相关文章

  1. LeetCode 164. Maximum Gap[翻译]

    164. Maximum Gap 164. 最大间隔 Given an unsorted array, find the maximum difference between the successi ...

  2. leetcode[164] Maximum Gap

    梅西刚梅开二度,我也记一题. 在一个没排序的数组里,找出排序后的相邻数字的最大差值. 要求用线性时间和空间. 如果用nlgn的话,直接排序然后判断就可以了.so easy class Solution ...

  3. 【LeetCode】164. Maximum Gap (2 solutions)

    Maximum Gap Given an unsorted array, find the maximum difference between the successive elements in ...

  4. 【刷题-LeetCode】164 Maximum Gap

    Maximum Gap Given an unsorted array, find the maximum difference between the successive elements in ...

  5. ✡ leetcode 164. Maximum Gap 寻找最大相邻数字差 --------- java

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  6. 164. Maximum Gap (Array; sort)

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  7. [LeetCode] 164. Maximum Gap 求最大间距

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  8. Java for LeetCode 164 Maximum Gap

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  9. 164. Maximum Gap *HARD* -- 无序数组找出排序后连续元素的最大间隔

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

随机推荐

  1. WebService简单介绍

    什么是Web Services 一直没有一个明确的答案,最近听了一个大牛讲WebService,顿时明了了,作个记录免得以后忘了. N年之前,各公司都在炒作SOA,不过现在已经没人再提了,现在都改叫W ...

  2. ###STL学习--函数对象

    点击查看Evernote原文. #@author: gr #@date: 2014-08-13 #@email: forgerui@gmail.com 在stl中,函数对象被大量地使用,用以提高代码的 ...

  3. TortoiseSVN本地代码版本控制设置步骤。

    1.下载安装TortoiseSVN客户端. 2.在某个盘创建空的文件夹作为项目代码的版本库.在空的文件夹内部右键鼠标TortoiseSVN->Create repository here 3.在 ...

  4. 九度OJ 1528 最长回文子串 -- Manacher算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1528 题目描述: 回文串就是一个正读和反读都一样的字符串,比如"level"或者"n ...

  5. Class类文件的结构

    Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件中,中间没有任何分隔符.Class文件的结构只有两种数据类型:无符号数和表.无符号数以u1.u2. ...

  6. VS2010 EntityFramework Database First

    本文演练介绍如何使用实体框架进行 Database First 开发.通过 Database First,可以从现有数据库对模型进行反向工程处理.模型存储在一个 EDMX 文件(扩展名为 .edmx) ...

  7. 在Mac OS X中使用VIM开发STM32(3)

    本文原创于http://www.cnblogs.com/humaoxiao,非法转载者请自重!       在上一篇文章中,我们安装了ctags插件,ctags能对我们的源代码文件中的元素建立索引表, ...

  8. thinkphp autoload 命名空间自定义 namespace

    使用thinkPHP过程中,一些自定义的类库和第三方类库需要找一个合适的位置放置,放到系统默认的org文件夹感觉不太好,破坏了thinkPHP的原生目录. 就看了一下官方手册,可以在模块或者应用的配置 ...

  9. 进程,线程(thread)

    每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段, 它可以在程序里独立执行.也可把它理解为代码运行 ...

  10. DataGridView默认不选中

    NurseGridList.CurrentCell = null;                NurseGridList.ClearSelection();                Nurs ...