164. 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.
链接: 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。
- 我们把32位的数字分为4个batch,每个batch有8个digit,使用LSD的话我们是从最低一级的batch开始计算。这里我们要使用一个mask = 255,也就是二进制的11111111来找到每个batch。也要做一个auxiliary array - aux[] 用来保存临时结果
- 对于每个batch,我们都要做一次index counting sort,一共四次,从最低8位开始,到最高8位
- 每次确定了batch之后我们就可以创建buckets数组。这里buckets数组 count = new int[R + 1] , 这里的 + 1很重要
- 我们第一次遍历数组,根据最低8位,统计所有数字出现的频率,然后放入相应的bucket里,这里有个小trick很关键,我们虽然将低8位映射到从[0 - 255]这样的256个bucket里,但写入count数组的时候,我们有意把count[0]留下,把数字的count写到 [1 - 256]的bucket中。这样做的好处,要在后面才能看到,就是从经过aggregation后的count数组,将排序后的数字填入到aux[]数组中时。
- 然后,我们对统计好的数字和频率进行aggregation,利用count数组求一个accumulated count。经历过这一步以后,我们的count[i]代表的意思就是,有多少个数字应该被放在 i 之前的buckets里。
- 接下来,我们根据aggregation的结果,我们把这些数字填到aux[]里
- 最后把aux[]中的数字拷贝回nums中,继续计算下一个batch。 因为LSD的操作是stable的,所以我们进行完全部4个batch以后就会得到最终结果
- 这里要注意的一点是,32位数字最高8位digit的这个batch和其他三个不同。在这8位里0 ~ 127为正数,而128 ~ 255为负数。所以在这个batch里,计算完aggregation数组后,我们要做一个很巧妙的shift操作
- 先求出shift1 = count[R] - count[R / 2], 也就是在输入的nums[]中有多少个数字为负
- 再求出shift2 = count[R / 2], 输入的nums[]中有多少个正数
- 对于[0 - 127]的这些数字,他们都应该排在负数前面,所以我们对每一个count[i] 增加 shift1
- 对于[128 - 255]的这些数字,他们都应该排在正数后面,所以我们对每一个count[i] 减少 shift2
- 之后再根据新的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的更多相关文章
- LeetCode 164. Maximum Gap[翻译]
164. Maximum Gap 164. 最大间隔 Given an unsorted array, find the maximum difference between the successi ...
- leetcode[164] Maximum Gap
梅西刚梅开二度,我也记一题. 在一个没排序的数组里,找出排序后的相邻数字的最大差值. 要求用线性时间和空间. 如果用nlgn的话,直接排序然后判断就可以了.so easy class Solution ...
- 【LeetCode】164. Maximum Gap (2 solutions)
Maximum Gap Given an unsorted array, find the maximum difference between the successive elements in ...
- 【刷题-LeetCode】164 Maximum Gap
Maximum Gap Given an unsorted array, find the maximum difference between the successive elements in ...
- ✡ leetcode 164. Maximum Gap 寻找最大相邻数字差 --------- java
Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...
- 164. Maximum Gap (Array; sort)
Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...
- [LeetCode] 164. Maximum Gap 求最大间距
Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...
- Java for LeetCode 164 Maximum Gap
Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...
- 164. Maximum Gap *HARD* -- 无序数组找出排序后连续元素的最大间隔
Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...
随机推荐
- 让progressDialog不会触摸消失
项目中的进度菊花圈,在网络请求的时候会出现,但是手一触碰到屏幕,就会消失,看了下自己的设置,给对话框设置了该方法: progressDialog.setCancelable(true); 点击Prog ...
- Android四大组件之BroadcastReceiver
什么是BroadcastReceiver? BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播. 在Android系统中,广播体现在方方面面, ...
- linux添加用户、用户组、权限
# useradd –d /usr/sam -m sam 此命令创建了一个用户sam,其中-d和-m选项用来为登录名sam产生一个主目录/usr/sam(/usr为默认的用户主目录所在的父目录). 假 ...
- Android Metro风格的Launcher开发系列第二篇
前言: 各位小伙伴们请原谅我隔了这么久才开始写这一系列的第二篇博客,没办法忙新产品发布,好了废话不说了,先回顾一下:在我的上一篇博客http://www.cnblogs.com/2010wuhao/p ...
- Podfile 文件的编写
# Uncomment this line to define a global platform for your projectplatform :ios, '9.0' target 'Cocoa ...
- nodejs js模块加载
本文地址:http://www.cnblogs.com/jasonxuli/p/4381747.html nodejs的非核心模块(core module)加载主要使用的就是module.js. 项目 ...
- Custom Action : dynamic link library
工具:VS2010, Installshield 2008 实现功能: 创建一个C++ win32 DLL的工程,MSI 工程需要调用这个DLL,并将Basic MSI工程中的两个参数,传递给DLL, ...
- Nginx+keepalived实现负载均衡
Nginx的优点是: 1.工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名.目录结构,它的正则规则比HAProxy更为强大和灵活,这也是它目前广泛流行的主要原因之一,Nginx ...
- 排序算法FIVE:插入排序InsertSort
/** *插入排序思路:O(n^2) * 最外层一个循环,从第二个数到最后一个,变量为i * 每个数存储在key变量中 * 变量j,是左边已经排好序的数组的上限 * 判断key与前面每一个数比较 1, ...
- 一套帮助你理解C语言的测试题(转)
前言 原文链接:http://www.nowamagic.net/librarys/veda/detail/775 内容 在这个网站(http://stevenkobes.com/ctest.html ...