leetcode
leetcode 1751 ~ 1800
从双倍数组中还原原数组

从双倍数组中还原原数组

难度:

标签:

题目描述

代码结果

运行时间: 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的数量是否为偶数?
因为题目的目标是从一个包含双倍数的数组中还原出原数组。原数组中的每个元素都必须在双倍数组中以其原始数值和两倍数值的形式出现。对于0来说,其双倍也是0,因此在双倍数组中,0的数量必须是偶数,这样才能确保每个0都可以与另一个0配对,形成原始数组中的一个0。如果0的数量是奇数,则无法完全配对,意味着无法还原成有效的原数组。
🦆
题解中提到如果数组长度不是偶数则直接返回空数组,这个假设的逻辑依据是什么?
如果输入数组changed的长度不是偶数,那么不能完全由原数组和其对应的双倍数组组成,因为原数组中每个元素和其对应的双倍数都应该出现两次。一个奇数长度的数组无法被完全分成这样的成对形式,因此无法从中完整地还原出原数组。这是基于题目要求,每个原始元素及其双倍必须出现,从而保证数组长度必须是偶数。
🦆
对于数组中的最大值mx,为何从mx开始向下遍历直至0,而不是从0向上遍历?
从最大值mx开始向下遍历直至0的原因是这样可以直接判断较大数的双倍关系是否成立,并且减少错误匹配的可能性。如果从0开始向上遍历,可能会先处理较小的数,而这些小数可能是较大数的一半,这样在遇到较大数时,它们的计数可能已经被错误地减少,从而导致错误的匹配。从大到小遍历可以保证当处理一个数时,所有可能的双倍数都已经被先前处理过,从而保持正确的计数和匹配。
🦆
在处理非零元素时,如果当前元素i是奇数直接返回空数组的逻辑依据是什么?
在处理非零元素时,如果当前元素i是奇数,则返回空数组的逻辑是基于无法找到一个有效的原始数组元素m使得m的双倍等于i。题目要求能够从changed数组中找出原数组,使得每个元素的双倍也在changed数组中。对于奇数i,无法通过将任何整数m乘以2得到奇数(因为整数乘以2总是偶数),因此如果changed数组中包含奇数,则说明无法将该数组还原为每个元素及其双倍的形式,即无法找到一个合理的原数组。

相关问题