【数组中数字出现的次数-有限状态自动机】

数组中数字出现的次数

想必大家对数组中数字出现的次数的这种题并不少见,
主要有三种:
1,找出数组中只出现一次的数字(其他数字出现两次)
2,找出数组中仅有的两个仅出现一次的数字(其他数字出现两次)
3,找出数组中仅出现一次的数字(其他数字均出现三次)

本次主要对第三个问题进行讲解,因为前两种的思路,很容易想出,且很好理解。
我把三道题的链接放到下面:
链接: 1,仅有一个数字出现一次
在这里插入图片描述

链接: 2,仅有两个数字出现一次
在这里插入图片描述

链接: 3,仅有一个数字出现一次,其余出现三次
在这里插入图片描述

一,有限状态自动机解法

大体的思路:
统计32个比特位中,每一位1的出现次数,将其对3取余,最终得到的结果就是仅出现一次的数字
在这里插入图片描述
由于二进制位的位运算规则相同,所以考虑一位即可。
如下图所示,某二进制1的个数仅有三种状态:0,1,2
1,如果输入二进制位1,就按照以下做出转换。
2,如果输入二进制位0,不做转换。
在这里插入图片描述
由于,每个比特位,不是0就是1,无法记录2,所以引出第二个状态位
分别将其命名:one two 表示两个状态位。
在这里插入图片描述

  • 下面讲解如何对one ,two两个状态位进行更新
  • 状态位 one的更新:
if(two==0)
{
    
    
	if(n==1)
		one=~one;
	else
		one=one;
}
else if(two==1)
{
    
    
	one=0;
}

可以,对其用位操作符进行简化:
在这里插入图片描述

  • 状态位two的更新:
    状态two的更新是根据更新后的one来进行的(注意是更新后的one哟)
if(two==1)
{
    
    
	if(n==1)
		{
    
    
			if(one==0)
				two=0;
		}
}
else if(two==0)
{
    
    
	if(n==1)
	{
    
    
		if(one==0)
			two=1;
	}
}

为了方便理解,可以根据表格中的数据,理解上述关系式。
在这里插入图片描述
在这里插入图片描述

  • 代码:
  • 注意:&的优先级高于^
int singleNumber(int* nums, int numsSize){
    
    
    int twos=0,ones=0;
    for(int i=0;i<numsSize;i++)
    {
    
    
        ones = ones ^ nums[i] & ~twos;
        twos = twos ^ nums[i] & ~ones;
    }
    return ones;
}

别看这代码只有短短的几行,但是这其中的思考量是不小的。

  • 解释为何要做出简化:
    因为如果按照上述那种if else语句写的话,只是针对某个比特位,而简化后是对整个数据而言(也就是32个比特位)。

二,一般解法

所谓一般解法,就是分别记录各个数据的每个比特位,然后每位的数量进行%3处理。

int singleNumber(int* nums, int numsSize){
    
    
    int a[32]={
    
    0};
    for(int i=0;i<numsSize;i++)
    {
    
    
    	for(int j=0;j<32;j++)
    	{
    
    
    		a[j]+=nums[i]&1;
    		nums[i]>>=1;
    	}
    }
    int sum=0;
    for(int i=0;i<32;i++)
    {
    
    
    	sum+=a[i]%3==0?0:(int)pow(2,i);
    }
    return sum;
}

对比这种解法来说,更容易理解,且适用性很强,无论题目中其他数据都出现几次,我们只需该一处代码即可。但是效率不如上面的解法优秀。

猜你喜欢

转载自blog.csdn.net/Djsnxbjans/article/details/128434677