2122-还原原数组
Alice 有一个下标从 0 开始的数组 arr
,由 n
个正整数组成。她会选择一个任意的 正整数k
并按下述方式创建两个下标从 0 开始的新整数数组 lower
和 higher
:
- 对每个满足
0 <= i < n
的下标i
,lower[i] = arr[i] - k
- 对每个满足
0 <= i < n
的下标i
,higher[i] = arr[i] + k
不幸地是,Alice 丢失了全部三个数组。但是,她记住了在数组 lower
和 higher
中出现的整数,但不知道每个整数属于哪个数组。请你帮助
Alice 还原原数组。
给你一个由 2n 个整数组成的整数数组 nums
,其中 恰好 n
个整数出现在 lower
,剩下的出现在 higher
,还原并返回 原数组 arr
。如果出现答案不唯一的情况,返回 任一 有效数组。
注意: 生成的测试用例保证存在 至少一个 有效数组 arr
。
示例 1:
**输入:** nums = [2,10,6,4,8,12]
**输出:** [3,7,11]
**解释:**
如果 arr = [3,7,11] 且 k = 1 ,那么 lower = [2,6,10] 且 higher = [4,8,12] 。
组合 lower 和 higher 得到 [2,6,10,4,8,12] ,这是 nums 的一个排列。
另一个有效的数组是 arr = [5,7,9] 且 k = 3 。在这种情况下,lower = [2,4,6] 且 higher = [8,10,12] 。
示例 2:
**输入:** nums = [1,1,3,3]
**输出:** [2,2]
**解释:**
如果 arr = [2,2] 且 k = 1 ,那么 lower = [1,1] 且 higher = [3,3] 。
组合 lower 和 higher 得到 [1,1,3,3] ,这是 nums 的一个排列。
注意,数组不能是 [1,3] ,因为在这种情况下,获得 [1,1,3,3] 唯一可行的方案是 k = 0 。
这种方案是无效的,k 必须是一个正整数。
示例 3:
**输入:** nums = [5,435]
**输出:** [220]
**解释:**
唯一可行的组合是 arr = [220] 且 k = 215 。在这种情况下,lower = [5] 且 higher = [435] 。
提示:
2 * n == nums.length
1 <= n <= 1000
1 <= nums[i] <= 109
- 生成的测试用例保证存在 至少一个 有效数组
arr
方法一:枚举 + 双指针
思路与算法
我们首先将数组 arr 按照升序排序。
根据题目的要求,arr 可以拆分成两个长度为 n 的数组,并且对于元素较小的那个数组 lower 中的每一个元素,在元素较大的那个数组 upper 中都唯一对应着一个恰好比它大 2k 的元素。当 arr 有序时,最小的那个元素 arr}[0] 一定是属于 lower 的,这样一来,我们就可以枚举 arr 中剩余的 2n-1 个元素,分别作为 arr}[0] 在 upper 中唯一对应的元素,并判断剩余元素的合法性。
假设 arr}[0] 对应着 arr}[i],那么我们就可以得到 k 的值:
k = arr[i] - arr[0]}{2}
由于 k 是整数并且 k > 0,因此我们必须要求 arr}[0] 与 arr}[i] 同奇偶,并且它们的值不相等。在求出 k 的值后,我们可以使用双指针的方法判断剩余的元素是否满足要求:
我们用两个指针 left 和 right 分别指向 0 和 i,其中 left 的作用的是每次找到剩余元素中最小的那一个,它一定是属于 lower 的;right 的作用是指向恰好等于 arr}[\textit{left}] + 2k 的元素,并且将 left 和 right 对应起来;
我们还需要一个长度为 2n 的数组,记录每一个元素是否被使用过。如果指针到达了已经被使用过的元素,则无需处理当前元素;
由于我们还剩余 2n-2 个元素,因此需要进行 n-1 次对应操作。每一次操作中,我们首先向右移动 left 指针,直到指针指向的元素没有被使用过,此时 arr}[\textit{left}] 就是最小的未被使用过的元素,它一定属于 lower。随后我们向右移动 right 指针,直到 arr}[\textit{left}] + 2k = \textit{arr}[\textit{right}] 成立并且 arr 未被使用过。如果不存在这样的元素,那么我们就可以断定剩余的元素无法满足要求;否则,我们就将 arr}[\textit{left}] 和 arr}[\textit{right}] 标记为「使用过」,并将 arr}[\textit{left}] + k(或 arr}[\textit{right}] - k)加入答案。
由于题目保证了「生成的测试用例保证存在至少一个有效数组」,因此上述双指针的方法也一定能找到一个正确的答案。
代码
1 | class Solution { |
1 | class Solution: |
复杂度分析
时间复杂度:O(n^2)。排序需要的时间为 O(n \log n)。枚举 arr}[i] 需要的时间为 O(n),双指针判断需要的时间为 O(n),这一部分的总时间为 O(n^2)。
空间复杂度:O(n)。排序需要 O(\log n) 的栈空间。在每一次枚举 arr}[i] 的过程中,我们需要 O(n) 的空间记录每个元素是否被使用过,但枚举之间是互相独立的,因此一共也只需要 O(n) 的空间。