一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
前言
今天的题目为中等,主要是需要利用哈希表去统计每一个数出现的次数,哈希表用于这种统计数组中元素出现的次数还是挺常见的。
每日一题
今天的题目是 954. 二倍数对数组,难度为中等
- 给定一个长度为偶数的整数数组 arr,只有对 arr 进行重组后可以满足 “对于每个 0 <= i < len(arr) / 2,都有 arr[2 * i + 1] = 2 * arr[2 * i]” 时,返回 true;否则,返回 false。
示例 1:
输入:arr = [3,1,3,6]
输出:false
示例 2:
输入:arr = [2,1,2,6]
输出:false
示例 3:
输入:arr = [4,-2,2,-4]
输出:true
解释:可以用 [-2,-4] 和 [2,4] 这两组组成 [-2,-4,2,4] 或是 [2,4,-2,-4]
提示:
- 0 <= arr.length <= 3 * 104
- arr.length 是偶数
- -105 <= arr[i] <= 105
题解
哈希表
题目需要我们去统计给的数组是否能评分成 n/2 个组合,每一个组合刚好是两个两倍关系大小的数,那么根据这个要求,我们就需要去统计出现的每一个数的数量,因为同样的一个数,它是可以出现多次的,也就是说不能够简单的循环去遍历判断一个数是否存在刚好是它两倍大的数,因为可能两倍大的那个数有两个,或者这个数存在两个,这都是不符合题目要求的,题目要求是要刚好成对,那么我们就需要去统计每个数出现的次数。
说到统计数组中元素的数量,最常用的应该就是 map 哈希表的了吧,将数组的元素都存入哈希表,出现一次就映射为1,两次就为2,以此增加,这样最后就能够得到一个key为数组元素,val为元素出现次数的map表。
那么map表获得了之后,我们就可以去遍历这个map表,当然我们要去寻找两倍大的数,这里就需要注意一个点,我们需要从小到大去获取值,因为一个最小值,指挥有着对应的大两倍的数,但是这个大两倍的数,有可能还存在着大两倍的数,所以作为中间值可能会是两端的个数相加,比如 [1,2,2,4] 也是满足题目要求的,但是你不能单纯的只是判断,1 和 2 的个数对不上就返回 false,必须要将 2 减去 1 的个数,后面 2 也需要去做判断,寻找是否存在大于它两倍的数。
-
我们需要将所有的元素存入一个 map 表,用来统计个数。
-
循环遍历map表的每一个元素。
-
循环的时候需要去判断当前的值的个数是否会大于比它大两倍的数,大于的话就会返回false
-
判断过后 大两倍的那个数 的个数要将去当前这个数的个数。
-
到最后都没有返回false的话,就说明都满足要求,返回true
/**
* @param {number[]} arr
* @return {boolean}
*/
var canReorderDoubled = function(arr) {
const map = new Map();
for (const x of arr) {
map.set(x, (map.get(x) || 0) + 1);
}
const numberList = [];
for (const x of map.keys()) {
numberList.push(x);
}
numberList.sort((a, b) => Math.abs(a) - Math.abs(b));
for (const x of numberList) {
if(map.get(x) == 0) continue
if ((map.get(2 * x) || 0) < map.get(x)) {
return false;
}
map.set(2 * x, (map.get(2 * x) || 0) - map.get(x));
}
return true;
};