ttps://leetcode-cn.com/problems/array-of-doubled-pairs/
难度:中等
给定一个长度为偶数的整数数组 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
方法一、Hash + 排序
/**
* Hash做法 + 排序
* @param arr
* @return
*/
public static boolean canReorderDoubled(int[] arr) {
// 需要排序,从小打大
Arrays.sort(arr);
// key 存储值, value存储个数
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < arr.length; i++) {
// 值是0,直接舍掉
if (arr[i] == 0) {
continue;
}
map.put(arr[i], map.getOrDefault(arr[i], 0) + 1);
// 注意条件。其梳理必须大于0
if (map.containsKey(2 * arr[i]) && map.get(2 * arr[i]) > 0) {
// 存在 2 倍的 值
map.put(2 * arr[i], map.get(2 * arr[i]) - 1);
map.put(arr[i], map.get(arr[i]) - 1);
} else if (arr[i] % 2 == 0 && map.containsKey(arr[i] / 2) && map.get(arr[i] / 2) > 0) {
// 存在 1 / 2 的值
map.put(arr[i] / 2, map.get(arr[i] / 2) - 1);
map.put(arr[i], map.get(arr[i]) - 1);
}
}
for (Integer value : map.values()) {
if (value != 0) {
return false;
}
}
return true;
}
方法二、回溯算法
/**
* 回溯算法,超时了
* 讲这些组合全部排列出来,找出满足条件的,直接返回
*
* 但是由于 0 <= arr.length <= 3 * 104 数组的长度太大了。结果超时了
*
* @param arr
* @return
*/
public boolean canReorderDoubled2(int[] arr) {
Arrays.sort(arr);
List<Integer> tmp = new ArrayList<>();
// 保证当前数,不会重复出现
boolean[] visited = new boolean[arr.length];
return backTrace(arr, visited, tmp);
}
boolean backTrace(int[] arr, boolean[] visited, List<Integer> tmp) {
if (tmp.size() == arr.length) {
return true;
}
for (int i = 0; i < arr.length; i++) {
int num = arr[i];
if (visited[i] || (tmp.size() > 0 && tmp.size() % 2 != 0 && 2 * tmp.get(tmp.size() - 1) != num)) {
continue;
}
tmp.add(num);
visited[i] = true;
boolean res = backTrace(arr, visited, tmp);
if (res) {
return true;
}
visited[i] = false;
tmp.remove(tmp.size() - 1);
}
return false;
}
官方答案:
class Solution {
public boolean canReorderDoubled(int[] arr) {
Map<Integer, Integer> cnt = new HashMap<Integer, Integer>();
for (int x : arr) {
cnt.put(x, cnt.getOrDefault(x, 0) + 1);
}
if (cnt.getOrDefault(0, 0) % 2 != 0) {
return false;
}
List<Integer> vals = new ArrayList<Integer>();
for (int x : cnt.keySet()) {
vals.add(x);
}
Collections.sort(vals, (a, b) -> Math.abs(a) - Math.abs(b));
for (int x : vals) {
if (cnt.getOrDefault(2 * x, 0) < cnt.get(x)) { // 无法找到足够的 2x 与 x 配对
return false;
}
cnt.put(2 * x, cnt.getOrDefault(2 * x, 0) - cnt.get(x));
}
return true;
}
}
my_java_algorithm/Top0954_middle.java at main · liufei96/my_java_algorithm (github.com)
总结:
- 下次在遇到这种题目,先看下数组的长度,对于这种范围的,用回溯算法,很明显是会超时。