LeetCode 2122. 还原原数组 思维+双指针
LeetCode 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
。
样例
输入: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]。
输入: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 必须是一个正整数。
输入:nums = [5,435]
输出:[220]
解释:
唯一可行的组合是 arr = [220] 且 k = 215 。在这种情况下,lower = [5] 且 higher = [435] 。
算法
(暴力枚举,双指针) \(O(n^2)\)
-
首先将将给定的数组从小到达排序,可以断定\(nums(0)\)为\(arr [0] - k\),
-
枚举 \(i\),假设当前\(nums(i)\)为\(arr [0] + k\),其中 \(nums(i)\) 与 \(nums(0)\) 的差值作为 \(2k\),然后代入检验。
-
检验给定的差值 \(2k\) 时,可以采用双指针的方法,如果发现没有找到与当前位置匹配的数字,则返回失败。
时间复杂度
- 最坏情况需要枚举 \(O(n)\) 次,每次枚举需要 \(O(n)\) 的时间验证,故总时间复杂度为 \(O(n^2)\)。
空间复杂度
- 需要 \(O(n)\) 的额外空间存储排序的系统栈,以及验证过程中的临时数组。
C++ 代码
class Solution {
public:
vector<int> res;
bool check(vector<int>& nums, int k){
res.clear();
vector<bool> st(nums.size(), false);
for(int i = 0, j = 1; i < nums.size(); i++){
if(st[i] == true) continue;
while(j < nums.size() && nums[j] - nums[i] < k){
j++;
}
if(j == nums.size() || nums[j] - nums[i] != k) return false;
res.push_back(nums[i] + k / 2);
st[j] = true;
j++;
}
return true;
}
vector<int> recoverArray(vector<int>& nums) {
sort(nums.begin(), nums.end());
int k = 0;
for(int i = 1; i < nums.size(); i++){
k = nums[i] - nums[0];
if(k == 0 || (k & 1)) continue;
if(check(nums, k)){
break;
}
}
return res;
}
};