搜狗2018笔试题,编程题是这样:一个环形区域,从小到大输入每个环形点上的角度,求其中距离最大的两个点。
写了半天,人家说最好用时间复杂度低的写,所以想用时间复杂度为N的方法,但是没写出来,边界不好控制,一直到交完卷了才写出来,测试了几个特殊的例子,感觉好像没问题。。。
输入数据,第一个为输入的数据个数,接下来,从小到大输入数据,求其中距离最大的两个点。因为是圆环状,所以可以用N的平法的方法,也可以稍微改进,用N*log2N的方法。我用的是N的方法,大体思路是:因为有序输入数据,所以,找到最小的数据很方便,然后以最小的数据点穿过圆心画直径,这是第一条线,将所有的数据映射到这条线上,最接近最小数据+180的点,为最终点,算出第一个最大值。然后以这条直径作垂直线,同时遍历一遍数据,找到映射到新直线上的两个最远点,这是第二个最终点,求出两个最终点的最大值,即为最远点。
用数字举个例子,比如输入数据,10.0000, 189.00000, 196.00000, 200.0000 则作第一条直线为,10 ----- 190 ,最远的两个点为10.0000 和 189.0000,然后作第二条直线,100 ----- 280,求出最远点,再算他们之间的最大值。这种方法,只需要遍历两遍数组,时间复杂度为N。个人觉得这个思路没问题,欢迎挑毛病。(本来笔试的时候,不应该用这么难受的方法的,其实用N*log2N 就行,哎,当时死心眼了,非得用这个,把自己写的很难受。。。。)
代码:
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
void fun(vector<double> &ve,int n)
{
double xbegin = ve[0];
double xend = xbegin + 180;
double min = xbegin;
double max = xbegin;
bool flag = false;
if(ve[0] >= 180 || ve[n-1] <= 180)
{
flag = true;
}
for(int i = 0; i < n; ++i)
{
if(abs(max - (xend)) > abs(ve[i] - xend))
max = ve[i];
}
double end = max - min > 180 ? 180 - (max - min - 180) : max - min;
if(flag)
{//判断有没有必要在进行垂直线的计算
cout<<fixed<<setprecision(8)<<end<<endl;
return ;
}
xbegin = xbegin + 90;
xend = xend + 90;
min = xend;
max = xbegin;
for(int i = 0; i < n; ++i)
{
//找最大值
if(abs(max - xend) > abs(ve[i] - xend))
max = ve[i];
//找最小值
if(abs(min - xbegin) > abs(ve[i] - xbegin))
min = ve[i];
}
double tmp = max - min > 180 ? 180 - (max - min - 180) : max - min;
end = end > tmp ? end : tmp;
cout<<fixed<<setprecision(8)<<end<<endl;
}
int main()
{
vector<double> ve;
int n;
cin>>n;
double tmp;
for(int i = 0; i < n; ++i)
{
cin>>tmp;
ve.push_back(tmp);
}
fun(ve,n);
return 0;
}