跳到主要内容

元素之积

三个数中最大乘积

给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。

方案A 通过排序

思路:

  • 首先将数组排序。
  • 如果数组中全是非负数,则排序后最大的三个数相乘即为最大乘积;如果全是非正数,则最大的三个数相乘同样也为最大乘积。
  • 如果数组中有正数有负数,则最大乘积既可能是三个最大正数的乘积,也可能是两个最小负数(即绝对值最大)与最大正数的乘积。
  • 综上,我们在给数组排序后,分别求出三个最大正数的乘积,以及两个最小负数与最大正数的乘积,二者之间的最大值即为所求答案。

:::details 点击查看代码

function largestProduct(nums){
nums.sort((a,b)=>a-b);
let len=nums.length;
return Math.max(nums[0]*nums[1]*nums[len-1],nums[len-1]*nums[len-2]*nums[len-3])
}

const nums=[-3,-2,-1,4,3,1,2,5,-10];
console.log(largestProduct(nums));

:::

性能分析:

  • 时间复杂度:O(NlogN),其中 NN 为数组长度。排序需要 O(N\log N)O(NlogN) 的时间
  • 空间复杂度:O(logN),主要为排序的空间开销。

方案B 通过线性扫描

思路:

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

:::details 点击查看代码

 function largestProduct(nums){
let [min1,min2,max1,max2,max3]=[Infinity,Infinity,-Infinity,-Infinity,-Infinity];
for(let i=0;i<nums.length;i++){
let x=nums[i];
if(min1>x){
min2=min1;
min1=x;
}else if(min2>x){
min2=x
}
if(max1<x){
max3=max2;
max2=max1;
max1=x;
}else if(max2<x){
max3=max2;
max2=x;
}else if(max3<x){
max3=x;
}
}
return Math.max(min1*min2*max1,max1*max2*max3)
}

const nums=[-3,-2,-1,4,3,1,2,5,-10];
console.log(largestProduct(nums));

:::

性能分析:

  • 时间复杂度:O(N),其中 NN 为数组长度。我们仅需遍历数组一次。
  • 空间复杂度:O(1)

除自身以外数组的乘积

给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

示例:

输入: [1,2,3,4]
输出: [24,12,8,6]

方案 前缀积与后缀积

思路:

  1. 初始化result数组,对于给定索引i,result[i]代表的是i左侧所有数字的乘积
  2. result[0]=1nums初始左侧元素乘积为1
  3. 设立right,遍历跟踪右边元素的乘积,并更新数组result[i]=result[i]*right,然后更新right=right*nums[i]
  4. right=1,nums初始右侧元素乘积为1

:::details 点击查看代码

function productExceptSelf(nums) {
const len=nums.length;
const result=new Array(len).fill(0);
result[0]=1;
for(let i=1;i<len;i++){
result[i]=nums[i-1]*result[i-1];
}
let right=1;
for(let i=len-1;i>=0;i--){
result[i]=result[i]*right;
right*=nums[i];
}
return result;
};

:::

性能分析: