Fork me on GitHub

910.最小差值II

基本思路

我们先把数组排个序,题目要求求最小差值,那么就必须是大数-$k$,小数+$k$,这样才能尽可能地减小差值。

那么哪些是所谓的’大数’呢?我们可以设置一个分割点$i$,即$i$为序列中最后一个需要+$k$的下标,在$i$之前的数是小数,在$i$之后的数是大数。那么整个序列的最大值就是$max(A.back()-k , A[i] + k)$,最小值就是$min(A[0]+k , A[i+1]-k)$

为什么分割点之前的数都是小数呢?

首先我们令$i$是序列中最后一个需要+$k$的下标,使得$A[i]$要+$k$,其次$A[0]$一定要+$k$,$A.back()$一定要-$k$,我们设$j < i$,由于$A[j]+k < A[i]+k$,$A[j]-k$要么$> A[0]+k$,此时对结果没有影响,要么$A[j]-k < A[0]+k$,此时使得结果变大了,不可取,所以我们干脆使得$A[j]+k$,这样对结果没有影响,所以对于$j < i$,$A[j]$必须+$k$。

为什么分割点之后的数都是大数呢?

我们令$i$是序列中最后一个需要+$k$的下标,使得$A[i]$要+$k$,所以之后的都是大数了。

分割点不存在怎么办?

不可能,分割点最小是0,此时的差值是$A.back()-A[0] - 2*k$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int smallestRangeII(vector<int>& A, int k) {
sort(A.begin() , A.end());
int res = A.back() - A[0];
for(int i = 0 ; i<A.size() - 1 ; ++i){
int Min = min(A[0] + k , A[i+1] - k);
int Max = max(A.back() - k , A[i] + k);
res = min(res , Max - Min);
}
return res;
}
};