645.错误的集合 | 448.找到所有数组中消失的数字 |面试题17.19.消失的两个数字

645. 错误的集合

labuladong 题解思路

集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。

给定一个数组 nums 代表了集合 S 发生错误后的结果。

请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

示例 1:

输入:nums = [1,2,2,4]
输出:[2,3]

示例 2:

输入:nums = [1,1]
输出:[1,2]

思路一:映射关系 

//映射的思路,将nums中的数字同下标建立映射关系
class Solution {
public:
    vector<int> findErrorNums(vector<int>& nums) {
        int n=nums.size();
        int dup=-1;
        for(int i=0;i<n;i++)
        {
            int index=abs(nums[i])-1;
            if(nums[index]<0)
            {
                dup=abs(nums[i]);
            }
            else
            {
                nums[index]*=-1;
            }
        }
        int missing=-1;
        for(int i=0;i<n;i++)
        {
            if(nums[i]>0)
            {
                missing=i+1;
            }
        }
        return vector<int>({dup,missing});
    }
};

思路二:数学法 

//数学法
//先排序,排序后的数组中,相邻两个数字相等的就是重复的那个数字
//丢失的那个数字=重复的那个数字-(nums数组中所有数字之和-从1~n的整数之和)
//例如:nums = [1,2,2,4],lose=2-(9-10)=3
class Solution {
public:
    vector<int> findErrorNums(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<int> res;
        for(int i=1;i<nums.size();i++)
        {
            if(nums[i]==nums[i-1])
            {
                res.push_back(nums[i]);
            }
        }
        int sum=(1+nums.size())*nums.size()/2;
        int lose=res[0]-(accumulate(nums.begin(),nums.end(),0)-sum);
        res.push_back(lose);
        return res;
    }
};

 

448. 找到所有数组中消失的数字

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]

示例 2:

输入:nums = [1,1]
输出:[2]

思路:
可以用哈希表存每一个元素,最后遍历哈希表,看缺少1~n之间的哪个数。
上述做法空间复杂度为O(N),我们可以直接让nums充当哈希表,原地修改。
由于nums的数字范围均在[1,n]中,我们可以利用这一范围之外的数字,来表达“是否存在”的含义。
具体来说,遍历nums,每遇到一个数x,就让 nums[x-1]增加 n。由于nums中所有数均在 [1,n]中,增加以后,这些数必然大于n。最后我们遍历nums,若nums[i]未大于n,就说明没有遇到过数 i+1,这样我们就找到了缺失的数字。
注意,当我们遍历到某个位置时,其中的数可能已经被增加过,因此需要对n取模来还原出它本来的值。

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        int n=nums.size();
        vector<int> ans;
        for(int i=0;i<n;i++)
        {
            int index=(nums[i]-1)%n;
            nums[index]+=n;
        }
        for(int i=0;i<n;i++)
        {
            if(nums[i]<=n)
            {
                ans.push_back(i+1);
            }
        }
        return ans;
    }
};

 

面试题 17.19. 消失的两个数字

给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?

以任意顺序返回这两个数字均可。

示例 1:

输入: [1]
输出: [2,3]

示例 2:

输入: [2,3]
输出: [1,4]

思路:数学法 

因为数组nums中的数字不重复,所以缺失的两数之和除以二的值" mid "一定在缺失的两数之间(比小的大,比大的小),再计算1~mid的总和,减去nums中在1~mid之间已经存在的整数,那么剩下的肯定就是缺失的两数中左边的那个。
例如:nums=[1,2,3,5,6,7,9]
缺失两数之和为12 (4+8),除以2是6 (4和8在6的一左一右),1 + 2 + ... + 6 = 21,减去nums中已经存在的6左边的数,即1+2+3+5+6=17,得4(因为这里面少加了4嘛),12-4=8得到另一个数。

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int n=nums.size()+2;//数组原本的长度
        int sum=(1+n)*n/2;//数组原本的元素和(1~n的整数和)
        int missTwoSum=sum-accumulate(nums.begin(),nums.end(),0);//缺失的两数之和
        int mid=missTwoSum/2;//缺失的两数之和/2
        int midSum=(1+mid)*mid/2;//1~mid的整数和
        for(int v:nums)
        {
            if(v<=mid)
            {
                midSum-=v;//减去位于mid左边的nums中的数,得到缺失的两数中左边的那个
            }
        }
        return {midSum,missTwoSum-midSum};//返回缺失的两数
    }
};

ps:还有一道类似的题目,可以采用异或运算的方法得到缺失的值

268. 丢失的数字 - 力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值