【剑指offer】一个单身狗和两个单身狗的问题@面试题56

目录

  • 1. 前情提要 —— 一个单身狗的故事
  • 2. 两个单身狗的故事
  • 3. 尾声

正文开始

1. 前情提要 —— 一个单身狗的故事

数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?

示例1 ——
输入:[3,0,1]
输出:2
示例2 ——
输入:[9,6,4,2,3,5,7,0,1]
输出:8

题目链接:消失的数字

这个“消失的数字”问题本质可以转化为单身狗问题来解决。

异或的运算性质 —— 同0异1

  • 0异或任何数结果还是这个数
    0 ⨁ a = a 0\bigoplus a =a 0a=a
  • 任何数异或本身都是0
    a ⨁ a = 0 a \bigoplus a = 0 aa=0

思路

那么,我们就异或遍历0到n所有整数,再异或遍历nums这个数组中每一个元素。
由异或运算符性质可知,相同的数字都被异或掉了,剩下的那个就是只出现一次的数字

此问题就已经转化为 —— 单身狗问题

一个数组中只有一个数字是出现一次,其他所有数字都出现了两次。编写一个函数找出这个只出现一次的数字。

代码如下 ——

int missingNumber(int* nums, int numsSize){
   int x = 0;
   int i = 0;
   for(i = 0; i<=numsSize; i++)
   {
       x ^= i;
   }
   for(i = 0; i<numsSize; i++)
   {
       x ^= nums[i];
   }
   return x;
}

2. 两个单身狗的故事

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例1 ——
输入:nums = [4,1,4,6]
输出:[1,6][6,1]
示例2 ——
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10][10,2]

题目链接:两个单身狗的故事

由上一题的经验,我们很容易的想到异或的方法

思路

分组 ——

  • 把这两个的只出现一次的数字各自分到两个组中
  • 其余数字成对分到两个组中去
  • 分别遍历异或两组,就可以拿到这两个单身狗数字了

那么如何分组呢?

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

既然这两个数字不同,那么它们的二进制表示中,一定有一位不同。
用这个例子来说,我们可以以最低位来划分,也可以以第二位来划分 ——

[101] - 5
[110] - 6
分组:
[110 6 2 2 4 4 ]   
[101 5 1 1 3 3 ][110 6 2 2 3 3 ]
[101 5 1 1 4 4 ] 

❄️ 先把所有数字都异或在一起,计算出的ret,即是5^6的结果

5 - 101
6 - 110 异或(01)011

ret的二进制表示是1的位即是,5和6的不同位,这样就找到了分组的依据。

❄️之前的学习中,我们知道,二进制位的每一位我们都是可以拿到的,只需要配合>>&1即可。我们就可以找到这两个单身狗数字的一个不同的二进制位的位置pos

再用这个位置来划分这两个组即可。

完整代码 :

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* singleNumbers(int* nums, int numsSize, int* returnSize){
    int* arr = (int*)malloc(sizeof(int)*2);
    *returnSize = 2;
    //1.把所有数字都异或在一起
    int i = 0;
    int ret = 0;
    for(i = 0; i < numsSize; i++)
    {
        ret ^= nums[i];
    }

    //2.找到这两个单身狗数字的,不同的二进制位の位置
    int pos = 0;
    for(i = 0; i < 32; i++)
    {
        if(((ret>>i) & 1) == 1)
        {
            pos = i;
            break;
        }
    }

    //3. 分组,边分组边异或
    int m = 0;
    int n = 0;
    for(i = 0; i < numsSize; i++)
    {
        if(((nums[i]>>pos)& 1) == 1)
        {
            m ^= nums[i];
        }
        else
        {
            n ^= nums[i];
        }
    }

    arr[0] = m;
    arr[1] = n;

    return arr;
}

3. 尾声

这两个单身狗就是这样幸福的生活在一起~
就是天意让他们在茫茫人海中找到彼此吧!哈哈

你可能感兴趣的:(剑指offer,leetcode)