排序题目:三个数的最大乘积

题目

标题和出处

标题:三个数的最大乘积

出处:628. 三个数的最大乘积

难度

3 级

题目描述

要求

给定一个整数数组 nums \texttt{nums} nums,在数组中找出三个数,使得这三个数的乘积最大,并返回最大乘积。

示例

示例 1:

输入: nums   =   [1,2,3] \texttt{nums = [1,2,3]} nums = [1,2,3]
输出: 6 \texttt{6} 6

示例 2:

输入: nums   =   [1,2,3,4] \texttt{nums = [1,2,3,4]} nums = [1,2,3,4]
输出: 24 \texttt{24} 24

示例 3:

输入: nums   =   [-1,-2,-3] \texttt{nums = [-1,-2,-3]} nums = [-1,-2,-3]
输出: -6 \texttt{-6} -6

数据范围

  • 3 ≤ nums.length ≤ 10 4 \texttt{3} \le \texttt{nums.length} \le \texttt{10}^\texttt{4} 3nums.length104
  • -1000 ≤ nums[i] ≤ 1000 \texttt{-1000} \le \texttt{nums[i]} \le \texttt{1000} -1000nums[i]1000

解法一

思路和算法

由于数组 nums \textit{nums} nums 中可能存在正数、零与负数,因此需要考虑当乘积最大时的三个数的所有可能情况。

  • 如果数组中的所有元素都是非负数,则任意三个数的乘积都是非负数,数组中的最大三个数的乘积即为最大乘积。

  • 如果数组中的所有元素都是负数,则任意三个数的乘积都是负数,为了使乘积最大应该使乘积的绝对值最小,数组中的最大三个数即为绝对值最小的三个数,乘积即为最大乘积。

  • 如果数组中同时有非负数与负数,则根据负数的个数,有两种可能的情况。

    • 如果数组中至少有两个负数,则当乘积最大时,最大乘积一定是非负数。可能选三个最大的非负数,也可能选一个最大的非负数与两个最小的负数(即两个绝对值最大的负数)。

    • 如果数组中只有一个负数,则任意三个数中至少有两个非负数,当乘积最大时,一定是选数组中的最大三个数。

根据上述分析可知,当乘积最大时,三个数的可能情况有两种,一是选数组中最大的三个数,二是选数组中最大的一个数与最小的两个数。对于这两种情况分别计算乘积,返回最大乘积。

代码

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

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间。

  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间。

解法二

思路和算法

由于计算最大乘积只需要得到数组中最大的三个元素与最小的两个元素,并不需要得到所有元素的顺序,因此可以直接遍历数组找到最大的两个元素。

遍历数组 nums \textit{nums} nums,遍历过程中维护最大的三个元素与最小的两个元素,对于每个元素 num \textit{num} num,与最大的三个元素以及最小的两个元素比较,并更新相应的元素值。遍历结束之后,即可得到最大的三个元素与最小的两个元素,并计算最大乘积。

代码

class Solution {
    public int maximumProduct(int[] nums) {
        int firstMax = Integer.MIN_VALUE, secondMax = Integer.MIN_VALUE, thirdMax = Integer.MIN_VALUE;
        int firstMin = Integer.MAX_VALUE, secondMin = Integer.MAX_VALUE;
        for (int num : nums) {
            if (num > firstMax) {
                thirdMax = secondMax;
                secondMax = firstMax;
                firstMax = num;
            } else if (num > secondMax) {
                thirdMax = secondMax;
                secondMax = num;
            } else if (num > thirdMax) {
                thirdMax = num;
            }
            if (num < firstMin) {
                secondMin = firstMin;
                firstMin = num;
            } else if (num < secondMin) {
                secondMin = num;
            }
        }
        return Math.max(thirdMax * secondMax * firstMax, firstMin * secondMin * firstMax);
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组一次。

  • 空间复杂度: O ( 1 ) O(1) O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

伟大的车尔尼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值