[刷题]寻找两个单身狗

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

前言

       本文是关于Leetcode刷题——寻找两个单身狗的C语言实现。

       新手一个,水平比较低,还请包涵。

题目描述

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

示例 1:

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

解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0] 输出:[-1,0]

示例 3:

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

提示:

除两个只出现一次的整数外,nums 中的其他数字都出现两次。

计数统计法

时间复杂度:O(n)

思路

       创建一个动态数组buk,利用其下标对应原数组中的元素,利用buk中对应下标的值作为该下标对应的值出现的次数,类似于计数排序中的计数方法, 就是利用数组记录各数字出现次数。

代码

int* FindSingle(int* arr, int sz)
{
	int max = 0;
	int i = 0;
	int j = 0;
	int cnt = 0;
	static int ret[2] = {0};

	for (i = 0; i < sz; i++)//找出最大值以确定动态数组元素个数
	{
		if (arr[i] > max)
			max = arr[i];
	}

	int* buk = (int*)calloc(max, sizeof(int));
	if (NULL == buk)
	{
		perror("buk");
		return;
	}

	for (i = 0; i < sz; i++)//计数并存储到数组buk中
	{	
		buk[arr[i]]++;
			
	}

	for (j = 0; j < max; j++)//遍历以找出只出现一次的两个数字
	{
		if (buk[j] == 1 && cnt < 2)
		{
			ret[cnt] = j;
			cnt++;
		}
	}
    
    free(buk);
    buk = NULL;
	return ret;//将找到的两个数字存到全局数组中并返回其指针
}

int main()  //以一个20个元素的数组作为示例
{

	int arr[20] = {1, 2, 3, 3, 4, 4, 5, 6, 6, 5, 7, 9, 8, 7, 8, 9, 10, 10, 11, 11};
	int* tmp = FindSingle(arr, 20);

	printf("%d %d\n", tmp[0], tmp[1]);

	return 0;
}

分组异或法

时间复杂度:O(n)

思路

       要是只寻找一个单身狗,就可以无脑异或:遍历数组,把全部数异或在一起。为什么可以这样呢?是根据异或的两个小特点:一是相同的数异或后为0,二是任何数和0异或都得到它本身。基于此,在把全部数异或的时候相同的数就全部化为0了,而异或0对数值没有影响,最后就剩下单身狗了(悲)。

       不过这里是要寻找两只单身狗,要是全部异或在一起最后得到两个单身狗异或的值,无法分离。那可不可以把两只单身狗分开呢,把他俩分到不同的组去,分开来异或,这样不就分别筛选出两只单身狗了吗。不过难就难在如何分组。

       想想看,能不能利用一下两只单身狗异或的值,这里举个例子:数组arr[] = {1, 2, 3, 4, 4, 3, 2, 1, 5, 6};很明显5和6是单身狗。5和6异或得到的值的二进制位中看看最右边为1的是哪一位,在那一位上5和6的二进制位不同,可以以此来分组。分组以后再分别和组内的数异或即可。

寻找两个单身狗.png

步骤

1.全部数异或

2.分组: 根据两单身狗在二进制位第n位上不同来分组

3.分别异或

代码

void FindSingle(int* arr, int sz, int* sig_1, int* sig_2)
{
    int i = 0;
    int tmp = 0;
    int pos = 0;
    
    for (i = 0; i < sz; i++)
    {
        tmp ^= arr[i];
    }

    while (tmp)
    {
        if (tmp % 2)
            break;
        tmp /= 2;
        pos++;
    }

    for (i = 0; i < sz; i++)
    {
        if ((arr[i] >> pos) & 1)
        {
            *sig_1 ^= arr[i];
        }
        else
        {
            *sig_2 ^= arr[i];
        }
    }

}