题意描述:有两个升序的数组A,B 求|A[i]-B[j]|的最小值
解题思路:首先想到的是暴力解法,即内外双循环,逐一拿数组中的两元素作差,取最小的min,但这样做的时间复杂度达到了O(m*n)。所以想优化解法,先上代码再解析吧:
int GetMinArraySubtraction(int A[], int lenA, int B[], int lenB) {
if (lenA == 0 && lenB == 0)
return 0;
if (A[0] > B[lenB - 1])
return A[0] - B[lenB - 1];
if (B[0] > A[lenA - 1])
return B[0] - A[lenA - 1];
int min = abs(A[0] - B[0]);//所求最小
int i = 0, j = 0;
if (A[i] > B[j])
j++;
else i++;
int flagA = 0;//记录数组上一个下标
int flagB = 0;
while (i < lenA && j < lenB) {
if (A[i] > B[j]) {
int temp = abs(A[flagA] - B[j]);
min = temp < min ? temp : min;
flagB = j;
j++;
}
else {
int temp = abs(A[i] - B[flagB]);
min = temp < min ? temp : min;
flagA = i;
i++;
}
}
while (i < lenA) {//B遍历完了
int temp = abs(A[i++] - B[flagB]);
min = temp < min ? temp : min;
}
while (j < lenB) {//A遍历完了
int temp = abs(B[j++] - A[flagA]);
min = temp < min ? temp : min;
}
return min;
}
因为每次作差必是两数组中的元素作差,而最小的差必是两数组中相对排序相邻的元素,所以可以虚拟一个数组C用来存放A、B合并排序后的结果,但这里并不真正需要数组C而只用声明两个标记变量flagA、flagB分别记录数组A和数组B上一次计数到的元素下标,然后当每次插入新元素时就与上一次的对方计数到的数组中的元素作差,取最小。整个算法的时间复杂度为O(m+n)
以下是我设计的测试用例:
int arrayA[] = { 1,10,23,45,97 };
int arrayB[] = { 6,17,33,62,87,96 };
int arrayC[] = { 6,17,33,62,87,98 };
cout << GetMinArraySubtraction(arrayA, 5, arrayB, 6) << endl;//1
cout << GetMinArraySubtraction(arrayA, 5, arrayC, 6) << endl;//1