[C language] Find two numbers that only appear once

Find two numbers that appear only once

Question description

Question source:260. Numbers that appear only once III - Leetcode

You are given an array of integers nums in which exactly two elements appear only once and all remaining elements appear twice. Find those two elements that appear only once. You can return answers in any order.

Example 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

Example 2:

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

Example 3:

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

Analysis of ideas

When we see this question, it is not difficult for us to think of finding a code for a single number, that is, XORing all the numbers once

So here we might as well think in this direction. Can we use the idea of ​​finding a number to find two numbers?

If we directly XOR all the numbers, then the number we get is the result of the XOR of two separate numbers. Obviously, this method is not very feasible.

But let’s change the angle. Can we divide this bunch of numbers into two groups, and then XOR the two groups of numbers independently, then we can find them?

A new problem arises here, how to group these numbers and ensure that the two numbers are divided into different groups. Here we need to rely on the properties of XOR. We know that if the two numbers are different, then XOR will definitely produce a new number, and the binary bits of this number will show the different positions of the two numbers. Then we can group these numbers by this.


Maybe some people didn’t understand the above idea, so here is an example.

If we want to find 3 4 from 1 1 2 2 3 4

According to the last four digits of binary, 3 is 0011 and 4 is 0100

It can be seen that the last three digits of these two numbers are different, so at this time we only need to select any different digit to group, and 3 and 4 will definitely not be grouped together.

So how do we find the different bits?

The answer is to get 3^4 by XORing all the numbers, and then you can get the last four binary digits as 0111

That is to say, different bits appear as 1 after XOR. Then you can judge and group by judging the 1 on the digital binary bit after XOR.

And due to the particularity of binary, there are only 0 and 1, so the different bit positions of two separate numbers must be a 1 and a 0, which also makes grouping very simple.

In this example, we assume that the first binary digit is used to group

Then 1 is 0001 and 2 is 0010

The grouping is 1 1 3, 2 2 4. At this time, the two groups can be XORed to get 3 and 4.

Code

First of all, we must XOR all the numbers together so that we can find the different bits later.

    int num = nums[0];
    for(int i = 1; i < numsSize; i++){
    
    
        num ^= nums[i];
    }

Then we need to find out which bit starts to be different, that is, find out which bit in the binary bit starts to appear 1.

    int count = 0;
    while(!(num & 1)){
    
    
        num >>= 1;
        count++;
    }

then creates a number to be used for grouping. The above count also works at this time, used to convert the binary digits 1 Move to a different bit position

But there is one thing to note here. Since signed integers can only move 31 bits to the left, if there is a number that happens to be different in the 32nd bit, then an error will be reported here ( The examples on Leetcode are worth complaining)

So the type used here is unsigned integer

unsigned int tmp = (unsigned int)1 << count;

Then the next step is to group and store the two sets of numbers

    int arr1[numsSize];
	int arr1Size = 0;
	int arr2[numsSize];
	int arr2Size = 0;
    for (int i = 0; i < numsSize; i++) {
    
    
        //如果不同位上都是1
		if (tmp & nums[i]) {
    
    
			arr1[arr1Size] = nums[i];
			arr1Size++;
        //如果不同位上都是0
		}else{
    
    
			arr2[arr2Size] = nums[i];
			arr2Size++;
		}
	}

Then XOR the two sets of numbers separately. The point to note here is that you must initialize the data of malloc, or use it directlycalloc

 	*returnSize = 2;
 	int* ret = (int*)malloc(sizeof(int) * 2);
	ret[0] = arr1[0];
 	for (int i = 1; i < arr1Size; i++) {
    
    
		ret[0] ^= arr1[i];
	}
		ret[1] = arr2[0];
	for (int i = 1; i < arr2Size; i++) {
    
    
		ret[1] ^= arr2[i];
 	}
    return ret;
}

Code preview

int* singleNumber(int* nums, int numsSize, int* returnSize) {
    
    
	int num = nums[0];
	for (int i = 1; i < numsSize; i++) {
    
    
		num ^= nums[i];
	}
	int count = 0;
	while (!(num & 1)) {
    
    
		num >>= 1;
		count++;
	}
	unsigned int tmp = (unsigned int)1 << count;
	int arr1[numsSize];
	int arr1Size = 0;
	int arr2[numsSize];
	int arr2Size = 0;
	for (int i = 0; i < numsSize; i++) {
    
    
		if (tmp & nums[i]) {
    
    
			arr1[arr1Size] = nums[i];
			arr1Size++;
		}
		else {
    
    
			arr2[arr2Size] = nums[i];
			arr2Size++;
		}
	}
	*returnSize = 2;
	int* ret = (int*)malloc(sizeof(int) * 2);
	ret[0] = arr1[0];
	for (int i = 1; i < arr1Size; i++) {
    
    
		ret[0] ^= arr1[i];
	}
	ret[1] = arr2[0];
	for (int i = 1; i < arr2Size; i++) {
    
    
		ret[1] ^= arr2[i];
	}
	return ret;
}

Guess you like

Origin blog.csdn.net/qq_42150700/article/details/130308403