Sword56-II——数组中数字出现的次数 II
注:五颗星困难模式,不喜勿入
方法1——有限状态交换机
- 思路:二进制形式中,对于出现三次的数字,其对于1上的数一定可以被3整除,即为3的倍数,因此只需要其最后结果的每一位上都对3求余,最后剩下的各个位上为1的数字即为最后结果
- 因为任何数字对3取余的余数有3种(0、1、2),因此所有数字的二进制上1的个数状态只可能有3种
- 对于二进制该位上输入的情况
- 若输入二进制中该位为0,则状态保持不变
- 若输入二进制中该位为1,则状态变化有三种情况
- 0 -> 1
- 1 -> 2
- 2 -> 0
- 由于二进制中只有0、1的表示,因此表示三种情况需要由两个二进制位进行表示,即two、one。将上述情况转换即为
- 若输入二进制中该位为0,则状态保持不变
- 若输入二进制中该位为1,则状态变化有三种情况
- 00 -> 01
- 01 -> 10
- 10 -> 00
- 如何计算one?
- 首先需要考虑two是否需要进位,其次需要考虑two的降位
- 当two为0时
- 输入为0,one不管从0或1,都将不变,即为one
- 输入为1,one从0为1、从1为0,都将取反,即为~one
- 当two为1时(此时one起始只能为0)
- 输入为0或1,one都只能为0
- 综上所述
- 当two为0,one = one ^ n
- 当two为1,one = 0
- 再次简化:one = one ^ n & ~two
- 如何计算two?(同one计算,只不过是在新one上计算)
- 即最终结果为:two = two ^ n & ~two
- 特殊情况与临界分析:无
- 终止条件:无
- 步骤:
- 定义两个表示进制的数字
- foreach循环遍历数组
- 求解one
- 求解two
- 退出循环时,one即为出现一次的数字
public int singleNumber(int[] nums) {
// 定义表示进制的两个数字
int one = 0, two = 0;
// foreach循环
for (int num : nums) {
// 求解one
one = one ^ num & ~two;
// 求解two
two = two ^ num & ~one;
}
// 返回出现一次的数字
return one;
}