leetcode 164. Maximum Gap

本文探讨了求解数组中最大间隔的算法问题,介绍了通过排序、桶排序和基数排序三种方法来解决这一问题,并分析了各自的优缺点及适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

给出一个无序数组,求数组里的这些元素按排序情况下相邻元素相差的最大值。
比如{6,1,2},那么就是2、6之间相差最大,返回4

这道题最容易想到的就是把数组排好序,然后遍历一次,找到相差最大的两个相邻元素,事实上这么做也是可以通过的。

public int maximumGap(int[] nums) {
        if(nums.length < 2){
             return 0;
         }
         Set<Integer> set = new TreeSet<Integer>();
         for(int i=0;i<nums.length;i++){
             set.add(nums[i]);
         }
         int max = 0;
         Iterator<Integer> it = set.iterator();
         int before = it.next();
         while(it.hasNext()){
             int after = it.next();
             max = Math.max(max, after - before);
             before = after;
         }
         return max;
    }

那么有没有O(n)的时间复杂度实现?还是有的,但是还是要往能做到O(n)时间的排序才能想到,像官方题解的桶排序就是如此,把属于同一区间的数放入同一个桶中。

用桶排序做此题的诀窍在于,划分桶的总数量、单个桶的容量时,要保证桶之间的差值一定大于桶内的差值,这样就只需要比较前一个桶里最大值与后一个桶最小值得差值即可。

public int maximumGap(int[] nums) {
         if(nums.length < 2){
             return 0;
         }
         int len = nums.length;
         int max = Integer.MIN_VALUE;
         int min = Integer.MAX_VALUE;
         for(int i=0;i<len;i++){
             max = Math.max(max, nums[i]);
             min = Math.min(min, nums[i]);
         }
         if(max - min < 2){
             return max - min;
         }
         int aaaa = (int) Math.ceil((double)(max - min) / (len - 1));
         int bucketCount = (max-min)/aaaa;
         int M[] = new int[bucketCount+1];
         int N[] = new int[bucketCount+1];
         for(int i=0;i<bucketCount+1;i++){
             M[i] = Integer.MIN_VALUE;
             N[i] = Integer.MAX_VALUE;
         }
         for(int i=0;i<len;i++){
             int index = (nums[i]-min) / aaaa;
             M[index] = Math.max(M[index], nums[i]);
             N[index] = Math.min(N[index], nums[i]);
         }
         if(bucketCount == 1){
             return N[1] - M[0];
         }
         int result = 0;
         int lastMax = Integer.MIN_VALUE;
         if(M[0] != Integer.MIN_VALUE){
             lastMax = M[0];
         }
         for(int i=1;i<M.length;i++){
             if(N[i] != Integer.MAX_VALUE){
                 result = Math.max(N[i]-lastMax,result);
             }
             if(M[i] != Integer.MIN_VALUE){
                 lastMax = M[i];
             }
         }
         return result;
     }

另外还有一种解法是基数排序,基数排序从低位到高位对数组元素排序,最终能够达到完全排序的目的。
此种算法的时间复杂度依赖于待排序元素的最大位数i,复杂度为O(i*n),对于此题来说还是比较合适。
关键点在于如何把取余数相同后的元素放在同一区间,这里参考了leetcode的官方解答。

public int maximumGap(int[] nums) {
        if(nums.length < 2){
             return 0;
         }
         int len = nums.length;
         int exp = 1;
         int radix = 10;
         int max = Integer.MIN_VALUE;
         int min = Integer.MAX_VALUE;
         for(int i=0;i<len;i++){
             max = Math.max(max, nums[i]);
             min = Math.min(min, nums[i]);
         }
         while(max/exp>0){
             int count[] = new int[radix];
             for(int i=0;i<len;i++){
                 count[nums[i]/exp%10]++; //计算每个相同数字结尾的有多少个
             }
             for(int i=1;i<radix;i++){
                 count[i] += count[i-1]; //计算每个相同数字结尾的区间
             }
             int temp[] = new int[len];
             for(int i=len-1;i>=0;i--){//把不同数字结尾的放入各自区间
                 temp[--count[nums[i]/exp%10]] = nums[i];
             }
             for(int i=len-1;i>=0;i--){
                 nums[i] = temp[i]; 
             }
             exp *= 10;
         }
         int result = nums[1] - nums[0];
         for(int i=1;i<len;i++){
             result = Math.max(result, nums[i] - nums[i-1]);
         }
         return result;
    }

执行testcae 7ms的效率还是可以的,毕竟是完全排序,实现起来也比较容易理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值