LeetCode Array 164 Maximum Gap

164. Maximum Gap

Given an unsorted array, find the maximum difference between the successive elements in its sorted form.

Return 0 if the array contains less than 2 elements.

Example 1:
Input: [3,6,9,1]
Output: 3
Explanation: The sorted form of the array is [1,3,6,9], either (3,6) or (6,9) has the maximum difference 3.

Example 2:
Input: [10]
Output: 0

Explanation: The array contains less than 2 elements, therefore return 0.
Note:
You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.
Try to solve it in linear time/space.

solution 1: sorting

将数组排序,然后遍历求相邻元素的差值,最后得到最大gap。

        public int maximumGap(int[] nums) {
            if (nums == null || nums.length < 2) return 0;
            int res = 0;
            int len = nums.length;

            Arrays.sort(nums);

            for (int i = 1; i < len; i++) {
                res = Math.max(res, nums[i] - nums[i-1]);
            }
            return res;
        }

复杂度为: O ( n l o g n ) O(nlogn) O(nlogn)

solution 2: Radix sort

代替上面的Arrays.sort(),使用radix sort(bucket sort)进行排序,采用LSD。radix sort有两种方法LSD(Least sgnificant digital),MSD(Most sgnificant digital),LSD由键值的最右边(个位)开始排序,MSD则相反,LSD适用于digits较小的数,MSD适用于digits较大的数,关于radix sort原理可以查看下面的文章
Radix Sort

    public class solution2 {
        public int maximumGap(int[] nums) {
            if (nums == null || nums.length < 2) return 0;
            int len = nums.length;
            int res = 0;
            // use radix sort(bucket sort), LSD to sort the array
            // create buckets using arraylist
            // could also use a 2D array, but it takes more memory
            ArrayList<Integer> buckets[] = new ArrayList[10];
            // find the maximum number in the array
            // in order to determine the number of runs
            int maxNum = 0;
            for (int i = 0; i < len; i++) {
                maxNum = Math.max(maxNum, nums[i]);
            }
            int numLoop = 0;
            int divide = 1;
            while (maxNum/10 != 0) {
                numLoop++;
                divide*=10;
            }

            int lsd; // represents the index of bucket that a num should be put into
            int temp = 1;
            while (numLoop!=0) {
                for (int i = 0; i < len; i++) {
                    lsd = (nums[i]/temp)%10;
                    // since the element will be appended to the end of the list
                    // use add()
                    buckets[lsd].add(nums[i]);
                }
                int counter = 0;// count the index of nums
                for (int i = 0; i < 10; i++) {
                    while(!buckets[i].isEmpty()) {
                        nums[counter++] = buckets[i].get(0);
                        buckets[i].remove(0);
                    }
                }
                temp = temp*10;
                numLoop--;
            }

            for (int i = 1; i < len; i++) {
                res = Math.max(res, nums[i] - nums[i-1]);
            }
            return res;
        }
    }

复杂度分析:
时间: O ( d ∗ ( n + k ) ) O(d*(n+k)) O(d(n+k)),d是counting sort的次数,和数组中最大数的位数有关,k是buckets的个数,此处为10.
空间: O ( n ) O(n) O(n)

在leetcode上提交时会提醒超出time limit,如[1, 100000]。主要是因为数组过小。

solution 3

同样采用radix sort但是对于bucket的size进行了优化.
首先可以确定的是对于一个大小为N的数组,其最小元素为min,最大元素为max,maximum gap至少大于等于 f l o o r ( m a x − m i n N − 1 ) floor(\frac{max-min}{N - 1}) floor(N1maxmin)。可以采用反证法证明,假设均匀分布且,每个数之间的gap都恰好为 f l o o r ( m a x − m i n N − 1 ) floor(\frac{max-min}{N - 1}) floor(N1maxmin),此时 m a x = m i n + g a p ∗ ( N − 1 ) max = min + gap*(N-1) max=min+gap(N1) < max得到矛盾,说明最大gap至少大于等于 f l o o r ( m a x − m i n N − 1 ) floor(\frac{max-min}{N - 1}) floor(N1maxmin)

为了保证不需要比较每个bucket内部的数的大小,构造size为 f l o o r ( m a x − m i n N − 1 ) floor(\frac{max-min}{N - 1}) floor(N1maxmin)的bucket。在此情况下只需要比较不同bucket之间的最大gap。 同时bucket间的maximum gap只需要bucket内的最小最大值就可以得到。

注意点:
1 边际情况:全部是duplicates, [1,1,1,1],需要确保size>0
2 bucket个数:int bucketNum = (maxNum-minNum)/size + 1
3 preMax初始化

    public class solution3 {
        public int maximumGap(int[] nums) {
            if (nums == null || nums.length < 2) return 0;
            int len = nums.length;
            int res = 0;
            // find the maximum, minimum number in the array
            // in order to determine the size of the bucket
            int maxNum = Integer.MIN_VALUE;
            int minNum = Integer.MAX_VALUE;
            for (int i = 0; i < len; i++) {
                maxNum = Math.max(maxNum, nums[i]);
                minNum = Math.min(minNum, nums[i]);
            }

            // size is the maximum gap within a bucket
            /*
            note that if the array is filled with duplicates
            like [1, 1, 1, 1], the maxNum - minNum == 0, and thus size == 0
            which we need to avoid. Because when we calculate bucketNum,
            (maxNum-minNum) is divided by size.
            To sum up,we need to make sure size > 0
             */
            int size = Math.max(1, (maxNum-minNum)/(len-1));

            // define and initialize bucket

            int bucketNum = (maxNum-minNum)/size + 1;
            int[] bucketMin = new int[bucketNum];
            int[] bucketMax = new int[bucketNum];
            for (int i = 0; i < bucketNum; i++) {
                bucketMax[i] = Integer.MIN_VALUE;
                bucketMin[i] = Integer.MAX_VALUE;
            }

            // traverse the array and put numbers into buckets
            for (int i = 0; i < len; i++) {
                int index = (nums[i] - minNum)/size;
                bucketMax[index] = Math.max(bucketMax[index], nums[i]);
                bucketMin[index] = Math.min(bucketMin[index], nums[i]);
            }

            // as for the initialization of prevMax
            // since the first bucket, bucket[0] can't be empty (minNum is in it)
            // we can initialize prevMax with minNum
            int prevMax = minNum;
            for (int i = 0; i < bucketNum; i++) {
                if (bucketMax[i] == Integer.MIN_VALUE && bucketMin[i] == Integer.MAX_VALUE)
                    // the bucket is empty
                    continue;
                res = Math.max(res, bucketMin[i] - prevMax);
                prevMax = bucketMax[i];
            }
            return res;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值