给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大,要求时间复杂度:O(n),空间复杂度:O(1)
输入描述:
无序整数数组A[n]
输出描述:
满足条件的最大乘积
示例1
输入
3 4 1 2
输出
24
思路:要求找出无序数组中的乘积最大的三个数,由于数组中可能有负数,查找时需要考虑两种情况:一种是找出最大的三个数作乘积,另一种是找出最大的正数以及最小的两个负数作乘积,比较这两个乘积大小,取较大值为最终结果。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
long[] num = new long[n];
for(int i=0;i<n;i++){
num[i] = sc.nextLong();
}
long res = find(num);
System.out.println(res);
}
}
private static long find(long[] s){
long max1 = 0,max2 = 0,max3 = 0,min1 = 0,min2 = 0; //创建五个变量分别保存最大的三个数和最小的两个数,空间复杂度为O(1);
int n = s.length;
for(int i=0;i<n;i++){
if(s[i] > max1){ //没遍历一个元素就更新最值
max3 = max2;
max2 = max1;
max1 = s[i];
}else if(s[i] > max2){
max3 = max2;
max2 = s[i];
}else if(s[i] > max3){
max3 = s[i];
}else if(s[i] < min1){
min2 = min1;
min1 = s[i];
}else if(s[i] > min1 && s[i] < min2){
min2 = s[i];
}else{
continue;
}
}
return Math.max(max3*max2*max1, max1*min1*min2);
}
}
另外一种思路是:构建两个堆,一个是大顶堆,一个是小顶堆,从大顶堆中取出最大的三个数作乘积,以及取出大顶堆中的最大值以及小顶堆中的最小两个值作乘积,最后比较二者的大小,取大值。大顶堆可以用优先队列来实现,优先队列能够自定义排序规则,下面是代码:
import java.util.*;
public class Main {
static PriorityQueue<Long> minHeap = new PriorityQueue<>(30,new Comparator<Long>(){ //小顶堆
@Override
public int compare(Long o1,Long o2){
return (int)(o1 - o2);
}
});
static PriorityQueue<Long> maxHeap = new PriorityQueue<>(30,new Comparator<Long>(){ //大顶堆
@Override
public int compare(Long o1,Long o2){
return (int)(o2 - o1);
}
});
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
for(int i=0;i<n;i++){ //时间复杂度为O(n),空间复杂度O(1)
maxHeap.offer(num[i]);
minHeap.offer(num[i]);
}
long max1 = maxHeap.poll();
long max2 = maxHeap.poll();
long max3 = maxHeap.poll();
long min1 = minHeap.poll();
long min2 = minHeap.poll();
long res = Math.max(max1*max2*max3, max1*min1*min2); //去较大值作为最后结果
System.out.println(res);
}
}
}