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.
[Thoughts]
Suppose there are N elements and they range from A to B.
Then the maximum gap will be no smaller than ceiling[(B - A) / (N - 1)]
Let the length of a bucket to be len = ceiling[(B - A) / (N - 1)], then we will have at most num = (B - A) / len + 1 of bucket
for any number K in the array, we can easily find out which bucket it belongs by calculating loc = (K - A) / len and therefore maintain the maximum and minimum elements in each bucket.
Since the maximum difference between elements in the same buckets will be at most len - 1, so the final answer will not be taken from two elements in the same buckets.
For each non-empty buckets p, find the next non-empty buckets q, then q.min - p.max could be the potential answer to the question. Return the maximum of all those values.
public int maximumGap(int[] num) { if (num == null || num.length < 2) return 0; // get the max and min value of the array int min = num[0]; int max = num[0]; for (int val:num) { min = Math.min(min, val); max = Math.max(max, val); } // the minimum possibale gap, ceiling of the integer division int gap = (int)Math.ceil((double)(max - min)/(num.length - 1)); int[] bucketsMIN = new int[num.length - 1]; // store the min value in that bucket int[] bucketsMAX = new int[num.length - 1]; // store the max value in that bucket Arrays.fill(bucketsMIN, Integer.MAX_VALUE); Arrays.fill(bucketsMAX, Integer.MIN_VALUE); // put numbers into buckets for (int val:num) { if (val == min || val == max) continue; int idx = (val - min) / gap; // index of the right position in the buckets bucketsMIN[idx] = Math.min(val, bucketsMIN[idx]); bucketsMAX[idx] = Math.max(val, bucketsMAX[idx]); } // scan the buckets for the max gap int maxGap = Integer.MIN_VALUE; int previous = min; for (int i = 0; i < num.length - 1; i++) { if (bucketsMIN[i] == Integer.MAX_VALUE && bucketsMAX[i] == Integer.MIN_VALUE) // empty bucket continue; // min value minus the previous value is the current gap maxGap = Math.max(maxGap, bucketsMIN[i] - previous); // update previous bucket value previous = bucketsMAX[i]; } maxGap = Math.max(maxGap, max - previous); // updata the final max value gap return maxGap; }
以上Java代码写的不太好,代码重构成如下:
public int maximumGap(int[] num) { if (num == null || num.length < 2) return 0; // get the max and min value of the array int min = num[0], max = num[0]; for (int val:num) { min = Math.min(min, val); max = Math.max(max, val); } // the minimum possibale gap, ceiling of the integer division int gap = (int)Math.ceil((double)(max - min)/(num.length - 1)); int bucketLen = (max - min)/gap + 1; // != num.length - 1 int[] bucketsMIN = new int[bucketLen]; // store the min value in that bucket int[] bucketsMAX = new int[bucketLen]; // store the max value in that bucket Arrays.fill(bucketsMIN, Integer.MAX_VALUE); Arrays.fill(bucketsMAX, Integer.MIN_VALUE); // put numbers into buckets for (int val:num) { int idx = (val - min) / gap; // index of the right position in the buckets bucketsMIN[idx] = Math.min(val, bucketsMIN[idx]); bucketsMAX[idx] = Math.max(val, bucketsMAX[idx]); } // scan the buckets for the max gap int maxGap = 0, prev = min; for (int i = 0; i < bucketLen; i++) { // empty bucket if (bucketsMAX[i] == Integer.MIN_VALUE) continue; // min value minus the previous value is the current gap maxGap = Math.max(maxGap, bucketsMIN[i] - prev); // update previous bucket value prev = bucketsMAX[i]; } return maxGap; }
C++版本:
int maximumGap(vector<int> &num) { if (num.size() < 2) return 0; int minval = INT_MAX, maxval = INT_MIN; for (auto v : num) { minval = min(v, minval); maxval = max(v, maxval); } double gap = ((double) maxval - minval) / (num.size() - 1); vector<pair<int, int> > buckets(num.size() - 1, {-1, -1}); for (auto v : num) { if (v == minval || v == maxval) continue; int idx = (v - minval) / gap; if (buckets[idx].first == -1) buckets[idx].first = v; else buckets[idx].first = min(buckets[idx].first, v); buckets[idx].second = max(buckets[idx].second, v); } int maxdiff = 0, lastval = minval; for (auto it : buckets) { if (it.first == -1) continue; maxdiff = max(maxdiff, it.first - lastval); lastval = it.second; } maxdiff = max(maxdiff, maxval - lastval); return maxdiff; }
Note that the size of each bucket is (max - min) / (n - 1), which is less than or equal to the maximum gap (since we have n - 1 gaps for n numbers, and the total length is max - min). Therefore, the maximum gap can only be the gap between the maximum element in the i-th bucket and the minimum element in the (i+1)-th bucket.
An example is, [4, 1, 8, 3, 10, 7] min is 1 and max is 10, the gap is 9/5 = 1.8 so the five buckets are [1, 2.8), is empty (since 1 is minimum and has been ignored) [2.8, 4.6), min is 3 and max is 4 [4.6, 6.4), is empty [6.4, 8.2), min is 7 and max is 8 [8.2, 10), is empty Then we scan these buckets again. If we ignore the empty buckets, it makes sense to compare the following gaps: 3 (min of the second bucket) - 1 (minimum in total) 7 (min of the fourth bucket) - 4 (max of the second bucket) 10 (maximum in total) - 8 (max of the fourth bucket) and we found that the maximum gap is 3.
这题本质上是桶排序,首先扫描一遍数组(长度为N)得到最小值和最大值,那么可以得出max gap的下限:
max_gap >= ceil ( (MAX - MIN) / N )
这个下限可以作为bucket的长度,然后可以很容易求出bucket的个数:
num_buckets = (MAX - MIN) / bucket_len + 1
然后重新扫描数组,每个元素K所属bucket的id为(K - MIN) / bucket_len。
扫描的过程中记录每个bucket包含元素的最大值和最小值。
然后对桶进行一次扫描,求出相邻两个非空桶的最大值与最小值之差。这个差的最大值,就是结果。
int maximumGap(const vector<int> &num) { if(num.size() < 2) return 0; int min = INT_MAX, max = INT_MIN; for(auto i : num) { min = std::min(min, i); max = std::max(max, i); } auto ceil_div = [](int x,int y){return (x % y) ? x / y + 1 : x / y;}; int max_dif = ceil_div(max-min, (int)num.size()-1); vector<vector<int>> buckets(1 + (max-min)/max_dif, {INT_MAX,INT_MIN}); for(auto i : num) { int bucketid = (i - min) / max_dif; buckets[bucketid][0] = std::min(buckets[bucketid][0], i); buckets[bucketid][1] = std::max(buckets[bucketid][1], i); } int ret = 0, last_nonempty = 0; while(buckets[last_nonempty][1] < 0) last_nonempty++; for(int i = last_nonempty + 1; i < buckets.size(); ++i) { if(buckets[i][1] < 0) continue; ret = std::max(ret, buckets[i][0] - buckets[last_nonempty][1]); last_nonempty = i; } return ret; }
Reference:
http://www.fgdsb.com/2015/01/03/maximum-gap/
http://fenghaolw.blogspot.co.uk/2014/12/maximum-gap.html
http://www.programcreek.com/2014/03/leetcode-maximum-gap-java/
http://cgm.cs.mcgill.ca/~godfried/teaching/dm-reading-assignments/Maximum-Gap-Problem.pdf
相关推荐
javascript js_leetcode题解之164-maximum-gap.js
java java_leetcode-maximum-depth-of-binary-tree
java java_leetcode题解之Maximum Gap.java
《LeetCode---C++实现》是一本专注于C++编程语言解决LeetCode在线判题平台上的算法问题的书籍。LeetCode是程序员广泛使用的平台,它提供了大量的编程题目来提升编程技能和算法理解,尤其对于准备面试的程序员来说,...
1. leetCode-126-Word-LadderII.md:这涉及到第126题,词梯问题,通常是一个字符串转换问题,目标是找到两个单词之间的最短转换序列,每次只改变一个字母。 2. leetcode-224-Basic-Calculator.md:这是第224题,基础...
leetcode-cli-plugins leetcode-cli 的第 3 方插件。 什么是 如何使用 如何使用 插件 名称 描述 增强的命令 按公司或标签过滤问题 list 不要在同一台计算机上使 Chrome 的会话过期 login 不要在同一台计算机上使 ...
哈希表 - LeetCode刷题 - 题解
假设数组长度为N,准备N+1个桶,把max放在N+1号桶,nums中在[min,max)范围上的数放在1~N号桶中,对于1 ~ N号桶的每一个桶来说,负责的区间
LeetCode 101 - A Grinding Guide.pdf
leetcode-cli 一个享受 leetcode 的高效 cli 工具! 非常感谢 leetcode.com,一个非常棒的网站! ⦙⦙⦙⦙⦙⦙⦙⦙ 一个很打问题的方法。 问题来缓解离线思考。 编码前的源代码。 居住和与 leetcode.com。 下载你...
leetcode-cli 注意:这个存储库是为了临时使用而分叉的。 注意:从 webbrowser 复制 cookie 并使用leetcode user -c可以临时修复不能。 一个享受 leetcode 的高效 cli 工具! 非常感谢 leetcode.com,一个非常棒的...
这个压缩包“leetcode--python”显然包含了与LeetCode相关的Python解题代码,可能是一个开源项目,用于存储用户或社区成员解决LeetCode问题的Python实现。 **LeetCode概述** LeetCode提供了一系列的算法和数据结构...
leetcode26 algo 算法与数据结构,练习代码 语言:java 8 开发工具:vscode,安装插件Java Extension Pack vscode有智能提示,可调试,有重构支持,满足代码练习要求,相比IDEA更轻量级,普通笔记本即可流畅运行。 ...
leetcode 答案Leetcode---算法 我对 Leetcode 算法问题的回答
leetcode 接口 该项目可帮助您使用首选的 IDE 或带有命令行界面 (CLI) 的编辑器来执行 leetcode。 入门 先决条件 Windows 10、MacOS、Linux Chrome版 >=90.0.4430 安装 # Prepare your virtual environment conda ...
js js_leetcode题解之53-maximum-subarray.js
javascript js_leetcode题解之152-maximum-product-subarray.js
leetcode-machine-swift :SOS_button: 请帮助在Sources/leetcode-machine-swift/leetcode.swift设置所有 leetcode 问题。 :SOS_button: 在 swift 编码时有 xcode 总是好的。 利用自动补全、类型检查...功能可以帮助...
c语言入门 C语言_leetcode题解之53-maximum-subarray.c
leetcode-cli 一个享受 leetcode 的高效 cli 工具! 非常感谢 leetcode.com,一个非常棒的网站! ⦙⦙⦙⦙⦙⦙⦙⦙ 一个很打问题的方法。 问题来缓解离线思考。 编码前的源代码。 居住和与 leetcode.com。 下载你...