Easy
题目描述
两对数字 (a, b) 和 (c, d) 之间的乘积差定义为 (a * b) - (c * d)。
例如,(5, 6) 和 (2, 7) 之间的乘积差是 (5 * 6) - (2 * 7) = 16。
给你一个整数数组 nums,选择四个不同的下标 w、x、y 和 z,使数对 (nums[w], nums[x]) 和 (nums[y], nums[z]) 之间的乘积差最大。
返回以这种方式能够得到的最大乘积差。
示例 1:
输入:nums = [5,6,2,7,4]
输出:34
解释:我们可以选择下标 1 和 3 作为第一对 (6, 7),下标 2 和 4 作为第二对 (2, 4)。
乘积差是 (6 * 7) - (2 * 4) = 34。
示例 2:
输入:nums = [4,2,5,9,7,4,8]
输出:64
解释:我们可以选择下标 3 和 6 作为第一对 (9, 8),下标 1 和 5 作为第二对 (2, 4)。
乘积差是 (9 * 8) - (2 * 4) = 64。
约束条件:
- 4 <= nums.length <= 10^4
- 1 <= nums[i] <= 10^4
提示:
- 如果只需要在数组中找到2个数的最大乘积,你应该选择哪2个数?
- 我们只需要关心数组中的4个数字。
解题思路
要使乘积差 (a * b) - (c * d) 最大化,我们需要让 a * b 尽可能大,同时让 c * d 尽可能小。
核心思路:
- 为了使第一个乘积
a * b最大,我们应该选择数组中最大的两个数 - 为了使第二个乘积
c * d最小,我们应该选择数组中最小的两个数
解法分析:
- 排序解法:对数组排序,取最大的两个数和最小的两个数
- 一次遍历解法(推荐):通过一次遍历找到最大的两个数和最小的两个数
一次遍历的优势:
- 时间复杂度更优:O(n) vs O(n log n)
- 空间复杂度更优:O(1) vs O(1)或O(n)(取决于排序算法)
在遍历过程中,我们维护四个变量:最大值、第二大值、最小值、第二小值。遍历结束后,最大乘积差就是 max1 * max2 - min1 * min2。
代码实现
class Solution {
public:
int maxProductDifference(vector<int>& nums) {
int max1 = 0, max2 = 0; // 最大值和第二大值
int min1 = INT_MAX, min2 = INT_MAX; // 最小值和第二小值
for (int num : nums) {
// 更新最大值和第二大值
if (num > max1) {
max2 = max1;
max1 = num;
} else if (num > max2) {
max2 = num;
}
// 更新最小值和第二小值
if (num < min1) {
min2 = min1;
min1 = num;
} else if (num < min2) {
min2 = num;
}
}
return max1 * max2 - min1 * min2;
}
};
class Solution:
def maxProductDifference(self, nums: List[int]) -> int:
max1 = max2 = 0 # 最大值和第二大值
min1 = min2 = float('inf') # 最小值和第二小值
for num in nums:
# 更新最大值和第二大值
if num > max1:
max2 = max1
max1 = num
elif num > max2:
max2 = num
# 更新最小值和第二小值
if num < min1:
min2 = min1
min1 = num
elif num < min2:
min2 = num
return max1 * max2 - min1 * min2
public class Solution {
public int MaxProductDifference(int[] nums) {
int max1 = 0, max2 = 0; // 最大值和第二大值
int min1 = int.MaxValue, min2 = int.MaxValue; // 最小值和第二小值
foreach (int num in nums) {
// 更新最大值和第二大值
if (num > max1) {
max2 = max1;
max1 = num;
} else if (num > max2) {
max2 = num;
}
// 更新最小值和第二小值
if (num < min1) {
min2 = min1;
min1 = num;
} else if (num < min2) {
min2 = num;
}
}
return max1 * max2 - min1 * min2;
}
}
var maxProductDifference = function(nums) {
let max1 = 0, max2 = 0; // 最大值和第二大值
let min1 = Infinity, min2 = Infinity; // 最小值和第二小值
for (let num of nums) {
// 更新最大值和第二大值
if (num > max1) {
max2 = max1;
max1 = num;
} else if (num > max2) {
max2 = num;
}
// 更新最小值和第二小值
if (num < min1) {
min2 = min1;
min1 = num;
} else if (num < min2) {
min2 = num;
}
}
return max1 * max2 - min1 * min2;
};
复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 一次遍历(推荐) | O(n) | O(1) |
| 排序 | O(n log n) | O(1) |
说明:
- 一次遍历解法只需要遍历数组一次,时间复杂度为 O(n)
- 空间复杂度为 O(1),只使用了常数个额外变量
- 排序解法虽然思路简单,但时间复杂度较高,不如一次遍历解法高效