据说是今年腾讯面试题,就各种答案

肖远行 2012-04-21 11:25:33
Description
Given three integer sequences which have been sorted in ascending order,pick one integer from each sequence and we can get three integers.we want these three integers to be nearest to each other.Assuming these three integers as a,b,c, they are nearest to each other means d=(a-b)2+(b-c)2+(c-a)2 is the smallest.

Input
There are many test cases. For each test case,the first line are three integers la,lb,lc, they let you know the length of each sequence. The following three lines separately have la,lb,lc integers,give you the integers in each sequence. 1<=la,lb,lc<=10^6 and All integers in the sequences are in the range of [-10^9,10^9].

Output
For each test case, just print one integer : the smallest d as mentioned above.

Sample Input
10 10 10
1 2 3 4 5 6 7 8 9 10
2 3 6 8 10 12 14 16 18 20
3 5 7 9 11 12 14 16 18 20

Sample Output
0
...全文
835 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
yasz1 2012-04-27
  • 打赏
  • 举报
回复
用中学学的均值不等式可以降元- -。。
傻X 2012-04-27
  • 打赏
  • 举报
回复
mark一下吧
肖远行 2012-04-26
  • 打赏
  • 举报
回复
if(a[i] < b[j])
{
++i;
}
else if(a[i] > b[j])
{
++j;
}
else
{
++i;++j;
}

这样变化的话,确实是线性,类似那个标程的思想,
但是正确性什么的还需要证明下。。。因为这样变化会去掉很多(a,b)组合。。。
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 的回复:]
大致这个意思
enum_c(a[i],b[j]);
if(a[i] < b[j])
{
++i;
}
else if(a[i] > b[j])
{
++j;
}
else
{
++i;++j;
}
[/Quote]
enum_c的时候,可以先确定(a,b,a+b/2)是否小于min,可以的话再二分。
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
大致这个意思
enum_c(a[i],b[j]);
if(a[i] < b[j])
{
++i;
}
else if(a[i] > b[j])
{
++j;
}
else
{
++i;++j;
}
肖远行 2012-04-26
  • 打赏
  • 举报
回复
你的归并具体指的是什么?
把数组a和数组b一起排序。。。

如果从这个归并后的数组之中,选取|a-b|的最小值的话,可以做到O(n),
但是如果要穷举所有的|a-b|的话,需要平方的算法吧。。。
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 的回复:]
a=b时,用c靠近a是没错的吧?
a != b时,c落在ab之间没错吧?

这样的话,需要枚举所有的(a,b)对了,
复杂度就是M*N*logK了、、、
[/Quote]
不会呀,之前的归并就是来做这个事的。(m+n)*logk
肖远行 2012-04-26
  • 打赏
  • 举报
回复
a=b时,用c靠近a是没错的吧?
a != b时,c落在ab之间没错吧?

这样的话,需要枚举所有的(a,b)对了,
复杂度就是M*N*logK了、、、
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
@17f。
a=b时,用c靠近a是没错的吧?
a != b时,c落在ab之间没错吧?
设|ac| = x,|bc|=y.
则x + y = |ab|;
x^2 + Y^2 >= 2xy当且仅当x = y;
所以x = y = |ab|/2;
肖远行 2012-04-26
  • 打赏
  • 举报
回复
我也不能确实那个标程是否正确。。。

我的意思是,先想办法确定|a-b|最小了,
然后再选c的话,当时会去二分最靠近(a+b)/2的c,
但是这样能不能得到正确结果的需要证明。。。
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 的回复:]
发现个破绽,
取a-b的最小值,再取c
不代表最后能最小。。。

这个题最难的证明,确定a和b,再枚举c,
容易想到,麻烦的是确认可以这样做。。。
[/Quote]
破绽是为什么?A-B取最小了代表|a-b|已经确定,现在是当前枚举ab时的最小值,肯定要个min记录的。
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]
嗯,数据弱一点的话,应该可以过,
定2点,枚举1点,这个思路,以前也考虑过,
当时想的混乱一点,题也没过。。。

额,如果没有很多组数据的话,可以通过,
这个算法的复杂度上界我算了下,大概在6*10的7次作用。。。
那么大概跑10多组数据,应该可以。。。
[/Quote]
既然是你们学校oj上的,上面标程能过不?

我有一个疑问
当前状态0
0. A B C
1. AB C
2. A B C
3. A B C
这个例子显然是状态1的结果最小。我也说明了,处于状态0时调整B的话,B = (A + C)/2时结果最小。
但是此处怎么没判断 1和 B最靠近(a+c)/2时的情况?

肖远行 2012-04-26
  • 打赏
  • 举报
回复
发现个破绽,
取a-b的最小值,再取c
不代表最后能最小。。。

这个题最难的证明,确定a和b,再枚举c,
容易想到,麻烦的是确认可以这样做。。。
肖远行 2012-04-26
  • 打赏
  • 举报
回复
嗯,数据弱一点的话,应该可以过,
定2点,枚举1点,这个思路,以前也考虑过,
当时想的混乱一点,题也没过。。。

额,如果没有很多组数据的话,可以通过,
这个算法的复杂度上界我算了下,大概在6*10的7次作用。。。
那么大概跑10多组数据,应该可以。。。
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
个人想法,abc为x轴上3个点。
求的是|ab| + |bc| + |ac|之和最小。

枚举其中2点(a,b),则|ab|已经固定,所以枚举的时候可以把ab先排序做个归并,最小值出现在两两之间的差。
如果a=b,则c为最靠近a的值。可以用lower_bound查找。
a!=b,则c点必然落在ab之间,且c = (a + b)/2时最小。则c为最靠近(a+b)/2的值。
[/Quote]
归并(nlogn + mlogm + klogk + n + m)
枚举应该是(n+m)*logk,枚举时遇到a=b=c立刻退出。
怕是过不了10^6数量级估计得线性。
肖远行 2012-04-26
  • 打赏
  • 举报
回复
while(i < n1 && j < n2 && k < n3 && ans > 0)
{
ans = min(ans, cal(a[i], b[j], c[k]));
tmpa = cal(a[i + 1], b[j], c[k]);
tmpb = cal(a[i], b[j + 1], c[k]);
tmpc = cal(a[i], b[j], c[k + 1]);
if(tmpa < tmpb && tmpa < tmpc) ++ i;
else if(tmpb < tmpc) ++ j;
else ++ k;
}

这个是主算法,只要操作就是如果改变i,j,k这三个下标。。。
肖远行 2012-04-26
  • 打赏
  • 举报
回复
我发一下程序,
是学校里面别人写的标程,
思路比较简单,一下子就能看懂了,
但是不知道对不对,我也没想出办法否认它,


#include<stdio.h>
#include<string.h>
#include<stdlib.h>

const int maxn = 1 << 20;
typedef long long LL;
LL a[maxn], b[maxn], c[maxn];

inline LL min(LL x, LL y)
{return x < y ? x : y;}

inline LL cal(LL x, LL y, LL z)
{return (x - y) * (x - y) + (x - z) * (x - z) + (z - y) * (z - y);}

int main()
{
LL ans, tmpa, tmpb, tmpc;
int n1, n2, n3, i, j, k;

freopen("in.txt", "r", stdin);
while(scanf("%d%d%d", &n1, &n2, &n3) != EOF)
{
for(i = 0; i < n1; ++ i) scanf("%lld", &a[i]);
for(i = 0; i < n2; ++ i) scanf("%lld", &b[i]);
for(i = 0; i < n3; ++ i) scanf("%lld", &c[i]);

ans = ((LL)1 << 63) - 1;
i = j = k = 0;

while(i < n1 && j < n2 && k < n3 && ans > 0)
{
ans = min(ans, cal(a[i], b[j], c[k]));
tmpa = cal(a[i + 1], b[j], c[k]);
tmpb = cal(a[i], b[j + 1], c[k]);
tmpc = cal(a[i], b[j], c[k + 1]);
if(tmpa < tmpb && tmpa < tmpc) ++ i;
else if(tmpb < tmpc) ++ j;
else ++ k;
}
printf("%lld\n", ans);
}
return 0;
}
肖远行 2012-04-26
  • 打赏
  • 举报
回复
这种方式确实可以,只是复杂度高了点。。。
归并2个数组,是nlogn,然后还有枚举这些ab,
每次枚举消耗logn,
大概需要nlogn + nlogn。。。
仔细想了下,在归并后的数组里面穷举最接近的|a-b|应该能O(n),
你这个算法应该能过这个题目。。。
xiaobeiweng 2012-04-26
  • 打赏
  • 举报
回复
学习,,,,
j8daxue 2012-04-26
  • 打赏
  • 举报
回复
个人想法,abc为x轴上3个点。
求的是|ab| + |bc| + |ac|之和最小。

枚举其中2点(a,b),则|ab|已经固定,所以枚举的时候可以把ab先排序做个归并,最小值出现在两两之间的差。
如果a=b,则c为最靠近a的值。可以用lower_bound查找。
a!=b,则c点必然落在ab之间,且c = (a + b)/2时最小。则c为最靠近(a+b)/2的值。
加载更多回复(6)

590

社区成员

发帖
与我相关
我的任务
社区描述
提出问题
其他 技术论坛(原bbs)
社区管理员
  • community_281
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧