面试题 16.06. 最小差
思路:给定两个整数数组a和b,计算具有最小差绝对值的一对数值(每个数组中取一个值),并返回该对数值的差。
首先暴力法可行,但是时间复杂度太高,那么要想降低时间复杂度首先需要排序,不排序是没有任何规律的,排序后可以采用双指针的方法,不断移动指针使指针指向的两个值越来越接近,哪一个指针更大我们就移动另一个指针使其接近:
public int smallestDifference(int[] a, int[] b) {
/*
对两个数组进行排序
双指针
int diff = a[i] - b[j]
如果 diff < 0 ,表示 a[i] 小于 b[j] ,a 尽可能接近 b,那么 i++
如果 diff > 0 ,表示 a[i] 大于 b[j] ,b 尽可能接近 a,那么 j++
特殊情况:
a = {1,2,3,4,5}
b = {6,7,8,9,10}
如果 a 数组最大值比 b 数组最小值还小,那么 a 数组 i 会一直右移,直到到达边界 break
*/
int alen = a.length;
int blen = b.length;
Arrays.sort(a);
Arrays.sort(b);
int minVal = Integer.MAX_VALUE;
int i = 0;
int j = 0;
while(i < alen && j < blen){
//使用 long,防止 -2147483648 转正数后还是 -2147483648
long diff = a[i] - b[j];
minVal = (int)Math.min(Math.abs(diff), minVal);
if(diff < 0){
i++;
}else{
j++;
}
}
return minVal;
}
另外我们知道,只要是排序数组都会涉及到二分法,那么我们可否固定a对b二分呢,因为主要也是找最接近的数,同样也用min不断记录差值:
public int smallestDifference(int[] a, int[] b) {
Arrays.sort(a);
Arrays.sort(b);
long res = Integer.MAX_VALUE;
for(int num : a){
int left = 0;
int right = b.length - 1;
while(left <= right){
int mid = (left + right) >>> 1;
long diff = (long)num - b[mid];
res = Math.min(res, Math.abs(diff));
if(diff == 0){
return (int)res;
}
if(diff > 0){
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return (int)res;