每日一题 优势洗牌

109 阅读3分钟

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

每日一题 优势洗牌

原题链接:

870. 优势洗牌

示例 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 <= 105
nums2.length == nums1.length
0 <= nums1[i], nums2[i] <= 109

解题思路

这就是一题很典型的田忌赛马的题目 (看了好多解析都是这样说的,其实也没错啦)
我们照搬田忌赛马的核心思路:

  • nums1中的下等马 换 nums2的上等马
  • nums1中的中等马 换 nums2的下等马
  • nums1中的上等马 换 nums2的中等马 获取nums1的上中下等马,很简单,我们仅需要对 nums1 进行一次排序就好,但是最终的结果需要是相对于 nums2 的优势最大化。 那么就表示我们不能直接对 nums2 进行排序操作,那么我们需要对nums2进行映射排序了。

不太懂?请看下面的详细解析

步骤一

  1. nums1 进行排序
    • let newNums1 = nums1.sort((i, j) => i - j)
  2. 获取 nums2 排序后的下标值映射
    • let newNums2 = new Array(len).fill().map((value, key) => key).sort((i, j) => nums2[i] - nums2[j])

Q: 为什么需要 获取 nums2 的下标值映射,而不是直接对 nums2 进行排序
A:

  1. 最终的结果需要是相对于 nums2 的优势最大化,是针对nums2的位置来进行排序的,所以我们需要保证 nums2的顺序不发生改变
  2. 获取 nums2 排序后的下标值映射是为了,可以通过下标映射来访问没有被排序后的 nums2的值 image.png
// 排序 nums1 获得 从小到大的 数组
let newNums1 = nums1.sort((i, j) => i - j)
// nums2的键值对索引
// 获取后 对 索引进行排序 获得 nums2 从小到大的 排序键值索引
let newNums2 = new Array(len).fill().map((value, key) => key).sort((i, j) => nums2[i] - nums2[j])

步骤二

  • 为已经上场比赛的选手占位置
// 然后我们需要获取左右两个节点
  // 左右两个节点 是为了进行比对的时候 放置数据的位置用
  let left = 0 // nums2的最小值
  let right = len - 1 // nums2的最大值
  • 设置最终要发挥的结果
// 最终结果
  let res = new Array(len).fill(0)

步骤三

排序数组,判断 nums2 的最小值 和 nums1当前节点的最小值

  • if(newNums1[i] > nums2[newNums2[left]])如果nums1 的最小值 大于 nums2 的最小值,就安排题目进行比赛
  • 否则,就让他和 nums2 的最大值进行比赛
if(newNums1[i] > nums2[newNums2[left]]){
  res[newNums2[left]] = newNums1[i]
  ++left
}else{
  res[newNums2[right]] = newNums1[i]
  --right
}

完整代码

var advantageCount = function (nums1, nums2) {
  // 数组长度
  let len = nums1.length
  // 排序 nums1 获得 从小到大的 数组
  let newNums1 = nums1.sort((i, j) => i - j)
  // nums2的键值对索引
  // 获取后 对 索引进行排序 获得 nums2 从小到大的 排序键值索引
  let newNums2 = new Array(len).fill().map((value, key) => key).sort((i, j) => nums2[i] - nums2[j])
  // 然后我们需要获取左右两个节点
  // 左右两个节点 是为了进行比对的时候 放置数据的位置用
  let left = 0 // nums2的最小值
  let right = len - 1 // nums的最大值
  // 最终结果
  let res = new Array(len).fill(0)
  // 遍历
  for(let i = 0; i < len; ++i) {
    // 如果 我们排序好的数组1的最小值 大于 nums2 的最小值
    // 那么就让他们进行比赛 然后 最小值增加
    // 如果小于 就用下等马 去 比上等马
    if(newNums1[i] > nums2[newNums2[left]]){
      res[newNums2[left]] = newNums1[i]
      ++left
    }else{
      res[newNums2[right]] = newNums1[i]
      --right
    }
  }
  return res
};