从双倍数组中还原原数组
难度:
标签:
题目描述
代码结果
运行时间: 103 ms, 内存: 32.5 MB
// 题目思路:
// 1. 先将 changed 数组排序。
// 2. 使用流的方式计算每个数字的出现次数。
// 3. 遍历排序后的数组,检查是否存在两倍于该数字的数字,并进行数量匹配。
// 4. 最后,如果所有数量都被正确配对,则返回 original 数组,否则返回空数组。
import java.util.*;
import java.util.stream.Collectors;
public class Solution {
public int[] findOriginalArray(int[] changed) {
if (changed.length % 2 != 0) return new int[0];
Arrays.sort(changed);
Map<Integer, Long> count = Arrays.stream(changed).boxed()
.collect(Collectors.groupingBy(e -> e, Collectors.counting()));
int[] original = new int[changed.length / 2];
int index = 0;
for (int num : changed) {
if (count.get(num) == 0) continue;
if (count.getOrDefault(num * 2, 0L) == 0) return new int[0];
original[index++] = num;
count.put(num, count.get(num) - 1);
count.put(num * 2, count.get(num * 2) - 1);
}
return original;
}
}
解释
方法:
此题解采用了计数排序的思路来解决问题。首先通过最大值创建一个足够大的数组 `li` 用于统计 `changed` 中每个元素的出现次数。首先,如果 `changed` 的长度不是偶数,则直接返回空数组,因为双倍数组的长度必须是偶数。接下来,特别处理 0 的情况,因为 0 的双倍还是 0,需要确保 0 的数量是偶数。然后从最大值开始向下遍历,对于每个 `i`,判断其一半 `i/2` 是否存在于 `li` 中,且数量是否足够。如果足够则将 `i/2` 加入结果数组 `ans` 中相应的次数,并减少 `li[i/2]` 的计数。如果在任何点出现不匹配,则返回空数组。这种方式有效地利用了计数数组来避免排序,从而提高效率。
时间复杂度:
O(n + mx)
空间复杂度:
O(mx)
代码细节讲解
🦆
在处理0的特殊情况时,为什么必须检查0的数量是否为偶数?
▷🦆
题解中提到如果数组长度不是偶数则直接返回空数组,这个假设的逻辑依据是什么?
▷🦆
对于数组中的最大值mx,为何从mx开始向下遍历直至0,而不是从0向上遍历?
▷🦆
在处理非零元素时,如果当前元素i是奇数直接返回空数组的逻辑依据是什么?
▷