前端算法第一八零弹-两个数对之间的最大乘积差

136 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

两个数对 (a, b)(c, d) 之间的 乘积差 定义为 (a * b) - (c * d)

  • 例如,(5, 6)(2, 7) 之间的乘积差是 (5 * 6) - (2 * 7) = 16

给你一个整数数组 nums ,选出四个 不同的 下标 wxyz ,使数对 (nums[w], nums[x])(nums[y], nums[z]) 之间的 乘积差 取到 最大值 。

返回以这种方式取得的乘积差中的 最大值

示例 1:

输入:nums = [5,6,2,7,4]
输出:34
解释:可以选出下标为 13 的元素构成第一个数对 (6, 7) 以及下标 24 构成第二个数对 (2, 4)
乘积差是 (6 * 7) - (2 * 4) = 34

示例 2:

输入:nums = [4,2,5,9,7,4,8]
输出:64
解释:可以选出下标为 36 的元素构成第一个数对 (9, 8) 以及下标 15 构成第二个数对 (2, 4)
乘积差是 (9 * 8) - (2 * 4) = 64

贪心

由于 nums\textit{nums} 中的元素均为正整数,因此任意数对的乘积均为正整数。那么 nums\textit{nums} 中的最大数对乘积即为数组中最大两个元素 mx1\textit{mx}_1mx2\textit{mx}_2 的乘积;同理,最小数对乘积即为数组中最小两个元素 mn1\textit{mn}_1mn2\textit{mn}_2 的乘积。

同时,由于 nums\textit{nums} 中的元素个数大于等于 44 个,因此这四个元素的下标一定互不相同。那么,nums\textit{nums} 中两个数对之间的乘积差最大值即为 (mx1×mx2)(mn1×mn2)(\textit{mx}_1 \times \textit{mx}_2) - (\textit{mn}_1 \times \textit{mn}_2)

我们可以通过对数组 nums\textit{nums} 的一次遍历,找到对应的四个元素,进而计算出两个数对之间的乘积差最大值。

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxProductDifference = function (nums) {
  // 交换数组中两个值的位置
  const swap = (arr, i, j) => {
    const tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }

  // 向数组中新增一个值,并保持其单调性,且维持长度为2
  const addItem = (arr, num, cb) => {// 利用回调函数
    arr.push(num);
    let j = arr.length - 1;
    while (j > 0 && cb(arr[j], arr[j - 1])) {// 从后往前比较,如果更大(或更小)则交换其位置,即进行一次冒泡
      swap(arr, j, j - 1);
      j--;
    }
    if (arr.length > 2) {
      arr.pop();
    }
  }

  const max = [];
  const min = [];

  for (let i = 0; i < nums.length; i++) {
    addItem(max, nums[i], (r, l) => r > l)
    addItem(min, nums[i], (r, l) => r < l)
  }

  return max[0] * max[1] - min[0] * min[1]
};