算法题分享 | 最大间距

26 阅读3分钟

iPad壁纸🗓文字篇19_5_舞木子_来自小红书网页版.jpg

题目

给定一个无序的数组 nums,返回 数组在排序之后,相邻元素之间最大的差值 。如果数组元素个数小于 2,则返回 0 。

您必须编写一个在「线性时间」内运行并使用「线性额外空间」的算法。

示例 1:

输入: nums = [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9]  ,  其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。

示例 2:

输入: nums = [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。

提示:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 109

题解

解题思路

可以先对数组进行排序,排好序后就很容易可以得到最大的差值了。但是题目中明确说明了要实现一个「线性时间」内运行并使用「线性额外空间」的算法,所以使用快速排序、归并排序等常见排序均不能满足,时间复杂度为 O(n logn),都是非线性的。需要使用基数排序,基数排序 可以在的 O(n) 的时间复杂度内完成排序。

基数排序 主要思想:

将元素按照数字的每一位进行多轮的分配和收集,从最低位开始,按当前位的值进行排序,直到完成最高位处理后,即可得到一个有序的数组,该算法是一个稳定的排序算法,主要适用于整数和字符串的排序(需统一位数)。

基数排序 的主要步骤:

从最低位开始,基于各个位对元素进行以下操作,直到完成最高一位的处理,即完成了数组的排序。这里假设正在处理的为第 i 位。

  1. 统计在第 i 位上各取值对应的元素数

  2. 基于上一步的结果得到在第 i 位上各取值对应元素在本轮排序结果数组中的下标范围

  3. 将数组元素逐一按照上一步得到的下标分布进行调整位置,当然这不是在原数组中操作,需要借助一个临时数组 buf 存放结果。

  4. 把 buf 数组拷贝回原数组

代码

class Solution {
    public int maximumGap(int[] nums) {
        int n = nums.length;
        if (n < 2) {
            return 0;
        }

        int exp = 1;
        int max = Arrays.stream(nums).max().getAsInt();

        int[] buf = new int[n];

        while(max >= exp) {

            int[] counts = new int[10]; 

            // 统计所有元素在 exp 对应位上值的分布
            for (int i = 0; i < n; i++) {
                int x =  (nums[i] / exp) % 10;
                counts[x]++; 
            }

            // 统计本轮排序在当前位各取值对应的元素下标情况
            // 例如 counts[0] = 2, counts[1] = 5,说明当前位为 0 的元素将排在 0 ~ 1,为 1 的排在 2 ~ 4
            for (int i = 1; i < counts.length; i++) {
                counts[i] += counts[i - 1]; 
            }

            // 将数组按照前面得到的 counts 中的分布进行整理
            // 从后往前处理是为了保证排序稳定性
            for (int i = n - 1; i >= 0; i--) {
                int x = (nums[i] / exp) % 10;
                buf[counts[x] - 1] = nums[i];
                counts[x]--;
            } 

            System.arraycopy(buf, 0, nums, 0, n);

            // 接下来处理更高一位
            exp *= 10;
        }

        // 从排好序的数组中获取到答案
        int res = 0;
        for (int i = 1; i < n; i++) {
            if (nums[i] - nums[i - 1] > res) {
                res = nums[i] - nums[i - 1];
            }
        }

        return res;
    }
}

复杂度分析

  • 时间复杂度:O(n)
    n 为数组的长度。
  • 空间复杂度:O(n)

优质项目推荐

推荐一个可用于练手、毕业设计参考、增加简历亮点的项目。

lemon-puls/txing-oj-backend: Txing 在线编程学习平台,集在线做题、编程竞赛、即时通讯、文章创作、视频教程、技术论坛为一体

公众号

有兴趣可以关注公众号一起学习更多的干货哈!

扫码_搜索联合传播样式-白色版.png