8.1日参加了拼多多内推的笔试,由于自己实力差距答得很差,所以在这里整理反省下,话不多说,首先是第一道题目:
题目描述:
给定一个无序数组,包含正数、负数和0,要求从中找出三个数的乘积,使得乘积最大,要求时间复杂度O(n),空间复杂度O(1)。
输入描述
第一行是数组大小n,第二行是无序整数数组A[n]
输出描述
满足条件的最大乘积
示例
输入
4
3 4 1 2
输出
24
第一眼看到题目思路没有弄清,后来看大家的题解后才发现其实也不是很复杂,其实这个最大乘积只包含两种情况:(1)最大三个数的乘积;(2)最大数与最小两个数的乘积,在这两种情况中判断最大的为我们需要的满足条件的最大乘积。
接下来的问题就变成了在无序数组中找到3个最大值2个最小值,而题目要求为时间复杂度为O(n)空间复杂度为O(1),这时就会想到比较经典的一个O(n)的分治法寻找第K大(小)的算法。
首先根据快速排序思路,写出一次排序的函数:
int adjustArray(long long s[],int left,int right)
{
while(left<right)
{
while(left<right&&s[right]>=s[left])
right--;
if(left<right)
swap(s[right],s[left]);
while(left<right&&s[left]<s[right])
left++;
if(left<right)
swap(s[right],s[left]);
}
return left;
}
通过一次快速排序,我们可以将序列排为以基元素左边大右边小的序列,所以基于我们需要得到第几大的数,就可以与基元素的位置进行比较,如果大于基元素位置就在右半部分求取,小于就在左半部分求取,下面给出分治求第K大的函数如下(PS:由于防止乘积爆int 这里采取long long型):
long long solve(int left,int right,long long s[],int k)
{
int now=adjustArray(s,left,right);
if(k<now)
return solve(left,now-1,s,k);
else if(k>now)
return solve(now+1,right,s,k);
else
return s[now];
}
所以最后按照题目要求写出整体函数:
int main()
{
const int N = 100000;
long long s[N];
int k;
int num;
int temp;
while(cin>>num)
{
for(int i=0;i<num;i++)
{
cin>>temp;
s[i]=temp;
}
//先找到最大的三个数,和最小的两个数
k=num-1;
long long x1=solve(0,num-1,s,k);
k=num-2;
long long x2=solve(0,num-1,s,k);
k=num-3;
long long x3=solve(0,num-1,s,k);
long long ans=x1*x2*x3;
if(num>3)
{
k=0;
long long y1=solve(0,num-1,s,k);
k=1;
long long y2=solve(0,num-1,s,k);
ans=max(ans,x1*y1*y2);
}
cout<<ans<<endl;
}
return 0;
}