Medium
题目描述
给定一个长度为偶数的整数数组 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]。
提示:
2 <= arr.length <= 3 * 10^4arr.length是偶数-10^5 <= arr[i] <= 10^5
解题思路
解题思路
这道题的核心是要判断数组中的元素能否两两配对,形成 (x, 2x) 的形式。
方法分析:
哈希表计数法:统计每个数字的出现次数,然后按照绝对值从小到大的顺序进行配对。对于每个数字
x,尝试与2x配对。排序贪心法:先对数组排序,然后依次处理每个元素,优先与其二倍值配对。
推荐解法:哈希表计数法
核心思想是:
- 使用哈希表统计每个数字的出现次数
- 按照数字绝对值从小到大的顺序处理(避免处理顺序问题)
- 对于每个数字
x,如果它还有剩余,就尝试与2x配对 - 特别处理
0的情况:0只能与0配对,所以0的个数必须是偶数
这种方法的优势是避免了复杂的排序逻辑,特别是在处理负数时更加直观。
时间复杂度:遍历数组统计次数 O(n),处理配对 O(n),总体 O(n) 空间复杂度:哈希表存储 O(n)
代码实现
class Solution {
public:
bool canReorderDoubled(vector<int>& arr) {
unordered_map<int, int> count;
for (int x : arr) {
count[x]++;
}
vector<int> keys;
for (auto& p : count) {
keys.push_back(p.first);
}
sort(keys.begin(), keys.end(), [](int a, int b) {
return abs(a) < abs(b);
});
for (int x : keys) {
if (count[x] == 0) continue;
if (x == 0) {
if (count[x] % 2 != 0) return false;
count[x] = 0;
} else {
if (count[2 * x] < count[x]) return false;
count[2 * x] -= count[x];
count[x] = 0;
}
}
return true;
}
};
class Solution:
def canReorderDoubled(self, arr: List[int]) -> bool:
from collections import Counter
count = Counter(arr)
# 按绝对值排序
for x in sorted(count, key=abs):
if count[x] == 0:
continue
if x == 0:
if count[x] % 2 != 0:
return False
count[x] = 0
else:
if count[2 * x] < count[x]:
return False
count[2 * x] -= count[x]
count[x] = 0
return True
public class Solution {
public bool CanReorderDoubled(int[] arr) {
var count = new Dictionary<int, int>();
foreach (int x in arr) {
count[x] = count.GetValueOrDefault(x, 0) + 1;
}
var keys = new List<int>(count.Keys);
keys.Sort((a, b) => Math.Abs(a).CompareTo(Math.Abs(b)));
foreach (int x in keys) {
if (count[x] == 0) continue;
if (x == 0) {
if (count[x] % 2 != 0) return false;
count[x] = 0;
} else {
if (!count.ContainsKey(2 * x) || count[2 * x] < count[x]) {
return false;
}
count[2 * x] -= count[x];
count[x] = 0;
}
}
return true;
}
}
var canReorderDoubled = function(arr) {
const count = new Map();
for (const num of arr) {
count.set(num, (count.get(num) || 0) + 1);
}
const keys = Array.from(count.keys()).sort((a, b) => Math.abs(a) - Math.abs(b));
for (const num of keys) {
if (count.get(num) > 0) {
const double = num * 2;
const numCount = count.get(num);
const doubleCount = count.get(double) || 0;
if (doubleCount < numCount) {
return false;
}
count.set(double, doubleCount - numCount);
}
}
return true;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n log n) | 主要由排序操作决定,其中 n 为数组长度 |
| 空间复杂度 | O(n) | 哈希表存储所有元素的计数信息 |