今天群里有人问了一道面试题,题目是N个未排序的整数,在线性时间内,求N个整数在数轴上相邻两个数之间的最大差值。
首先我想吐槽(莫怪~)群里某同学给出的一个解法,用桶排序+线性扫描,按照那位同学的意思,桶排序是O(n),所以整个过程是O(n)。然而并没有什么卵用,这位同学可能不是很了解桶排序的脾气,因为桶排序最乐观情况下才是O(n),而这道题如果使用排序,那结果应该是O(nlogn)。
然后我给出了我的解题思路:
- 求 N 个数最大值 MAX,最小值 MIN
- 把 [MIN, MAX) 之间平均分成 N 桶,并且补一个桶 [MAX, MAX + AVG),把所有数字放到对应桶里,并且求出每个桶最大值 BMIN 最小值 BMAX
- MAX_INTERVAL=MAX(MAX_INTERVAL, 非空桶.BMIN - 前一个非空桶.BMAX)
观点如下:
- 如果桶内有多个数,桶内任意数间差值必然小于平均值
- 如果两非空桶之间存在空桶,当前非空桶BMIN的值 - 前一个非空桶.BMAX >=平均值
- 有N+1个桶,不存在每个桶正好分到一个,必然存在至少一个空桶
最后Talk is cheap, but no comment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| func maxDiff(A []int) int { N := len(A) min := A[0] max := A[0] for i := 0; i < N; i++ { if A[i] > max { max = A[i] } if A[i] < min { min = A[i] } } avg := float32(max-min) / float32(N) B := make([]struct { used bool bmax int bmin int }, N+1) for i := 0; i < N; i++ { b := &B[int(float32(A[i]-min)/avg)] if b.used { if A[i] > b.bmax { b.bmax = A[i] } else if A[i] < b.bmin { b.bmin = A[i] } } else { b.bmax = A[i] b.bmin = A[i] b.used = true } } diff := 0 lb := 0 for i := 1; i <= N; i++ { if !B[i].used { continue } if B[i].bmin-B[lb].bmax > diff { diff = B[i].bmin - B[lb].bmax } lb = i } return diff }
|