阿里巴巴笔试面试题

1。已知三个升序整数数组a[l], b[m]和c[n]。请在三个数组中各找一个元素,是的组成的三元组距离最小。三元组的距离定义是:假设a[i]、b[j]和c[k]是一个三元组,那么距离为:

Distance = max(|a[ I ] – b[ j ]|, |a[ I ] – c[ k ]|, |b[ j ] – c[ k ]|)

请设计一个求最小三元组距离的最优算法,并分析时间复杂度。

这个题目其实很大一部分是数学推导,当完成了数学推导过后编码实现是很简答的事情。

两个公式是关键:

     max{|x1-x2|,|y1-y2|} =(|x1+y1-x2-y2|+|x1-y1-(x2-y2)|)/2   --公式(1)

   我们假设x1=a[ i ],x2=b[ j ],x3=c[ k ],则

Distance = max(|x1 – x2|, |x1 – x3|, |x2 – x3|) = max(   max(|x1 – x2|, |x1 – x3|) , |x2 – x3|)   --公式(2)

  根据公式(1),max(|x1 – x2|, |x1 – x3|) = 1/2 ( |2x1 – x2– x3| +  |x2 – x3|),带入公式(2),得到

                    Distance = max( 1/2 ( |2x1 – x2– x3| +  |x2 – x3|) , |x2 – x3| )  

      =1/2 * max(  |2x1 – x2– x3|  , |x2 – x3| ) + 1/2*|x2 – x3//把相同部分1/2*|x2 – x3|分离出来,这一步是最难实现的我觉得,这步变形不容易想到!

      =1/2 * max(  |2x1 – (x2 + x3)|  , |x2 – x3| ) + 1/2*|x2 – x3|   //把(x2 + x3)看成一个整体,使用公式(1)

      =1/2 * 1/2 *((|2x1 – 2x2| + |2x1 – 2x3|) + 1/2*|x2 – x3|

      =1/2 *|x1 – x2| + 1/2 * |x1 – x3| + 1/2*|x2 – x3|

      =1/2 *(|x1 – x2| + |x1 – x3| + |x2 – x3|)  //到这里公式的化简就全部完成了!!!目标函数。

目标函数已经求得,只需要求最小值。因为数组已经是升序排列了!!!所以我们可以设置三个数组起始指针,每次计算一个距离并更新。每次计算时找到值最小的那个指针下标然后++操作(很容易发现要想使得目标函数尽量小,则需要把指向数组最小的那个指针++,尽量使得彼此数组元素接近,从而目标函数值最小),直到某个数组或者全部数组遍历完,复杂度最多为O(l+m+n).

#include <iostream>
using namespace std;
int l=3,m=4,n=5;

int MinofInt(int a,int b,int c)
{
	if (a>b)
	{
		return b>c? c:b;
	}
	else
	{
		return a>c ? c:a;
	}
}
int MinDistance(int *a,int *b,int *c)
{
	int i=0,j=0,k=0;
	int MinSum=(abs(a[i]-b[j])+abs(a[i]-c[k])+abs(b[j]-c[k]))/2;
	int sum=0;
	int MinInt=0;
	while (i<l && j<m && k<n)
	{
		sum=(abs(a[i]-b[j])+abs(a[i]-c[k])+abs(b[j]-c[k]))/2;
		MinSum=MinSum<sum? MinSum:sum;
		MinInt=MinofInt(a[i],b[j],c[k]);
		if (MinInt==a[i])
		{
			i++;
		}
		if (MinInt==b[j])
		{
			j++;
		}
		if (MinInt==c[k])
		{
			k++;
		}
	}
	return MinSum;
}

int main()
{
	int a[]={1,2,3};
	int b[]={100,102,103,208};
	int c[]={100,102,103,208,300};
	cout<<"MinDistance is : ";
	cout<<MinDistance(a,b,c)<<endl;
	return 0;
}


2 。在黑板上写下50个数字:1至50.在接下来的49轮操作中,每次做如下动作:选取两个黑板上的数字a和b,擦去,在黑板上写|b - a|。请问最后一次动作之后剩下数字可能是什么?为什么?

1.剩下的数字不可能大于50,结果只可能是 0-50

2.根据     |奇数-偶数|=奇数,|奇数-奇数|=偶数,|偶数-偶数|=偶数 ,所以经过一次操作,只可能减少0或2个奇数,由于1-50中有25个偶数,因此最后剩下的数字是个奇数,范围缩小为[1,3,5…,49]

3.证明每个奇数都能实现,由于两组任意连续的自然数a,a+1,b,b+1可以经过操作|a - (a+1)|=1,|b - (b+1)|=1,|1-1|=0,即可以消除这四个数的影响,所以可以按照如下规则实现任意奇数。

例如:

得到1:可以把1,2取出来,剩下的数字按照(3,4),(5,6),…,(49,50)分组,共24组连续的数字,可以全部消除影响,最后只剩下1,2,经过一轮操作后得到1。

得到3:可以把1,4取出来,剩下的数字按照(2,3),(5,6),…,(49,50)分组,共24组连续的数字,可以全部消除影响,最后只剩下1,4,经过一轮操作后得到3。

得到2K+1:可以把1,2K+2取出来,剩下的数字按照(2,3),(4,5),…,(2K,2K+1),(2k+3,2k+4),…,(49,50)分组,共24组连续的数字,可以全部消除影响,最后只剩下1,2K+2,经过一轮操作后得到2K+1。
规律总结:对于任意的1-N,只需要对┌N/2┐进行分析,如果┌N/2┐为奇数,则最后的结果全是不大于N的奇数,否则全是不大于N的偶数

3.1000桶酒,其中1桶有毒。而一旦吃了,毒性会在1周后发作。现在我们用小老鼠做实验,

要在1周内找出那桶毒酒,问最少需要多少老鼠。

提示:可以将酒混合后喝

答案:10只。将酒编号为1~1000 将老鼠分别编号为1 2 4 8 16 32 64 128 256 512 喂酒时 让酒的编号等于老鼠编号的加和如:17号酒喂给1号和16号老鼠  76号酒喂给4号、8号和64号老鼠 七天后将死掉的老鼠编号加起来 得到的编号就是有毒的那桶酒 因为2的10次方等于1024 所以10只老鼠最多可以测1024桶酒

证明如下:使用二进制表示:01, 10, 100, 1000, … , 1,000,000,000。对于任何一个小于1024的数,均可以采用前面的唯一一组二进制数来表示。故成立。

类似于第三题有什么测试楼层摔东西几层摔坏都是利用二进制一些特征进行问题的求解。


 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值