[面试手撕3][桶排序]LC164

62 阅读2分钟
class Solution {
    public int maximumGap(int[] nums) {
        // 1. 选出数组中的最小值 m 和最大值 M
        //这里初始化M为最小值的目的是:任何一个值都可以比其大,方便贪心,下面关于m的设置也是基于这个考虑。
        int M = Integer.MIN_VALUE;  // 最大值
        int m = Integer.MAX_VALUE;  // 最小值
        
        // 遍历数组,计算出最小值 m 和最大值 M
        //这一块就是纯贪心
        for (int x : nums) {
            M = Math.max(M, x);  // 更新最大值
            m = Math.min(m, x);  // 更新最小值
        }
        
        // 如果最大值和最小值的差小于等于 1,则不能形成大的间隔,直接返回 M - m
        if (M - m <= 1) {
            return M - m;  // 如果最大值和最小值差距小于等于 1,返回差值
        }
​
        int n = nums.length;  // 数组长度
        // 计算桶的宽度,`d` 是每个桶的理论宽度
        // 注意 `(M - m + n - 2) / (n - 1)` 的计算方式是为了向上取整
        int d = (M - m + n - 2) / (n - 1);  // `d` 是最大间隔可能的最小间隔 **此处容易出问题
        
        // 2. 初始化桶
        int BucketNum = (M - m) / d +1;// 计算桶的数量 例如d=3 M=9 m=1 则0 1 2都落在索引为0的桶 3 4 5落在索引为1的桶 至于+的这个1,是出于数组长度的考虑,因为桶的索引是从0开始的,但是桶的数量得从1开始考虑。  **此处容易出问题
        int[][] buckets = new int[BucketNum][2];  // 创建桶,2维数组[2]:一个存最小值,一个存最大值
        for (int[] b : buckets) {
            b[0] = Integer.MAX_VALUE;  // 初始化每个桶的最小值为整型最大值
            b[1] = Integer.MIN_VALUE;  // 初始化每个桶的最大值为整型最小值
        }
        
        // 3. 将每个数字放入对应的桶中
        for (int x : nums) {
            // 计算该数字应该放入哪个桶
            int index = (x - m) / d;  // 计算该数字放入哪个桶  **此处容易出问题
            int[] b = buckets[index];  // 获取对应桶
            b[0] = Math.min(b[0], x);  // 更新桶内的最小值
            b[1] = Math.max(b[1], x);  // 更新桶内的最大值
        }
​
        // 4. 计算最大间隔
        int ans = 0;  // 用于存储最大间隔
        int preMax = Integer.MIN_VALUE;  // 上一个非空桶的最大值,初始化为最小值
        for (int[] b : buckets) {
            if (b[0] != Integer.MAX_VALUE) {  // 如果桶不为空(即桶内有数字)  **此处容易出问题
                // 当前桶的最小值减去上一个非空桶的最大值,得到间隔
                ans = Math.max(ans, b[0] - preMax);  // 计算当前间隔,更新最大间隔
                preMax = b[1];  // 更新上一个桶的最大值
            }
        }
        
        return ans;  // 返回最大间隔
    }
}
​