本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
题目
Acceptance:27% Difficulty: Hard
Give 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. Credis: Special thanks to @porker2008 for adding this problem and creating all test cases.
Tags Sort
题目理解
首先,拿到题目的时候,对maximum different between the successive elements有一定的误解。这里的 successive是连续的的意思,也就是说,题目的意思是寻找 当array排序后的连续两个数字之间的最大Gap
题目分析
于是题目变得很简单了(如果粗暴地想的话),排序,然后遍历nums[i] - nums[i - 1],不断替换掉maxGap的值(现在仍然记得某次阿里电面时让我求二叉树最长深度我竟然把每条路径的深度记下来,然后再去找max,真是糟糕的代码)。 然而题目提示
Try to solve it in linear time/space.
这就懵了。难道有不用排序就可以直接解决的思路吗?想了半天并没有什么好的思路,所以,还是先提交一份AC再说。
题解
-
先说swap “只是因为在人群中多看了你一眼,再也没能忘掉你的容颜” 不知道什么时候见过一句完成交换,于是心心念地找,终于找到了。
a ^= b ^= a ^= b;
当快排写完之后提交,然后WA,input [1, 1000], output -1, expect 999。 这个时候就想到之前也出现过这一的情况,特别是当交换的是两个int而非引用或者指针的时候。以为是当两个值相等的时候,通过^操作会时结果为0,然而事实真的如此吗?答案是否定的。可以写一个简单的测试代码来测试当输入为相同值时,swap的输出并非是0, 0。 问题出现在当交换的是同一个数字的时候。 对,当a ^= a时,a = 0了,后面无论怎样抑或,交换后的a永远都是0。而当 a = 6, b = 6时。第一次抑或, a=0, b = 6,第二次抑或 b = 6, a = 0, 第三次抑或 a = 6, b = 6。 那么问题来了:是不是需要在swap中添加判断,只有当 a != b 时,才进行 a ^= b ^= a ^= b 的操作呢?如果这样添加一个if结构,那么会造成swap的效率降低吗?降低到以致于不如申请一个temp来作最基本的交换吗?STL里的swap又是怎样写的呢?
-
说说QuickSort 现在写QuickSort仍然习惯于把最后一个字符当作参照,然后来遍历比较每个值。仍不习惯于使用随机快排。 当然,随机快排只是为了避免出现最差的情况。
AC Code:
void swap (int &a, int &b)
{
if (a != b)
a ^= b ^= a ^= b;
}
void quickSort (vector<int>& nums, int left, int right)
{
if (right <= left)
return;
int slowI = left;
for (int index = left; index < right; index++)
{
if (nums[index] < nums[right])
{
if (slowI < index)
{
swap(nums[slowI], nums[index]);
}
slowI++;
}
}
swap(nums[slowI], nums[right]);
quickSort(nums, left, slowI - 1);
quickSort(nums, slowI + 1, right);
}
int maximumGap(vector<int>& nums)
{
if (nums.size() <= 1)
return 0;
quickSort(nums, 0, nums.size() - 1);
int maxG = nums[1] - nums[0];
for (int i = 2; i < nums.size(); i++)
{
if (nums[i] - nums[i - 1] > maxG)
maxG = nums[i] - nums[i-1];
}
return maxG;
}
- 看看大家的代码 提交后的质量只beats了22%左右的答案。于是在百思不得更好的算法之后去看了discussion。发现那些O(n)的算法大多使用了counting sort,bucket, radix等等。 哇哦。。。打开了新世界的大门,桶排序、基数、计数排序。这三个排序之前在准备面试的时候看到过名字,但是一直没整理(因为感觉不会考到这里)。 再看看大家的代码,以下列代码为例:
int maximumGap(vector<int>& nums)
{
const int size_num = nums.size();
if (size_num < 2) return 0;
int maxV = *max_element(nums.begin(), nums.end());
int minV = *min_element(nums.begin(), nums.end());
if (maxV == minV) return 0;
double range = (maxV - minV) / double(size_num - 1);
vector<int> max_b(size_num, INT_MIN), min_b(size_num, INT_MAX);
for (int i = 0; i < size_num; i++) {
int index = (nums[i] - minV) / range;
max_b[index] = max(max_b[index], nums[i]);
min_b[index] = min(min_b[index], nums[i]);
}
int max_g = (int)range, start = max_b[0];
for (int i = 1; i < size_num; i++) {
if (min_b[i] == INT_MAX) continue;
max_g = max(max_g, min_b[i] - start);
start = max_b[i];
}
return max_g;
}
(⊙o⊙)…。这都些什么鬼。经过简单百度,看到,其中大多是含于 < algorithm.h >中的STL。于是,之前说的用过STL,但是只用了vector,和map的一小部分。。。。简直弱爆了。