【c++】只出现一次的数字I II III(三个版本:三道题)

目录

1、力扣136. 只出现一次的数字

 2、 只出现一次的数字 II

3、只出现一次的数字 III


1、力扣136. 只出现一次的数字

解题思路:

 ^异或操作符求解),^操作符我之前文章写过,请记下以下性质(假设A是一个数):

A^A=0   0^A=A

那就把数组中的数全都^一遍就能得到那个单独的数了

class Solution {
public:
	int singleNumber(vector<int>& nums) {
		int val = 0;
		for (auto e : nums)
		{
			val ^= e;//与vector容器中的每个值^下
		}

		return val;
	}
};

 2、 只出现一次的数字 II

解题思路:

理解方式①:

大体思路找出只出现一次的数对应的二进制位,找到后还原它即可

具体思路:

 ①、给定四个数,观察对应二进制位,得出出现一次的数对应的相加后的二进制位个数一定是3n+1

故我们先求出所有数32个位中每个位为1的个数 

 ②、32位中每个位,只要位为1的个数是3n+1,就说明他是那个出现一次的数的二进制位,那只要找出这些位,还原这个数即可,怎么还原?

运用 | (或运算)   或者 ^(异或运算)

class Solution {
public:
	int singleNumber(vector<int>& nums) {
		//1、统计出所有数32个位中1出现的次数
		int bits[32] = { 0 };//储存32位的情况
		for (auto val : nums)
		{
			for (size_t i = 0; i < 32; ++i)
			{
				if ((val >> i) & 1)//或写为if(val & (1 << i))
				{//val的32位从低位到高位的每一位都判断是否存在1
				 //为真说明存在1,则bits数组对应++
					bits[i]++;
				}
				
			}
		}
		int num = 0;//要求的那个出现一次的数
		for (size_t i = 0; i < 32; ++i)
		{
			//次数为3N+1的位就是只出现一次的数为1的位
			if (bits[i] % 3 == 1)
			{
				//使num对应的二进制位变为只出现一次的数对应的二进制位
				num |= (1 << i);//或写为num ^= (1 << i);
			}
		}
		return num;
	}
};

理解方式②:

class Solution {
public:
	int singleNumber(vector<int>& nums) {
        int ret = 0;
        //依次修改每个二进制位
        for (int i = 0; i < 32; i++)
        {
            int sum = 0;//计算所有数每个二进制位的和
            for (auto x : nums) 
                sum += x >> i & 1;//获取第i位的二进制位
            sum %= 3;
            if (sum == 1) ret |= 1 << i;//把第i为修改为1
        }
        return ret;
	}
};

3、只出现一次的数字 III

 

解题思路:

这道题在我写^的文章中写过c语言版本的,思路都是一样的!

https://blog.csdn.net/m0_74044018/article/details/130195037

再说下思路:

  • 1、所有数^后,结果就是只出现一次的两个数^后的结果,重点在于如何分离两个数
  • 2、两个数既然不同,那么一定有一个二进制位(有同一位置相对应的二进制位)不同,因为是^,不同的一位^结果一定为1,那我们只要找到一位为1的即可,用这个1来分离两个数到两组,我们假设这个二进制位下标是k
  • 3、分为两组:k位为1的分为1组,k位为0的分为另一组,那么两个只出现一次的数一定被分到两组,而每一次都再^一遍,其他的出现两次的数一定会被^没,只会剩下那个只出现一次的数了
class Solution {
public:
	vector<int> singleNumber(vector<int>& nums) {
		//1、得出只出现一次的两个数^后的结果,val就是结果
		int val = 0;
		for (auto e : nums)	val ^= e;

		//2、随机找一个两个数不同的二进制位
		//二进制位不同则^后结果为1,故我们找个二进制位为1的即可
        size_t i = 0;
		for (; i < 32; ++i)
			if (val & (1 << i)) break;	//找到一个二进制位为1的则break,找到的i就是对应第几位

		//3、分离所有数为两组(那两个只出现一次的数肯定不在一组)
		int num1 = 0, num2 = 0;//储存只出现一次的两个数
		for (auto e : nums)
		{//第i位为1的为一组,为0的为另一组
			if (e & (1 << i)) num1 ^= e;
			else num2 ^= e;
		}
        return {num1, num2};
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值