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

题目
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。

不算正解,但这很python

def findDisappearedNumbers(nums):
    # 使用set
    return list(set(range(1, len(nums) + 1)) - set(nums))
解法一:
  1. 将数组元素对应为索引的位置加n
  2. 遍历加n后的数组,若数组元素值小于等于n,则说明数组下标值不存在,即消失的数字
  3. 例如:4211->12 6 1 5,则消失的数字是3

cpp:

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        vector<int> res;
        if(nums.empty()) return nums;
        for(int i=0;i<nums.size();i++)
        {
            int index=(nums[i]-1)%nums.size();
            nums[index]+=nums.size();
        }
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]<=nums.size())
                res.push_back(i+1);
        }
        return res;
    }
};
解法二
    # 将所有正数作为数组下标,置对应数组值为负值。那么,仍为正数的位置即为(未出现过)消失的数字。
    # 举个例子:
    # 原始数组:[4,3,2,7,8,2,3,1]
    # 重置后为:[-4,-3,-2,-7,8,2,-3,-1]
    # 结论:[8,2] 分别对应的index为[5,6](消失的数字)
def findDisappearedNumbers(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        for num in nums:
            index = abs(num) - 1
            # 始终保持nums[index]为负数
            nums[index] = -abs(nums[index])
        return [i + 1 for i, num in enumerate(nums) if num > 0]
解法三

思路分析:

“抽屉原理”,即“一个萝卜一个坑”,但这道题比较让人头疼的是“不使用额外空间”。

以下介绍来自“百度百科”之“抽屉原理”词条:

抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有 n + 1 个元素放到 n 个集合中去,
其中必定有一个集合里至少有两个元素。” 抽屉原理有时也被称为鸽巢原理。它是组合数学中一个重要的原理。

这道题的一个子过程是“交换数组中两个位置的元素”,如果不使用额外的空间,可以使用“异或运算”代替。
方法:抽屉原理 + 基于“异或运算”交换两个变量的值
下面直接给结论:“基于异或运算”利用了“异或运算”是不进位的二进制加法。它有如下性质:

如果 a ^ b = c ,那么 a ^ c = b 与 b ^ c = a 同时成立,利用这一条,可以用于交换两个变量的值。

于是,交换两个变量的值,例如 a 和 b,不使用第三个变量,可以这样做:

a = a ^ b
b = a ^ b
a = a ^ b
我理解的方式就是自己在纸上写几个例子,也比较好记一些,因为右边都一样,左边依次是 a、b、a。

这里要特别注意一点,在数组中使用异或运算交换两个变量的值的时候,一定要保证这两个变量不相等,因为a ^ a = 0 。

这个方法实际效率并不高

def findDisappearedNumbers(self, nums: List[int]) -> List[int]:
        # 基于异或运算交换数组两个位置的元素,不使用额外的空间
        def swap(nums, index1, index2):
            # 这一步是必要的,否则会使得一个数变成 0
            if index1 == index2:
                return
            nums[index1] = nums[index1] ^ nums[index2]
            nums[index2] = nums[index1] ^ nums[index2]
            nums[index1] = nums[index1] ^ nums[index2]

        for i in range(len(nums)):
            while nums[i] != nums[nums[i] - 1]:
                # 如果不在位置上,并且它将要去的那个位置上的数不等于自己,则交换
                swap(nums, i, nums[i] - 1)

        return [i + 1 for i, num in enumerate(nums) if num != i + 1]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值