题目:

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)

  1. public class Solution {
  2. public int maximumGap(int[] nums) {
  3. if(nums == null || nums.length < 2)
  4. return 0;
  5. lsdSort(nums);
  6. int maxDiff = Integer.MIN_VALUE;
  7. for(int i = 1; i < nums.length; i++)
  8. maxDiff = Math.max(nums[i] - nums[i - 1], maxDiff); //may overflow
  9. return maxDiff;
  10. }
  11.  
  12. private void lsdSort(int[] nums) {
  13. int len = nums.length;
  14. int[] aux = new int[nums.length];
  15. int totalBits = 32;
  16. int bitsPerByte = 8;
  17. int window = totalBits / bitsPerByte;
  18. int R = 1 << bitsPerByte; // R is radix
  19. int mask = R - 1; //
  20.  
  21. for(int d = 0; d < window; d++) { // for each window compared
  22. int[] count = new int[R + 1];
  23.  
  24. for(int i = 0; i < len; i++) { // count least significant 8 bits of each num in nums
  25. int c = (nums[i] >> (d * bitsPerByte)) & mask; // use mask to get least significant 8 bits
  26. count[c + 1]++;
  27. }
  28.  
  29. for(int i = 0; i < R; i++) // count accumulated position for each nums
  30. count[i + 1] += count[i];
  31.  
  32. if(d == window - 1) { // for most significant 8 bits, 0 ~ 127 is pos, 128 ~ 255 is neg, so 128 ~ 255 goes first
  33. int shift1 = count[R] - count[R / 2];
  34. int shift2 = count[R / 2];
  35. for(int i = 0; i < R / 2; i++)
  36. count[i] += shift1;
  37. for(int i = R / 2; i < R; i++)
  38. count[i] -= shift2;
  39. }
  40.  
  41. for(int i = 0; i < len; i++) { // move data
  42. int c = (nums[i] >> (d * bitsPerByte)) & mask;
  43. aux[count[c]++] = nums[i];
  44. }
  45.  
  46. for(int i = 0; i < len; i++) // copy back
  47. nums[i] = aux[i];
  48. }
  49.  
  50. }
  51. }

二刷:

依然使用了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)

  1. public class Solution {
  2. public int maximumGap(int[] nums) { // LSD
  3. LSDradix(nums);
  4. int maxGap = 0;
  5. for (int i = 1; i < nums.length; i++) maxGap = Math.max(maxGap, nums[i] - nums[i - 1]);
  6. return maxGap;
  7. }
  8.  
  9. private void LSDradix(int[] nums) {
  10. if (nums == null || nums.length == 0) return;
  11. int batchSize = 8;
  12. int batchNum = 32 / batchSize;
  13. int R = 1 << batchSize; // radix, each bucket we consider only [0 - 255] , 256 numbers
  14. int mask = R - 1; // 11111111, each batch 8 digits
  15. int len = nums.length;
  16. int[] aux = new int[len];
  17.  
  18. for (int d = 0; d < batchNum; d++) {
  19. int[] count = new int[R + 1];
  20. for (int num : nums) {
  21. int idx = (num >> (d * batchSize)) & mask;
  22. count[idx + 1]++; // index counting
  23. }
  24. for (int k = 1; k < count.length; k++) count[k] += count[k - 1]; // aggregation, find out the buckets boundaries
  25. if (d == batchNum - 1) { // for first 8 digits 01111111 is max, 11111111 is min, we shift nums
  26. int shift1 = count[R] - count[R / 2];
  27. int shift2 = count[R / 2];
  28. for (int k = 0; k < R / 2; k++) count[k] += shift1;
  29. for (int k = R / 2; k < R; k++) count[k] -= shift2;
  30. }
  31. for (int num : nums) {
  32. int idx = (num >> (d * batchSize)) & mask;
  33. aux[count[idx]++] = num; // we place each num in each buckets, from the start slot of the bucket
  34. }
  35. for (int k = 0; k < len; k++) nums[k] = aux[k];
  36. }
  37. }
  38. }

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. Sqlserver 快照

    最近,开发系统使用SqlServer2008 R2,但是由于系统数据压力的增加,准备增加一个和正式数据库同步的库,用来供接口和报表使用,所以开始对SqlServer里面的一些技术开始研究,第一篇先来研 ...

  2. 对象创建型模式------Builder(生成器或建造者模式)(2)

    链接转自:http://blog.csdn.net/wuzhekai1985/article/details/6667467 主要思想是:首先有个指挥家思想者将大体的设计思路设计出来,然后寻找一部分工 ...

  3. iOS真机调试之我见

     入职20多天,以前一直以为iOS真机调试是多么复杂的事情,但在公司大牛的帮助下:终于理清头绪,由于公司证书已申请,文章中免不了旁征博引. 1.首先,得有苹果开发者账号,如果在公司,公司会提供:不在公 ...

  4. GCD学习之dispatch_barrier_async

    iOS常见的多线程开发方式有NSThread.NSOPeration和GCD,抽象程度依次提高,GCD是最抽象的,使用起来最简单,但相对来说功能有限,比如不能cancel任务,这也算是一点遗憾吧. 今 ...

  5. js事件冒泡和事件委托

    js事件冒泡 js所谓的事件冒泡就是子级元素的某个事件被触发,它的上级元素的该事件也被递归执行 html: <ul class="clearfix" data-type=&q ...

  6. ASP.Net MVC 生成安全验证码

    ---------html <td>验证码:</td>            <td>                <img src="/Logi ...

  7. HTML5课程大纲/学习路线

    HTML5课程大纲/学习路线 这是什么? 这个一个HTML技术路线的课程大纲/学习大纲. 你能用它做什么? 如果你是找工作的人, 利用本大纲, 你可以学习HTML5语言, 做一个HTML前端工程师, ...

  8. 实现一个div在浏览器水平居中

    第一种方法: div { margin: 0 auto; width: 960px; } 第二种方法(兼容IE): body { text-align: center; } div { margin: ...

  9. centos 端口开放及关闭

    之前有讲过公司新买的服务器使用的是CentOS 5.5,部署好Tomcat之后却发现输入114.80.*.*:8080(即ip:8080)却无法显示Tomcat默认的首页.因为以前部署在Win Ser ...

  10. B树及2-3树的python实现

    B树(或称B-树)是一种适用于外查找的树,它是一种平衡的多叉树. 阶为M的B树具有下列结构特征: 1.树的根或者是一片树叶,或者其儿子数在2和M之间. 2.除根节点外的所有非树叶节点儿子数在┌M/2┐ ...