数组中唯一只出现一次的数字

Posted 穿过雾的阴霾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组中唯一只出现一次的数字相关的知识,希望对你有一定的参考价值。

思路

如果一个数字出现 3 次,那么它的二进制表示的每一位也出现三次,如果把所有出现三次的数字的二进制表示的每一位都分别加起来,那么每一位的和都能被 3 整除

  1. cnt[32] 数组存储每一位 1 出现的次数
  2. 遍历数组中所有数,将其二进制表示记录在 cnt 数组里
  3. 遍历 cnt 数组,根据 cnt[i] 能否被 3 整除,推断出答案的二进制的第 i 位是 0 还是 1

复杂度分析

时间复杂度 O(32n),空间复杂度用到了长度为 32 的辅助数组,O(1)

代码

class Solution 
public:
    int findNumberAppearingOnce(vector<int>& nums) 
        int cnt[35];//cnt[i]记录二进制第i位1的个数
        memset(cnt,0,sizeof cnt);
        for(auto num:nums)
        
            for (int i = 0; i < 32; i ++ )            
                if(num>>i&1)    cnt[i]++;
        
        
        int res=0;
        for (int i = 0; i < 32; i ++ )
            if(cnt[i]%3)//res二进制第i位为1
                res+=1<<i;
        return res;
    
;

《剑指Offer——数组中只出现一次的两个数字,数组中唯一只出现一次的数字》代码


前言

//============================================================================
// 《剑指Offer——数组中只出现一次的两个数字,数组中唯一只出现一次的数字》代码
//============================================================================
// 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序
// 找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
//============================================================================
// 题目:在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。请
// 找出那个吃出现一次的数字。
//============================================================================


一、示例

1.数组中只出现一次的两个数字,

/*========================================================
一个整型数组 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]
=======================================================*/

2.数组中唯一只出现一次的数字

/*=====================================================
在一个数组 nums 中除一个数字只出现一次之外,
其他数字都出现了三次。请找出那个只出现一次的数字。

示例 1:
输入:nums = [3,4,3,3]
输出:4

示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1
======================================================*/

二、代码解析

1.新建.cpp文件

代码如下(示例):

//============================================================================
// 《剑指Offer——数组中只出现一次的两个数字,数组中唯一只出现一次的数字》代码
//============================================================================
// 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序
// 找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
//============================================================================
// 题目:在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。请
// 找出那个吃出现一次的数字。
//============================================================================



#include <iostream>
#include<vector>
#include<unordered_map>
using namespace std;

/*========================================================
一个整型数组 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]
=======================================================*/
/*法一-----哈希表*/
vector<int> singleNumbers(vector<int>& nums)
{
	vector<int> result;
	unordered_map<int, int> map;
	for (int num : nums)
	{
		map[num]++;
	}
	for (auto item : map)
	{
		if (item.second == 1)
		{
			result.push_back(item.first);
		}
	}
	return result;
}
/*法二-----异或运算*/

// 找到num从右边数起第一个是1的位
unsigned int FindFirstBitIs1(int num)
{
	int indexBit = 0;
	while (((num & 1) == 0) && (indexBit < 8 * sizeof(int)))
	{
		num = num >> 1;
		++indexBit;
	}

	return indexBit;
}

// 判断数字num的第indexBit位是不是1
bool IsBit1(int num, unsigned int indexBit)
{
	num = num >> indexBit;
	return (num & 1);
}

void FindNumsAppearOnce(int data[], int length, int* num1, int* num2)
{
	if (data == nullptr || length < 2)
		return;

	int resultExclusiveOR = 0;
	for (int i = 0; i < length; ++i)
		resultExclusiveOR ^= data[i];

	unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);

	*num1 = *num2 = 0;
	for (int j = 0; j < length; ++j)
	{
		if (IsBit1(data[j], indexOf1))
			*num1 ^= data[j];
		else
			*num2 ^= data[j];
	}
}


/*=====================================================
在一个数组 nums 中除一个数字只出现一次之外,
其他数字都出现了三次。请找出那个只出现一次的数字。

示例 1:
输入:nums = [3,4,3,3]
输出:4

示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1
======================================================*/
/*法一---嘻哈表*/
int singleNumber(vector<int>& nums)
{
	unordered_map<int, int> map;
	for (int num : nums)
	{
		map[num]++;
	}
	for (auto item : map)
	{
		if (item.second == 1)
		{
			return item.first;
		}
	}
	return 0;
}

/*法二--位运算*/
int FindNumberAppearingOnce(vector<int>& nums)
{
	if (nums.empty())
	{
		return 0;
	}
	int bitSum[32] = { 0 };
	for (int i = 0; i < nums.size(); ++i)
	{											//3,4,3,3
		long bitMask = 1;
		for (int j = 31; j >= 0; --j)
		{
			int bit = nums[i] & bitMask;		//bit=1 
			if (bit != 0)
			{
				bitSum[j] += 1;					//bitSum[31]=1,
			}
			bitMask = bitMask << 1;				//bitMask=2
		}
	}
	int result = 0;
	for (int i = 0; i < 32; ++i)
	{
		result <<= 1;
		result += bitSum[i] % 3;
	}
	return result;
}

int main()
{
	vector<int> nums = { 1,1,1,2,3,3,3 };
	vector<int> nums1 = { 1,1,2,5,3,3 };
	int data[] = { 1,1,2,5,3,3 };
	cout << "数组中只出现一次的两个数字" << endl;
	vector<int> result = singleNumbers(nums1);
	int value1, value2;
	FindNumsAppearOnce(data,6,&value1,&value2);
	cout << "法一--->嘻哈表--->" << result[0] << " " << result[1] << endl;
	cout << "法二--->异或运算--->" << value1 << " " << value2 << endl;
	cout << "数组中唯一只出现一次的数字" << endl;
	cout << "法一--->嘻哈表--->" << singleNumber(nums) << endl;
	cout << "法二--->位运算--->" << FindNumberAppearingOnce(nums) << endl;
	return 0;
}

三,测试


以上是关于数组中唯一只出现一次的数字的主要内容,如果未能解决你的问题,请参考以下文章

《剑指offer》第五十六题II:数组中唯一只出现一次的数字

数组中唯一只出现一次的数字

剑指Offer打卡day42——ACWing 74. 数组中唯一只出现一次的数字

74. 数组中唯一只出现一次的数字

算法题1 数组中唯一出现1次的数|唯一出现2次的数

数组中只出现一次的数字