元素之积
三个数中最大乘积
给你一个整型数组 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]
方案 前缀积与后缀积
思路:
- 初始化
result
数组,对于给定索引i
,result[i]
代表的是i
左侧所有数字的乘积 result[0]=1
,nums
初始左侧元素乘积为1
- 设立
right
,遍历跟踪右边元素的乘积,并更新数组result[i]=result[i]*right
,然后更新right=right*nums[i]
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;
};
:::
性能分析: