🚩传送门:牛客题目

题目

给你一个整型数组nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
要求:时间复杂度 [NC]106. 三个数的最大乘积 - 图1,空间复杂度 [NC]106. 三个数的最大乘积 - 图2

示例 1:

输入:nums = [1,2,3] 输出:6

示例 2:

输入:nums = [1,2,3,4] 输出:24

示例 3:

输入:nums = [-1,-2,-3] 输出:-6

解题思路1:排序

首先将数组排序。

  1. 如果数组中全是正数,则排序后最大的三个数相乘即为最大乘积;(正的最多)
  2. 如果数组中全是负数,则排序后最大的三个数相乘即为最大乘积;(负的最少)
  3. 如果数组中有正数有负数,则最大乘积既可能是三个最大正数的乘积,也可能是两个最小负数(即绝对值最大)与最大正数的乘积。

综上,我们在给数组排序后,分别求出三个最大正数的乘积,以及两个最小负数最大正数的乘积,二者之间的最大值即为所求答案。

复杂度分析

时间复杂度:[NC]106. 三个数的最大乘积 - 图3,其中 [NC]106. 三个数的最大乘积 - 图4 是数组长度。排序需要 [NC]106. 三个数的最大乘积 - 图5 的时间。

空间复杂度:[NC]106. 三个数的最大乘积 - 图6,主要为排序的空间开销。

官方代码

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

解题思路2:线性扫描

在方法一中,我们实际上只要求出数组中最大的三个数以及最小的两个数,因此我们可以不用排序,用线性扫描直接得出这五个数。

复杂度分析

时间复杂度:[NC]106. 三个数的最大乘积 - 图7,其中 [NC]106. 三个数的最大乘积 - 图8 是数组长度,我们仅需遍历数组一次。

空间复杂度:[NC]106. 三个数的最大乘积 - 图9

官方代码

  1. class Solution {
  2. public long maximumProduct(int[] nums) {
  3. // 最小的和第二小的
  4. long min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
  5. // 最大的、第二大的和第三大的
  6. long max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
  7. for (int num : nums) {
  8. if (num > max1) { // ==========啥,你比老大的值还大=======
  9. max3 = max2; // 原老二委屈一下你,去做老三吧,难受...
  10. max2 = max1; // 原老大委屈一下你,去做老二吧,难受...
  11. max1 = num; // 大哥快请上座!!!
  12. } else if (num > max2) { // ==========啥,你比老二的值还大=======
  13. max3 = max2; // 原老二委屈一下你,去做老三吧,难受...
  14. max2 = num; // 二哥快请上座!!!
  15. } else if (num > max3) { // ==========哎,你比老三的值还大=======
  16. max3 = num; // 三哥快请上座!!!
  17. }
  18. if (num < min1) { // ==========啥,你比老幺的值还小=======
  19. min2 = min1; // 原老幺委屈一下你,去做二幺吧,难受...
  20. min1 = num; // 老幺快请上座!!!
  21. } else if (num < min2) { // ==========啥,你比二幺的值还小=======
  22. min2 = num; // 二幺快请上座!!!
  23. }
  24. }
  25. return Math.max(min1 * min2 * max1, max1 * max2 * max3);
  26. }
  27. }