《LeetCode之每日一题》:146.错误的集合
Posted 是七喜呀!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:146.错误的集合相关的知识,希望对你有一定的参考价值。
题目链接: 错误的集合
有关题目
集合 s 包含从 1 到 n 的整数。
不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,
导致集合 丢失了一个数字 并且 有一个数字重复 。
给定一个数组 nums 代表了集合 S 发生错误后的结果。
请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:
输入:nums = [1,2,2,4]
输出:[2,3]
示例 2:
输入:nums = [1,1]
输出:[1,2]
提示:
2 <= nums.length <= 10^4
1 <= nums[i] <= 10^4
题解
法一:排序
参考官方题解
思路:
先排序,使用变量pre记录前一个数字,cur记录当前数字
通过观察我们可以发现,
①缺失元素在下标为1 ~ n - 1时,必定存在cur - pre = 2;
②下标为1 或 n - 1,我们特殊判断
返回值第一个值我们存放重复数字,第二个值我们存放缺失数字
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
int n = nums.size();
vector<int> ans(2);
sort(nums.begin(), nums.end());
int pre = 0;
for (int i = 0; i < n; ++i){
int cur = nums[i];
if (pre == cur){
ans[0] = cur;//存放的重复的数字
} else if (cur - pre > 1){
ans[1] = pre + 1;
}
pre = cur;
}
if (nums[n - 1] != n){
ans[1] = n;
}
return ans;
}
};
法二:哈希计数
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
int n = nums.size();
unordered_map<int, int> mp;
vector<int> ans(2, 0);
for (int i = 0; i < n; ++i){
//for (auto& num : nums)
++mp[nums[i]];
}
for (int i = 1; i <= n; ++i){
if (mp[i] == 0){
ans[1] = i;
}
if (mp[i] == 2){
ans[0] = i;
}
}
return ans;
}
};
法三:位运算
参考官方题解
思路:
①类比题目找到1 ~ n中缺失的一个数字,我们自然而然会想到
数组中增加1 ~ n中全部的数字,并进行异或运算,得到xorSum。
②找出数组中两个出现奇数次的数字,其他出现偶数次数字,
通过lowBit = xorSum & (- xorSum) 找出最低不同二进制位,得出答案
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
int n = nums.size();
int xorSum = 0;
for (auto& num : nums){
xorSum ^= num;
}
for (int i = 1; i <= n; ++i){
xorSum ^= i;
}
int lowBit = xorSum - (xorSum & (xorSum - 1));//xorSum & (-xorSum)
int num1 = 0, num2 = 0;
for (auto& num : nums){
if ((lowBit & num) == 0){//注意lowBit是拿到最低二进制位的 1,不一定表示 1
num1 ^= num;
} else {
num2 ^= num;
}
}
for (int i = 1; i <= n; ++i){
if ((lowBit & i) == 0){
num1 ^= i;
} else {
num2 ^= i;
}
}
for (auto& num : nums){
if (num == num1){
return vector<int>{num1, num2};
}
}
return vector<int> {num2, num1};
}
};
法四:原地置换
参考官方题解评论区Jeff Wong
思路:
①数组中元素为1 ~ n,且有重复元素,故我们可以采用映射下标并标记为负数的方式找出重复元素ans[0]
②缺失数字,在映射下标的过程结束,所对应的数组值一定为正数,(当然过程中会存在负数的状态)
从找规律的角度理解,我们给出下面两组例子:
示例一;
//2 3 3 4映射下标并标记为负数过程结束,数组中元素变为
//2 -3 -3 -4,找规律发现,在该下标满足i + 1 != ans[0],且对应元素 > 0情况,则下标为 i 的元素 加 1即为缺失元素
示例二:
//1 2 2 4映射下标并标记为负数的过程结束,数组中元素变为
//-1 2 2 -4 找规律发现,在该下标满足 i + 1 != ans[0],
且 nums[i] > 情况下,则下标为 i 的元素 加 1 则为缺失数字
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
int n = nums.size();
vector<int> ans(2);
for (int i = 0; i < n; ++i){
int idx = abs(nums[i]) - 1;
if (nums[idx] < 0){//找出重复的元素
ans[0] = idx + 1;
}
nums[idx] = -nums[idx];
}
for (int i = 0; i < n; ++i){
if (nums[i] > 0 && i + 1 != ans[0]){//缺失的元素,下标映射一定为
ans[1] = i + 1;
}
}
return ans;
}
};
时间复杂度:O(n),找出重复数字O(n),找出缺失数字O(n),故总的时间复杂度O(n)
空间复杂度:O(1)
以上是关于《LeetCode之每日一题》:146.错误的集合的主要内容,如果未能解决你的问题,请参考以下文章