Single Number I & II

本文介绍如何在数组中找出只出现一次的元素,对于两次和三次重复的情况提供了两种算法实现。通过位操作达到线性时间和常数空间复杂度的要求。

Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Single Number II

 

Given an array of integers, every element appears three times except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

如果我自己想的话,大概想不出来这两道题该如何做,感觉自己还需要更宽广的思维...

这两道题的核心思想就是利用二进制的性质,将每一个数都拆成二进制位来计数.

Single Number

class Solution {
public:
    int singleNumber(int A[], int n) {
        int res = 0;
        for(int i = 0; i < n; i++)
        {
        	res ^= A[i];
        }
        return res;
    }
};

Single Number II

 
class Solution {
public:
    int singleNumber(int A[], int n) {
        int bit[32];
        for(int i = 0; i < 32; i++)
        {
            bit[i] = 0;
        }
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < 32; j++)
            {
            	bit[j] += (A[i] >> j) & 1;
            }
        }
        int res = 0;
        for(int i = 0; i < 32; i++)
        {
            bit[i] %= 3;
            res += (bit[i] > 0 ? 1 : 0) << i;
        }
        return res;
    }
};

&lt;think&gt;好的,我需要将用户提供的Java代码转换为C++,并解释其工作原理。首先,我得仔细理解原始代码的功能。这个函数名为singleNumber,接受一个整数数组nums,返回只出现一次的数字。其他数字都出现三次,所以这是一个找出唯一出现一次的数字的问题。 接下来,分析算法。代码中使用了一个bitSums数组,长度为32,用来统计每一位上1的总数。对于每个数字,遍历每一位,将每一位的1累加到对应的bitSums位置。然后,遍历bitSums,每位对3取余,因为出现三次的数字在该位上的和会是3的倍数,余数就是只出现一次的数字在该位的值。最后将这些余数组合成结果。 现在转换为C++。首先,C++的数组声明和Java不同,这里需要使用int bitSums[32] = {0}; 来初始化为0。循环部分,C++的foreach循环需要正确的类型,使用auto或者int来遍历nums。位操作部分,Java的&gt;&gt;运算符在C++中对于有符号数可能会有符号扩展的问题,但在这里处理的是int,C++和Java的行为应该一致。不过需要考虑负数的情况吗?因为题目中的nums可能包含负数,但原算法处理的是二进制位,不管符号,所以应该没问题。 然后,result的构造部分,Java中左移并加上余数,C++中的操作符相同。需要注意的是,在C++中,int的大小可能根据编译器不同而不同,但通常和Java一样是32位,所以没问题。 然后,测试一下可能的边界情况。比如nums中有负数,或者所有数字都出现三次,只有一个不同。但根据题目描述,输入应该是有效的,即确实存在这样的数字,所以代码不需要处理这些异常。 在代码转换时,需要注意变量声明的位置,C++需要明确类型,比如在循环中声明int num,或者使用auto。此外,函数的参数需要将int[] nums转换为C++中的vector&lt;int&gt;&amp; nums或者指针形式。用户可能希望代码使用vector,所以参数改为vector&lt;int&gt;&amp; nums。 总结步骤: 1. 将bitSums数组初始化为0。 2. 遍历每个数字,每个位,累加bit。 3. 计算每位模3的结果,组合成结果。 4. 返回结果。 现在编写C++代码,函数参数使用vector&lt;int&gt;&amp;,循环使用范围for循环。注意C++中右移操作符的行为是否与Java一致,Java的&gt;&gt;是带符号右移,C++中对于有符号数也是带符号右移,所以相同。 测试例子,比如输入[2,2,3,2],应该返回3。或者更复杂的例子,确保代码正确。 最后,解释代码时,需要分步骤说明每个部分的作用,特别是位统计和模3的原因,以及如何通过左移构造结果。&lt;/think&gt;以下是将该Java代码转换为C++的代码实现及逐步讲解: ```cpp int singleNumber(vector&lt;int&gt;&amp; nums) { int bitSums[32] = {0}; // 1. 创建32位二进制位统计数组 // 2. 遍历所有数字统计每一位的1出现次数 for (int num : nums) { for (int i = 0; i &lt; 32; i++) { // 从最高位(第31位)开始检查每一位是否为1 bitSums[i] += (num &gt;&gt; (31 - i)) &amp; 1; } } // 3. 通过取模3计算结果 int result = 0; for (int i = 0; i &lt; 32; i++) { result = (result &lt;&lt; 1) | (bitSums[i] % 3); // 逐位组合结果 } return result; } ``` #### 核心原理分步解析 1. **位统计阶段** - 每个数字的二进制位会被拆解到32个计数器(对应`bitSums[32]`数组) - 例如数字5(二进制`000...000101`)会让`bitSums[29]`、`bitSums[31]`各加1 - 时间复杂度:$O(32n)$,空间复杂度:$O(1)$ 2. **取模运算阶段** - 关键点:出现3次的数字在每个位的总和必然是3的倍数 - 例如某位总和为7(7%3=1)表示只出现一次的数字在该位为1 - 使用`bitSums[i] % 3`获取目标数字在该位的值 3. **结果重组阶段** - 通过左移位操作逐位构建最终数字 - `result &lt;&lt; 1`将已处理位左移腾出新位置 - `|`操作符将当前位的值合并到结果中 #### 代码差异说明 1. 数组初始化:C++要求显式初始化`int bitSums[32] = {0}` 2. 循环语法:C++使用`for (int num : nums)`遍历vector 3. 位运算符:`|`比`+`更符合位运算语义(但两者在此处等效) #### 示例验证 输入:`[2,2,3,2]`(二进制`10,10,11,10`) - 最低位总和:1(2出现3次) + 1(3出现1次)= 4 &rarr; 4%3=1 - 第二位总和:3(2出现3次) + 1(3出现1次)= 4 &rarr; 4%3=1 结果:二进制`11` &rarr; 十进制3 该方法通过二进制位的数学特性,以线性时间、常数空间解决「只出现一次的数字」问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值