1 题目
2 解法一(朴素算法:三重for循环)
思路:
暴力求解所有可能
#include<cstdio>
#include<climits>
#include<cmath>
#include<string.h>
#include<iostream>
int main(){
//S1={-1,0,9},S2={-25,-10,10,11},S3={2,9,17,30,41}
int S1[] = {-1,0,9};
int S2[] = {-25, -10, 10, 11};
int S3[] = {2, 9, 17, 30, 41};
int res[3];
//初始化
memset(res, 0, sizeof(res));
//计算长度
int extent1 = sizeof(S1)/sizeof(*S1);
int extent2 = sizeof(S2)/sizeof(*S2);
int extent3 = sizeof(S3)/sizeof(*S3);
//定义int最大值,用于向下比较
int minLength = INT_MAX;
for(int i = 0;i < extent1;i++){
for(int j = 0;j < extent2;j++){
for(int k = 0;k < extent3;k++){
int tempLength = std::abs(S1[i] - S2[j]) + std::abs(S2[j]- S3[k]) + std::abs(S3[k] - S1[i]);
if(tempLength < minLength){
minLength = tempLength;
res[0] = S1[i];
res[1] = S2[j];
res[2] = S3[k];
}
}
}
}
for(auto i:res){
std::cout<<i<<std::endl;
}
printf("MinLength is %d", minLength);
return 0;
}
时间复杂度:
O
(
e
x
t
e
n
t
1
∗
e
x
t
e
n
t
2
∗
e
x
t
e
n
t
3
)
O(extent1*extent2*extent3)
O(extent1∗extent2∗extent3)
空间复杂度:
O
(
1
)
O(1)
O(1)
3 解法二(较优解:二重循环+指针后移)
思路:二重循环扫描a、b,而c数组指针向右移(不回头)。
即:数组A、B、C的长度分别为l、m、n,双重循环枚举a、b,对数组C设置变量k存储数组下标不断后移,初始k=0,只要移动后的D更小(即c不是最右边的点;为中间点时,移动后距离大小不变;为最左边点时,移动后距离变小),就选择后移,然后对每一组a、b、c求出对应的距离D,并从中选出最小的距离。
三种情况(下面三种情景,a和b可以互换):
a b c 【c右移,距离只会变大】
a c b【c右移,距离不变】
c a b 【c右移,距离变小】
void ans(int A[], int B[], int C[], int m, int n, int l){
int D_min = INT_MAX, D;
int k = 0;//数组C下标初始为0
for (int i = 0; i < n; ++i) {枚举a、b
for (int j = 0; j < m; ++j) {
D = DD(A[i], B[j], C[k]);
while(k < l - 1 && DD(A[i], B[j], C[k + 1]) < D){//只有在c为最左边的点时,才右移
D = DD(A[i], B[j], C[++k]); //更新下标k和距离D
}
if(D < D_min) D_min = D;//更新D_min值
}
}
std::cout<<D_min;
}
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1)
4 解法三(较优解:一重循环+两折半查找)
思路:一重循环扫描a,两轮折半查找b、c。
即:枚举a,两次折半查找b、c,找到最接近a的b和c值,然后判断<A[i], B[j], C[k]>、<A[i], B[j+1], C[k]>、<A[i], B[j], C[k+1]>、<A[i], B[j+1], C[k+1]>哪种情况D最小即可。
//伪代码
int BinarySearch(int A[], L, R, x){
int mid;
while(L < R){
mid = (L + R)/2;
if(x <= A[mid]) R = mid;
else L = mid + 1;
}
return L;
}
void ans(int A[],n ,B[], m, C[], l){
int D_min = Maxint, D;
int k, l = 0;
for(int i = 0; i < n;i++){
j = BinarySearch(B[], 0, m, A[i]);
k = BinarySearch(C[], 0, m, A[i]);
//对A[i]、B[j-1]或B[j]或B[j+1],C[k-1]或C[k]或C[k+1]>排列组合求出最小的D并与D_min比较更新
}
cout<<D_min;
}
时间复杂度:
O
(
n
∗
l
o
n
g
m
∗
l
o
n
g
l
)
O(n*longm*longl)
O(n∗longm∗longl)
空间复杂度:
O
(
n
∗
l
o
g
2
n
)
O(n*log^2n)
O(n∗log2n)
5 解法四(最优解:技巧——贪心+三指针后移)
思路(摘自百度文档):
实现代码:
#include<cstdio>
#include<climits>
#include<cmath>
#include<string.h>
#include<iostream>
#define xIsMin(x, y, z) (((x) <= (y)) && ((x) <= (z)))
void ans(int S1[], int S2[], int S3[], int extent1, int extent2, int extent3){
int res[3];
memset(res, 0, sizeof(res));
int minLength = INT_MAX, dis;
int i = 0, j = 0, k = 0;
while(i < extent1 && j < extent2 && k < extent3 && minLength > 0){
dis = std::abs(S1[i] - S2[j]) + std::abs(S2[j]- S3[k]) + std::abs(S3[k] - S1[i]);
if(dis < minLength){
minLength = dis;
res[0] = S1[i];
res[1] = S2[j];
res[2] = S3[k];
}
if(xIsMin(S1[i],S2[j],S3[k])) i++;
else if(xIsMin(S2[j],S3[k],S1[i])) j++;
else k++;
}
for(auto i:res){
std::cout<<i<<std::endl;
}
printf("MinLength is %d", minLength);
}
int main(){
//S1={-1,0,9},S2={-25,-10,10,11},S3={2,9,17,30,41}
int S1[] = {-1,0,9};
int S2[] = {-25, -10, 10, 11};
int S3[] = {2, 9, 17, 30, 41};
int extent1 = sizeof(S1)/sizeof(*S1);
int extent2 = sizeof(S2)/sizeof(*S2);
int extent3 = sizeof(S3)/sizeof(*S3);
ans(S1, S2, S3, extent1, extent2, extent3);
return 0;
}
时间复杂度:
O
(
e
x
t
e
n
t
1
+
e
x
t
e
n
t
2
+
e
x
t
e
n
t
3
)
O(extent1_+ extent_2+ extent_3)
O(extent1+extent2+extent3)
空间复杂度:
O
(
1
)
O(1)
O(1)