难度:中等
目录
1、代码实现
一、问题描述
这里直接采用LeetCode上面的问题描述。
给定一个长度为偶数的整数数组 arr,只有对 arr 进行重组后可以满足 “对于每个 0 <= i < len(arr) / 2,都有 arr[2 * i + 1] = 2 * arr[2 * i]” 时,返回 true;否则,返回 false。
下面给出示例:
提示:
0 <= arr.length <= 3 * 104
arr.length
是偶数-105 <= arr[i] <= 105
二、解题思路
1、思路
看题目,该题就是一个数进行配对的题目,每个数都要配对一个两倍于自己的数,直至全部配对之后即可返回 true, 否则直接返回 false。
这里我们可以采用排序加 哈希表进行计数。排序的操作是为了让数组有序,这样大的负数可以配对两倍自己的小负数,大的整数可以配对二分之一自己的小整数。这是重点。
遍历一遍 arr ,将小的负数存储进哈希表并计数,大的负数用来匹配 2 倍自身的小负数,匹配成功的话将小负数的计数器 --;匹配失败将自己存入到哈希表中并且计数器 ++。对于正数来说还需要进行一个判断,因为是 int 型的数,那么奇数是不可能的做到 大于 0 且为正数的奇数:item = 2*(item/2)这是不相等的,因此只要判断大偶数是否存在自己一半的数是否存在哈希表之中,存在的话将其计数器 --,不存在则将该数存入哈希表并且计数器 ++。
最后遍历哈希表,看哈希表中的被统计的数的计数器是否有不为 0 的情况,有的话直接返回false,因为没有完全配对,没有最后则返回 true。
2、极端情况判断
这里的 0 是一个特殊情况。
3、极端情况解决
当存在 0 的时候 0 将被累计并且统计到计数器之中,最后遍历哈希表的时候判断 0 的个数是否是偶数即可,是偶数则说明可以一一配对成功,否则不可以。
三、解题
1、代码实现
class Solution {
public:
bool canReorderDoubled(vector<int>& arr) {
unordered_map<int,int> hash;
//这里排序过后使得大的负数接近0,小的正数接近于0
sort(arr.begin(),arr.end());
for(auto& i: arr) {
//如果 i 是偶数 并且大于0 并且哈希表中有其一半的数存在,将 i/2 计数进行减一
//因为是排过序的 所以只能是后面大的正整数查看是否有自己 1/2 的正整数(这点很重要)
//这里进行是否是偶数的判断是因为 奇数是不可能 满足 整型的 i = 2倍的 i/2的
if(!(i%2) and i > 0 and hash[i/2]){
hash[i/2]--;
}
//如果小于 0 那么 小的负数是不会有比自己还小的两倍关系的负数
//因此这里进行 * 2,将大的负数缩小两倍查看之前是否存储过 小两倍的负数 有的话计数器--
else if (i < 0 and hash[i*2]){
hash[i*2]--;
}
else {
hash[i]++;
}
}
for(auto& item : hash){
//判断 0 的个数是否是偶数,是的话继续,否则return false
if(!item.first){
if(!(item.second % 2)){
continue;
}
return false;
}
//判断该数的 计数器是否清零 若没有清零则说明没有一一配对 return false
if(item.second){
return false;
}
}
//全部配对 return true
return true;
}
};
2、时间复杂度 and 空间复杂度
时间复杂度:
空间复杂度: