LeetCode 260 Single Number III(只出现一次的数字 III)(*)

本文介绍了一种使用位运算解决的问题——在一个数组中找到仅出现一次的两个数字。通过异或操作和位检查,实现了线性时间和常数空间复杂度的解决方案。

原文

给定一个数字数组nums,其中有两个元素只出现一次,而其他所有元素均出现两次。

找出这两个只出现一次的元素。

例如:

给定nums = [1, 2, 1, 3, 2, 5],返回[3, 5]。

备注:
1, 返回结果的顺序不重要。所以在上例中,返回[3, 5]也是正确的。
2, 你的算法应该运行在线性时间复杂度。你可以只用常量空间复杂度来实现它吗?

原文

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. 

Find the two elements that appear only once.

For example:

Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].

Note:
1. The order of the result is not important. So in the above example, [5, 3] is also correct.

2. Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

分析

本题我曾在《剑指Offer》中见过,记得要用位运算,自己实现了一遍,不过再看了看书上的,并没有书上的规范,所以最后贴了书上的代码……

其实有这么一个性质:

任何数字异或其自身都等于零。

可能有读者不了解什么是异或,那么就来插播一下:

异或,英文为exclusiveOR,或缩写成xor,异或是一个被用于逻辑运算的数学符号。其数学符号是“⊕”,计算机符号是“xor”。

a⊕b=(¬a∧b)∨(a∧¬b)

true ⊕ false -> true
false ⊕ true -> true
true ⊕ true -> false
false ⊕ false -> false

也就是说两个值相同则异或结果为假,两个值不同则异或为真。所以任何数字异或其自身都等于零,因为两个值相同。

好了,切入正题。就以题目中给出的数组为例吧:

[1, 2, 1, 3, 2, 5, 6, 5, 4, 6]

分别换算成二进制如下:
00010010000100110010
01010110010101000110

对所有数组进行异或运算得出的结果是:0111

于是进行分组如下:
A组: 00011)、00102)、00011)、00113)、00102)
B组: 01015)、01106)、01016)、01004)、01105)

对A组进行再次异或运算的结果是:00113)

对B组进行再次异或运算的结果是:01004

判断该数字的二进制第n位是否是1的函数:

bool IsBit1(int num, unsigned int index) {
    num = num >> index;
    return (num & 1);
}`

找出该数字二进制中第一个1的函数:

unsigned int FindFirstBigIs1(int num) {
    int indexBit = 0;
    while (((num & 1) == 0) && (indexBit < 8 * sizeof(int))) {
        num = num >> 1;
        ++indexBit;
    }
    return indexBit;
}

根据LeetCode的函数模板修改了一点:

vector<int> singleNumber(vector<int>& nums) {
    vector<int> singleV;
    if (nums.size() <= 0) return singleV;

    int resultExclusiveOR = 0;
    for (int i = 0; i < nums.size(); ++i)
        resultExclusiveOR ^= nums[i];

    unsigned int indexOf1 = FindFirstBigIs1(resultExclusiveOR);

    int singleNum1 =0, singleNum2 = 0;
    for (int j = 0; j < nums.size(); ++j) {
        if (IsBit1(nums[j], indexOf1))
            singleNum1 ^= nums[j];
        else
            singleNum2 ^= nums[j];    
    }

    singleV.push_back(singleNum1);
    singleV.push_back(singleNum2);
    return singleV;
}

还有两道相关的题:

LeetCode 136 Single Number(只出现一次的数字)
LeetCode 137 Single Number II(只出现一次的数字 II)(*)

LeetCode的第260题中,题目被称为“只有一个公共元素的数组 II”。这是一道关于数组操作的数据结构和算法题目。给定两个已经排序的整数数组 nums1 和 nums2,你需要找出它们之间的一个共同的元素,这个元素在每个数组中都只出现一次。 该问题的目标是找到这样的一个公共元素,并返回它的值。例如,如果nums1 = [1, 2, 2, 4] 和 nums2 = [2, 2, 8, 10],那么唯一的公共单次出现的元素是2。 为了解决这个问题,你可以采用一种类似于双指针的方法。从两个数组的起始位置开始遍历,每次比较当前指针对应的元素。如果元素相等且在各自的数组中都是第一次出现(即前一个出现的位置比当前位置大),就将这个元素添加到结果中并继续向后移动指针。如果遇到不同的元素,则移动较小的那个指针的所在数组的指针。 Python 或 C++ 等语言中,可以实现一个循环或者递归的解决方案,直到找到共同的单次出现元素或遍历完其中一个数组。这里是一个简单的 Python 示例: ```python def singleNumber(nums1, nums2): i, j = 0, 0 count = {} while i < len(nums1) and j < len(nums2): if nums1[i] not in count or nums2[j] not in count: count[nums1[i]] = 1 i += 1 elif nums2[j] not in count: count[nums2[j]] = 1 j += 1 else: del count[nums1[i]] del count[nums2[j]] i += 1 j += 1 # 如果有一个数组没遍历完,剩下的最后一个元素就是公共唯一元素 return list(count.keys())[0] if i < len(nums1) else list(count.keys())[-1] ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值