2017.8.1拼多多内推内推笔试题(1)—最大乘积的求取(分治求K大(小))

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值