题目
标题和出处
标题:三个数的最大乘积
难度
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} 3≤nums.length≤104
- -1000 ≤ nums[i] ≤ 1000 \texttt{-1000} \le \texttt{nums[i]} \le \texttt{1000} -1000≤nums[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)。