leetCode 137. 只出现一次的数字 II(拓展篇) + 模5加法器 + 真值表(数字电路)

leetCode 137. 只出现一次的数字 II 有其他的题解可看我的往期文章:

leetCode 137. 只出现一次的数字 II + 位运算 + 模3加法器 + 真值表(数字电路) + 有限状态机-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/134138112?spm=1001.2014.3001.5501

关于 leetCode 137. 只出现一次的数字 II,参考灵神的解法做的思路分析:

cpp 复制代码
0->1->2->0->1->2->...
(0,0)->(0,1)->(1,0)->(0,0)->(0,1)->(1,0)->...
>>分析
其中有大量 0 和 1 之间的转换,可以用异或运算实现
    ① a=a^1
    ② b=b^1
方式1:「同时计算」
    a = a^x & a|b
    b = b^x & (~a)

方式2:「分别计算」
    先计算b,再计算a(思路:b在同时计算的时候式子比较简洁,可用新b来参与计算a)
    b = b^x & (~a)
    a = a^x & (~b)

    >>思路和过程分析
        (0,0)->(0,1)->(1,0)
        (1)先算b:b = b^x & (~a),可得
        (0,1)->(0,0)->(1,0)

        (2)再算a
        (0,1)->(0,0)->(1,0)
        // 1.调换位置
        (1,0)->(0,0)->(0,1)
        // 2.调整画法
        (0,0)->(0,1)->(1,0)

        // 计算b前的状态转换图
        (0,0)->(0,1)->(1,0)

        //最后的得到的状态转换图与计算b前的状态转换图是等价的,即若使用计算后的新b,则可以通过相同的公式计算a
        a = a^x & (~b)

1.方式1:

cpp 复制代码
class Solution {
public:
    // 模3加法 方法2:用位运算实现
    int singleNumber(vector<int>& nums) {
        int a=0,b=0;
        for(const int& x:nums) {
            int tmp_a = a;
            a = (a^x) & (a|b);
            b = (b^x) & (~tmp_a);
        }
        return b; 
    }
};

2.方式2:

cpp 复制代码
class Solution {
public:
    // 模3加法 方法2:用位运算实现
    int singleNumber(vector<int>& nums) {
        int a=0,b=0;
        for(const int& x:nums) {
            b = (b^x) & (~a);
            a = (a^x) & (~b);
        }
        return b; 
    }
};

灵茶山艾府出的思考题】(137. 只出现一次的数字 II - 力扣(LeetCode)):

  • 如果把转换规则改成 0→2→1→0→2→1→⋯ ,对应的代码应该如何修改呢?
  • 如果改成除了一个数字出现一次,其余数字均出现 5 次呢?

(1)第一题解法:

cpp 复制代码
这个是我的解题思路:
// 第一种方法
0 → 2 → 1 → 0 → 2 → 1 → ⋯
(0,0) -> (1,0) -> (0,1) -> (0,0) -> ...
>>分析
其中有大量 0 和 1 之间的转换,可以用异或运算实现
    ① a=a^1
    ② b=b^1
    
(1)先算a,a = a^x & (~b);可得
(1,0) -> (0,0) -> (0,1) -> (1,0) -> ...

(2)再算b
(1,0) -> (0,0) -> (0,1) 
// 1.调换位置
(0,1) -> (0,0) -> (1,0) 
// 2.调整画法
(0,0)->(1,0)->(0,1)

// 计算a前的状态转换图
(0,0)->(1,0)->(0,1)

// 最后的得到的状态转换图与计算a前的状态转换图是等价的,即若使用计算后的新a,则可以通过相同的公式计算b
b = b^x & (~a);

// 第二种方法
0->1->2->0->1->2->...
(0,0)->(0,1)->(1,0)->(0,0)->(0,1)->(1,0)->...

0 → 2 → 1 → 0 → 2 → 1 → ⋯
(0,0) -> (1,0) -> (0,1) -> (0,0) -> ...

仔细观察这个区别,其实就是a和b调换了,所以可以先计算a,再计算b
a = a^x & (~b);
b = b^x & (~a);

(2)第二题解法:

1.「同时计算」

化简 b 和 c:

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int singleNumber(vector<int> nums) {
	int i, a, b, c, tmpa, tmpb, tmpc;
	a = 0;
	b = 0;
	c = 0;
	for (const int& x : nums) {
		// 第一种
		tmpa = a;
		tmpb = b;
		tmpc = c;
		a = a & ~tmpb & ~tmpc & ~x | ~a & tmpb & tmpc & x;
		b = ~tmpa & b & (~tmpc | tmpc) | ~tmpa & x & (b ^ tmpc);
		c = ~tmpa & (c ^ x);
	}
	return c;
}

int main() {
	vector<int> nums{3,3,3,3,3,2,2,2,2,2,6,6,6,6,6,4,4,4,10,4,4 };
	cout<<"打印结果:"<<singleNumber(nums) << endl;
	return 0;
}

2.「分别计算」

发现上面化简 c 后,式子很简洁:

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int singleNumber(vector<int> nums) {
	int i, a, b, c, tmpa, tmpb, tmpc;
	a = 0;
	b = 0;
	c = 0;
	for (const int& x : nums) {
		// 第二种
		c = ~a & (c ^ x);
		b = ~a & ~c & (b ^ x) | ~a & b & c;
		a = ~b & ~c & (a ^ x);
	}
	return c;
}

int main() {
	vector<int> nums{3,3,3,3,3,2,2,2,2,2,6,6,6,6,6,4,4,4,10,4,4 };
	cout<<"打印结果:"<<singleNumber(nums) << endl;
	return 0;
}

我的解法,不知道是否正确,仅供参考!

相关推荐
海盗猫鸥2 小时前
C++入门基础篇(1)
开发语言·c++·学习
Thunter_4 小时前
[QT入门]树形视图控件
开发语言·c++·qt
Chris-zz4 小时前
C++:继承
开发语言·c++·算法·学习方法
川爻5 小时前
String类(STL开始)
开发语言·c++
取加若则_5 小时前
C++入门(C语言过渡)
c语言·开发语言·数据结构·c++·算法
YangZheng@5 小时前
23种设计模式
c++·算法·设计模式
枫yy6 小时前
C++入门 容器适配器 / stack && queue模拟实现
开发语言·c++
溪渣渣_梁世华7 小时前
Qt 进程间通信(一)——QSharedMemory共享内存
c++·qt·进程间通信
程序员爱德华7 小时前
C++(week10):C++基础: 第二章 类与对象
c++·类和对象
小李很执着7 小时前
【掌握C++ string 类】——【高效字符串操作】的【现代编程艺术】
开发语言·c++·后端·学习