Pigeon hole principle => need to make sure at least one bucket is empty

class Solution:
    def maximumGap(self, A: List[int]) -> int:
        """tc O(N) sc O(N)
        main idea:  since is required to write  in tc O(N) sc O(N) 
             since need to get max gap for each consecutive pair => wee need to sort => bucket sort 

            - with caculated avg gap, we can get max gap is not less than avg_gap 
            - if we hold min,max two values and assign at most n-2 items into n-1 buckets,  there must be empty buckets, so value pair consisting max gap will exist in two different bucket => compare current minBucket - prev maxBucket   
        0. edge case:  len < 2 or all values are same 
        1. get min max, get avg_gap
        2. create min max bucket and loop through array to assign each value based on avg_gap 
        3. at same index, compare each min bucket with previous index's max bucket. Note to avoid empty bucket 
        4. chekc last maxv with last maxBucket to update res 
        =======================================================================================
        1 3 6 8    avg_gap = ceil((8-1)//3) = 3   
        divide into bucket 
        [1,4)   [4,7)   [7,10)    n-1 = 3 buckets
         1 3     6        8     
          
          since for each bucket, only two end can be possible max diff pair, so we only record minvBucket and maxvBucket
          idx          0          1          2
          minvBucket   1          6          8
          maxvBucket   3          6          8  
          
          then we compare at each index, its minv - previous maxv, get the max diff 
                       NA         3          2        
        """
        n = len(A)
        if n < 2 or min(A) == max(A): # add for early termination 
            return 0
        minv,maxv = min(A),max(A)
        avg_gap = (maxv-minv-1)//(n-1)+1
        numBucket = n-1
        # get min,max at each interval 
        minvBucket = [float('inf')]*numBucket
        maxvBucket = [float('-inf')]*numBucket
        for a in A:
            if a in [minv,maxv]:
                continue 
            idx = (a-minv)//avg_gap
            minvBucket[idx] = min(minvBucket[idx],a) #if minvBucket[idx] != float('inf') else a 
            maxvBucket[idx] = max(maxvBucket[idx],a) #if maxvBucket[idx] != float('-inf') else a


        # check each consecutive bucket pair, get possible max diff from current minbucket - prev maxbucket 
        prev_max = minv 
        res = -1
        for i in range(numBucket):
            if minvBucket[i] == float('inf') and maxvBucket[i] == float('-inf'):  # empty bucket
                continue 
            res = max(res,minvBucket[i]-prev_max)
            prev_max = maxvBucket[i]
        res = max(res,maxv- prev_max) # update last possible max gap at maxv position since bucket range is [x,y) so maxv is not covered 
        #   e.g. A = [1,10000000]  only one bucket [1,10000000)
        return res