java数据结构与算法刷题-----LeetCode628. 三个数的最大乘积

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

在这里插入图片描述

排序

解题思路:时间复杂度O( n ∗ l o g 2 n n*log_2n nlog2n),空间复杂度O( l o g 2 n log_2n log2n),时间和空间复杂度都用在了快速排序上

对于一堆数里面挑出3个乘积最大,是个数学问题,有3种情况

  1. 这些数都是正数,则最大的3个数乘积最大
  2. 这些数都是负数,则最大的3个数乘积最大
  3. 有正有负,则可能是两个最小的和一个最大的乘积最大,也可能是3个最大的数乘积最大
  1. 只有1个正数,则最小的两个负数和这个正数相乘乘积最大
  2. 有多个正数,也有可能两个最小负数和最大正数更大。例如有[-20000,-10000,1,2,3]这样的数组,最大乘积为 − 10000 ∗ − 20000 ∗ 3 -10000*-20000*3 10000200003
  1. 综上所述,我们只需要找出3个最大的数,已经2个最小的数。然后取两种方案中大的即可。
  1. 3个最大的数乘积可能是最大(没有负数,或者负数乘积都特别小的情况)
  2. 2个最小加最大的数可能是最大(2个特别小的负数+一个最大正数)

有了上面的分析,我们的问题就变成了,找到数组中最大的3个数和最小的2个数

  1. 先排序,然后直接得到
  2. 快速查找算法,找到对应数字
  3. 线性搜索找最值
代码:这里是先排序的思路

在这里插入图片描述

class Solution {
    public int maximumProduct(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        return Math.max(nums[0] * nums[1] * nums[n - 1], nums[n - 3] * nums[n - 2] * nums[n - 1]);
    }
}

选择

解题思路:时间复杂度O( n n n),空间复杂度O( l o g 2 n log_2n log2n)
  1. 法一使用快速排序做
  2. 而对于仅仅找特定几个值的话,快速选择时间复杂度更低
  3. 对于找到第几大的值可以参考215题
🏆LeetCode215. 数组中的第K个最大元素https://blog.csdn.net/grd_java/article/details/136932454
代码

在这里插入图片描述

class Solution {
    public int maximumProduct(int[] nums) {
        int n = nums.length;
        int min1 = quickSort(nums,0,n-1,1),min2 = quickSort(nums,0,n-1,2);
        int max1 = quickSort(nums,0,n-1,n);
        int max2 = quickSort(nums,0,n-1,n-1);
        int max3 = quickSort(nums,0,n-1,n-2);
        return Math.max(max1*min1*min2, max1*max2*max3);
    }
    int quickSort(int[] a, int left,int right,int k){
        if(left >= right) return a[left];
        int x = a[left + right >> 1];//获取当前区间中间的数x
        //借助两个下标,让比x小的去x左边,比x大的去右边
        int leftIndex = left - 1, rightIndex = right + 1;//分别代表区间中应该在x左边(<=x)的下标和x右边的下标
        while(leftIndex < rightIndex){
            do leftIndex++;while(a[leftIndex] < x);//当leftIndex指向的值,>=x时,终止循环
            do rightIndex--;while(a[rightIndex] > x);//当rightIndex指向的值,<=x时,终止循环
            if(leftIndex < rightIndex){//如果leftIndex目前在x左边,而且rightIndex目前在x右边,说明他俩的指向的值应该调换位置
                swap(a,leftIndex,rightIndex);//让小的去x左边leftIndex位置,大的去x右边rightIndex位置
            }
        }//直到目前区间实现x是中位数,左边都比x小,右边都比x大为止
        //此时rightIndex必然指向第一个比x小的值(也就是x比它小的左边部分的边界)
        if(k <= (rightIndex - left + 1)) //如果left到rightIndex区间(比x小的左边部分),正好够我们找到第k大数
            return quickSort(a,left,rightIndex,k);//进入左边区间继续寻找
        else //如果左边部分没有第k大数,那就去右边找,此时左边部分的 rightIndex - left + 1已经确定都比第k大数小,所以k - 左边部分为下轮右边部分该找的值
            return quickSort(a,rightIndex+1,right,k-(rightIndex-left+1));//右边部分找第(k - 左边部分个数)大的数。
    }
    void swap(int[] a,int i,int j){
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

线性搜索最值

解题思路:时间复杂度O( n n n),空间复杂度O( 1 1 1)
  1. 对于一个数组的最大值和最小值,或者第二大,第2小等等。只要我们找的是边缘值(100个数,找最小的3个,找最大的3个),线性搜索效率会更高。但是如果是100个数里面找排序后最小的27个数,肯定不如快速选择和小根堆。
  2. 对于只找很少量的几个最值,线性搜索会很方便,只需要遍历一次数组
代码:可见,线性搜索,找最大的3个值就要3个if,100个就要100个if,所以只有找少数几个最值的时候可用

在这里插入图片描述

class Solution {
    public int maximumProduct(int[] nums) {
        //最大的3个
        int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
        //最小的两个
        int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
        //线性搜索
        for (int num : nums) {
            if (num > max3) {//如果当前值>第3大max3
                if (num < max2) max3 = num;//小于第二大max2,就赋值给max3
                 else if (num < max1) {//大于max2,小于max1,max2的值给max3,num赋值给max2
                    max3 = max2;//max2的值变为第3大
                    max2 = num;//num变为第二大
                } else {//如果也大于max1
                    max3 = max2;//max2给max3
                    max2 = max1;//max1给max2
                    max1 = num;//num给max1
                }
            }
            //如果当前值小于min2
            if (num < min2) {
                if (num > min1)  min2 = num;//但是大于min1,则num给min2
                else {//如果小于min1
                    min2 = min1;//min1给min2
                    min1 = num;//num给min1
                }
            }
        }
        //可见,线性搜索,找最大的3个值就要3个if,100个就要100个if,所以只有找少数几个最值的时候可用
        //两种方案返回大的
        return Math.max(max1 * max2 * max3, max1 * min1 * min2);
    }
}
  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值