leetcode
leetcode 1851 ~ 1900
还原原数组

还原原数组

难度:

标签:

题目描述

代码结果

运行时间: 100 ms, 内存: 16.5 MB


import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Using Java Streams to process the array and find the original array `arr`.
 * The logic is the same but uses more functional programming style.
 */
public class Solution {
    public int[] recoverArray(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length / 2;
        for (int i = 1; i < nums.length; i++) {
            int k = (nums[i] - nums[0]) / 2;
            if (k > 0 && (nums[i] - nums[0]) % 2 == 0) {
                Set<Integer> lowerSet = new HashSet<>();
                Set<Integer> higherSet = Arrays.stream(nums).boxed().collect(Collectors.toSet());
                for (int num : nums) {
                    if (!lowerSet.contains(num - k)) {
                        lowerSet.add(num);
                    } else {
                        higherSet.remove(num);
                    }
                }
                if (lowerSet.size() == n && higherSet.size() == n) {
                    int[] result = lowerSet.stream().mapToInt(num -> num + k).toArray();
                    return result;
                }
            }
        }
        return new int[0];
    }
}

解释

方法:

首先,对输入数组 nums 进行排序。然后遍历数组,尝试找到可能的差值 d = 2k,其中 k 是原数组 arr 和 lower 或 higher 数组之间的差值。这个差值 d 必须是偶数,因为 k 需要是整数。对于每一个可能的 d,尝试将 nums 分为两组,一组表示 lower,一组表示 higher。使用一个集合 vis 来记录已经被使用的 higher 的索引,确保每个元素只被使用一次。通过遍历检查是否可以完全匹配 lower 和 higher 数组。如果成功匹配,说明已经找到了原数组 arr。此算法尝试所有可能的 d,直到找到一个有效的结果。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在尝试找到可能的差值 d 时,你是如何确定 d 必须是偶数的?
在这个问题中,我们需要将数组 nums 分解为两组 lower 和 higher,其中 higher 中的每一个元素都比对应的 lower 中的元素大 d,且这个差值 d 等于 2k。因此,为了使 k 为一个整数,d 必须是偶数。这是因为任何偶数除以 2 的结果都是整数,而如果 d 是奇数,则 d/2 会得到一个分数,不符合 k 为整数的要求。
🦆
为什么在遍历数组时跳过重复元素,即 nums[i] == nums[i - 1] 的情况?
在这种方法中,跳过重复元素是为了防止重复计算相同的差值 d。如果数组中有重复的元素,计算的差值 d 会相同,从而导致算法重复检查相同的 k 值,这样会降低算法效率。此外,重复的元素可能不适合作为分组的起始点,因为它们不会引入新的差值 d,从而可能错过探索新的分组方式。
🦆
在双指针策略中,为什么选择 nums[i] - nums[0] 作为起始的差值 d?这种选择对于找到正确的 k 有什么特别的意义吗?
选择 nums[i] - nums[0] 作为起始的差值 d 是基于将数组的最小元素作为lower组的起始点,这样可以简化问题的复杂度。通过这种方式,我们可以从最小可能的差值开始探索,逐步增大差值,直到找到合适的 k 值。这种方法能够系统地覆盖所有可能的差值,并确保不遗漏任何可能的 k 值。
🦆
算法在检测到 nums[hi] - nums[lo] > d 时选择中断循环,这样的处理是否可能导致漏掉正确的 k 值?
当 nums[hi] - nums[lo] > d 时中断循环是基于这样的假设:已经对 nums 进行了排序,如果在当前 lower 索引 lo 的情况下,没有在 higher 找到匹配的元素,而是找到了一个差值大于 d 的元素,那么对于当前的 d 和 k,正确的分组已经不可能实现。因为随着 lo 的增加,lower 的值会增大,从而使得满足 nums[hi] - nums[lo] = d 的 hi 的值也应该相应地更大或无法找到,因此不会漏掉正确的 k 值。

相关问题