优势洗牌

64 阅读1分钟

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

870. 优势洗牌 - 力扣(LeetCode)

给定两个大小相等的数组 nums1 和 nums2nums1 相对于 nums2优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描述。

返回 nums1 的任意排列,使其相对于 nums2 的优势最大化。

示例 1:

输入: nums1 = [2,7,11,15], nums2 = [1,10,4,11]
输出: [2,11,7,15]

示例 2:

输入: nums1 = [12,24,8,32], nums2 = [13,25,32,11]
输出: [24,32,8,12]

提示:

  • 1 <= nums1.length <= 10^5
  • nums2.length == nums1.length
  • 0 <= nums1[i], nums2[i] <= 10^9

思路

看到这个题目,想到了田忌赛马的故事,我们可以采取同样的策略来获取nums1相对nums2的优势,我们需要在nums1中找到大于nums2[i]的最小数字,如果存在这样的数字nums1[j],我们把nums1[j]nums1[i]交换。如果不存在我们查找最小值nums1[j]并交换。

解题

解法一

循环遍历nums2,从nums1中查找大于nums2[i]的最小数,如果没有找到,就用nums1中的最小值,此方法可以求解,但是提交的时候会超出时间限制,不符合要求。

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var advantageCount = function (nums1, nums2) {
  for (let i = 0; i < nums2.length; i++) {
    let num = nums2[i];
    let n = i;
    for (let j = i + 1; j < nums1.length; j++) {
      if (
        (nums1[n] > num && nums1[j] > num) ||
        (nums1[n] <= num && nums1[j] <= num)
      ) {
        n = nums1[n] > nums1[j] ? j : n;
      } else {
        n = nums1[n] > nums1[j] ? n : j;
      }
    }
    if (n !== i) {
      let temp = nums1[i];
      nums1[i] = nums1[n];
      nums1[n] = temp;
    }
  }
  return nums1;
};

解法二

和解法一思路一致,只是从nums1中查找大于nums2[i]的最小数的时候做了一点优化,先把nums1排序,再二分查找。

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var advantageCount = function (nums1, nums2) {
  const res = new Array(nums1.length);
  nums1.sort((a, b) => a - b);
  const find = (n) => {
    let left = 0;
    let right = nums1.length - 1;
    while (left <= right) {
      const mid = (left + right) >> 1;
      if (nums1[mid] <= n) {
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }
    return left;
  };
  for (let i = 0; i < nums2.length; i++) {
    let idx = find(nums2[i]);
    idx = idx < nums1.length ? idx : 0;
    res[i] = nums1.splice(idx, 1)[0];
  }
  return res;
};

解法三

解法二虽然可以满足要求,不会超时,但是时间效率很差,还要继续优化,可以改为贪婪算法,在解法二的基础上,把num2也进行排序,并用双指针求解,具体看代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var advantageCount = function (nums1, nums2) {
  const n = nums1.length;
  nums1.sort((a, b) => a - b);
  const idx1 = new Array(n).fill(null).map((_, i) => i);
  idx1.sort((a, b) => nums2[a] - nums2[b]);
  const res = new Array(n);
  let left = 0;
  let right = n - 1;
  for (let i = 0; i < n; i++) {
    if (nums1[i] > nums2[idx1[left]]) {
      res[idx1[left]] = nums1[i];
      left++;
    } else {
      res[idx1[right]] = nums1[i];
      right--;
    }
  }
  return res;
};