欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【剑指】56(1).数组中只出现一次的两个数字

程序员文章站 2022-07-15 12:12:09
...

题目描述

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

算法分析

  1. 首先:位运算中异或的性质:两个相同数字异或=0一个数和0异或还是它本身
  2. 只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。
  3. 依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。

提交代码:

class Solution {
public:
	void FindNumsAppearOnce(vector<int> data, int* num1, int *num2) {
		if (data.empty())
			return;

		int temp = 0;
		for (auto iter = data.cbegin(); iter != data.cend(); ++iter)
			temp ^= *iter;

		// 找到最低位的第一个1
		int i = 1;
		while ((temp & i) == 0)
			i <<= 1;

		*num1 = *num2 = 0;
		for (auto iter = data.cbegin(); iter != data.cend(); ++iter)
		{
			if ((*iter & i) == 0)
				*num1 ^= *iter;
			else
				*num2 ^= *iter;
		}
	}
};

测试代码:

// ====================测试代码====================
void Test(const char* testName, vector<int> data, int expected1, int expected2)
{
	if (testName != nullptr)
		printf("%s begins: ", testName);

	int result1, result2;
	Solution s;
	s.FindNumsAppearOnce(data, &result1, &result2);

	if ((expected1 == result1 && expected2 == result2) ||
		(expected2 == result1 && expected1 == result2))
		printf("Passed.\n\n");
	else
		printf("Failed.\n\n");
}

void Test1()
{
	vector<int> data = { 2, 4, 3, 6, 3, 2, 5, 5 };
	Test("Test1", data, 4, 6);
}

void Test2()
{
	vector<int> data = { 4, 6 };
	Test("Test2", data, 4, 6);
}

void Test3()
{
	vector<int> data = { 4, 6, 1, 1, 1, 1 };
	Test("Test3", data, 4, 6);
}

int main(int argc, char* argv[])
{
	Test1();
	Test2();
	Test3();

	return 0;
}