![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/c976a317c745ec5e5363159d4118b7ce.png)
排序
解题思路:时间复杂度O(
n
∗
l
o
g
2
n
n*log_2n
n∗log2n),空间复杂度O(
l
o
g
2
n
log_2n
log2n),时间和空间复杂度都用在了快速排序上 |
---|
对于一堆数里面挑出3个乘积最大,是个数学问题,有3种情况
- 这些数都是正数,则最大的3个数乘积最大
- 这些数都是负数,则最大的3个数乘积最大
- 有正有负,则可能是两个最小的和一个最大的乘积最大,也可能是3个最大的数乘积最大
- 只有1个正数,则最小的两个负数和这个正数相乘乘积最大
- 有多个正数,也有可能两个最小负数和最大正数更大。例如有[-20000,-10000,1,2,3]这样的数组,最大乘积为
−
10000
∗
−
20000
∗
3
-10000*-20000*3
−10000∗−20000∗3
- 综上所述,我们只需要找出3个最大的数,已经2个最小的数。然后取两种方案中大的即可。
- 3个最大的数乘积可能是最大(没有负数,或者负数乘积都特别小的情况)
- 2个最小加最大的数可能是最大(2个特别小的负数+一个最大正数)
有了上面的分析,我们的问题就变成了,找到数组中最大的3个数和最小的2个数
- 先排序,然后直接得到
- 快速查找算法,找到对应数字
- 线性搜索找最值
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/297e59136aadee635e622dbe3930ee40.png)
class Solution {
public int maximumProduct(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
return Math.max(nums[0] * nums[1] * nums[n - 1], nums[n - 3] * nums[n - 2] * nums[n - 1]);
}
}
选择
解题思路:时间复杂度O(
n
n
n),空间复杂度O(
l
o
g
2
n
log_2n
log2n) |
---|
- 法一使用快速排序做
- 而对于仅仅找特定几个值的话,快速选择时间复杂度更低
- 对于找到第几大的值可以参考215题
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4861d9117b5bcb158cd261dc68d379c4.png)
class Solution {
public int maximumProduct(int[] nums) {
int n = nums.length;
int min1 = quickSort(nums,0,n-1,1),min2 = quickSort(nums,0,n-1,2);
int max1 = quickSort(nums,0,n-1,n);
int max2 = quickSort(nums,0,n-1,n-1);
int max3 = quickSort(nums,0,n-1,n-2);
return Math.max(max1*min1*min2, max1*max2*max3);
}
int quickSort(int[] a, int left,int right,int k){
if(left >= right) return a[left];
int x = a[left + right >> 1];
int leftIndex = left - 1, rightIndex = right + 1;
while(leftIndex < rightIndex){
do leftIndex++;while(a[leftIndex] < x);
do rightIndex--;while(a[rightIndex] > x);
if(leftIndex < rightIndex){
swap(a,leftIndex,rightIndex);
}
}
if(k <= (rightIndex - left + 1))
return quickSort(a,left,rightIndex,k);
else
return quickSort(a,rightIndex+1,right,k-(rightIndex-left+1));
}
void swap(int[] a,int i,int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
线性搜索最值
解题思路:时间复杂度O(
n
n
n),空间复杂度O(
1
1
1) |
---|
- 对于一个数组的最大值和最小值,或者第二大,第2小等等。只要我们找的是边缘值(100个数,找最小的3个,找最大的3个),线性搜索效率会更高。但是如果是100个数里面找排序后最小的27个数,肯定不如快速选择和小根堆。
- 对于只找很少量的几个最值,线性搜索会很方便,只需要遍历一次数组
代码:可见,线性搜索,找最大的3个值就要3个if,100个就要100个if,所以只有找少数几个最值的时候可用 |
---|
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/2d37ea9a1636f8230c6669b4c3a0caa5.png)
class Solution {
public int maximumProduct(int[] nums) {
int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE;
int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
for (int num : nums) {
if (num > max3) {
if (num < max2) max3 = num;
else if (num < max1) {
max3 = max2;
max2 = num;
} else {
max3 = max2;
max2 = max1;
max1 = num;
}
}
if (num < min2) {
if (num > min1) min2 = num;
else {
min2 = min1;
min1 = num;
}
}
}
return Math.max(max1 * max2 * max3, max1 * min1 * min2);
}
}