一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情。
前言
力扣第164题 最大间距 如下所示:
给定一个无序的数组 nums,返回 数组在排序之后,相邻元素之间最大的差值 。如果数组元素个数小于 2,则返回 0 。
您必须编写一个在「线性时间」内运行并使用「线性额外空间」的算法。
示例 1:
输入: nums = [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9] , 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
一、思路
题目意思很简单:将无序数组排好序后,找到相邻元素最大的插值。我刚开始就是按照题目意思分为两个步骤实现了:
- 使用
Arrays.sort排序数组nums - 再遍历一遍数组求出相邻元素间最大的插值
代码和结果如下所示:
出乎意外的顺利,甚至还没有写测试用例就已经通过了。我就直奔题解去,一看官方原来是想使用 基数排序 或 桶排序,使得题目的时间复杂度为 O(N)。
在这里我们主要说明一下 基数排序 在此题的应用与流程
基数排序
先了解一下 基数排序 的基本思想:先找到数组中的最大值,然后个位、十位、百位的顺序来排序数组。此处以 nums = {30,61,93,100, 10} 作为例子
- 取出数组的个位,再按照个位的大小进行排序
排序后的结果
- 在个位数排序好的基础上,再对十位进行排序
排序好如下所示(虽然实际上无变化)
- 最后在个十位排序号的情况下,对百位进行排序
排序后
总的过程如下所示:
综上所述,基数排序 就是按照位数上的值从小到大的排序元素。
二、实现
实现代码
实现代码与思路中保持一致
public int maximumGap(int[] nums) {
int n = nums.length;
if (n < 2) {
return 0;
}
int cur = 1; // 当前对比的位
int[] temp = new int[n];
int maxVal = getMax(nums);
while (maxVal >= cur) {
// 0 ~ 9 计数
int[] count = new int[10];
for (int i = 0; i < n; i++) {
int digit = (nums[i] / cur) % 10;
count[digit]++;
}
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
for (int i = n - 1; i >= 0; i--) {
int digit = (nums[i] / cur) % 10;
// 当前位在元素对应的位置
int p = count[digit] - 1;
temp[p] = nums[i];
// 用过一次了,记得减去
count[digit]--;
}
System.arraycopy(temp, 0, nums, 0, n);
cur *= 10;
}
int ret = 0;
for (int i = 1; i < n; i++) {
ret = Math.max(ret, nums[i] - nums[i - 1]);
}
return ret;
}
public int getMax(int[] nums) {
int ret = nums[0];
for (int i = 1; i < nums.length; i++)
if (ret < nums[i]) ret = nums[i];
return ret;
}
测试代码
public static void main(String[] args) {
int[] nums = {30,61,93,100, 10};
new Number164().maximumGap(nums);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~