[JavaScript / leetcode] 954. 二倍数对数组

174 阅读1分钟

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

每日刷题 2022.10.02

题目

  • 给定一个长度为偶数的整数数组 arr,只有对 arr 进行重组后可以满足 “对于每个 0 <= i < len(arr) / 2,都有 arr[2 * i + 1] = 2 * arr[2 * i]” 时,返回 true;否则,返回 false。

示例

输入: arr = [3,1,3,6]
输出: false

解题思路

拓展

  • 自定义排序sort(): 因为我们需要找到符合要求的数对,且arr[i] -> 2 * arr[i],因此需要按照数的大小进行排序,非递减。

分析

  • 根据题意可知:
    • 所给的arr长度为偶数
    • 可对数组重组,对于每个0 <= i < len(arr) / 2,需要满足arr[2 * i + 1] = 2 * arr[2 * i].
      • 假设:当前的数组长度为4(偶数),那么对于每一个0 <= i < 2,也就是数组长度为4时,数组中的arr[1] = 2 * arr[0]、arr[3] = 2 * arr[2]
      • 由此可见:只需要保证每个数对中:一个数是另外一个数的2倍即可。
    • 总结:给你一个数组arr,判断数组是否能拆分成每个都符合要求的数对。因为不需要输出重组后的数组,因此不论如何排序均可。

实现

  • 不论是从小到大还是从大到小都可以,这里我选择从小到大,因为这样就只需要计算乘法,可以避开/2的情况
  • 预处理:将数组排序,需要(自定义)按照数字的绝对值来进行排序,数值小的放在数值大的前面,因为需要将第一个数作为基准,去查找其2倍的数,是否存在。
  • 使用map集合:记录数组中每个数值出现的次数。
  • for循环遍历的每一个数值,都是作为基准出现的。
    • 预判断,如果当前的基准出现的次数已经全部被匹配完成,为0,那么就直接跳过,查找下一个基准
    • 从下标0开始,通过map查找其在数组中出现过的次数,去查找和其匹配的2倍的数值是否存在;
    • 如果存在,还需要判断2倍的数值的出现次数是否大于等于当前基准的出现次数.
      • 如果大于等于,则说明基准出现的次数全部找到匹配的,则将其置0
      • 如果小于,则表示基准出现的次数不能够全部被匹配上,那么此时就应该返回false
    • 如果不存在,则表示找不到匹配的,此时就应该返回false
  • !!注意!!:数组中如果存在0的话,会出现错误
    • 因为在map集合中00会被当做一个数值来进行计算,自己减去自己并不能算匹配成功
    • 因此,需要通过map集合中存储的0数值的个数来进行判断
      • 奇数:没有办法完全匹配,返回false
      • 偶数:可以自己完成匹配,查找下一个基准

代码

/**
 * @param {number[]} arr
 * @return {boolean}
 */
var canReorderDoubled = function(arr) {
  // 排序
  let len = arr.length, map = new Map();
  arr.sort((a, b) => {
    return Math.abs(a) - Math.abs(b);
  });
  // console.log(arr)
  for(let i = 0; i < len; i++) {
    map.set(arr[i], (map.get(arr[i]) || 0) + 1)
  }
  // console.log(map)
  let set = new Set(arr)
  // console.log(set)
  for(let i = 0; i < len - 1; i++) {
    if(arr[i] == 0){
      if (map.get(0) % 2 == 0) continue;
      else return false;
    }
    if(map.get(arr[i]) == 0) continue;
    if(map.has(arr[i] * 2)){
      if(map.get(arr[i] * 2) >= map.get(arr[i])){
        map.set(arr[i] * 2, map.get(arr[i] * 2) - map.get(arr[i]))
        map.set(arr[i], 0);
      }else {
        return false;
      }
    }else {
      return false;
    }
  }
  return true;
};