【leetcode】136.只出现一次的数字

文章目录


碎碎念

好!自此已经刷完hot100的所有简单题!只是还欠了好多篇题解还没写,一点一点跟上吧!今天还学了一点简单的响应式布局,还差一个flex布局就真的算小小小小入门前端啦,项目也有一点点在拉起来了,今天很好很好!


一、题目

二、思路和题解

1.思路

这题首先想到的是用集合,遍历整个整个nums,出现第一次就加入集合,出现第二次再从集合中删除,当遍历完整个数组,就只剩下只出现一次的数啦。但是!思路很美好,苯人技术还是有比较大的进步空间的...我不是很会用集合...

所以还是看了一下题解学到一个思路,是用异或来做。

我们知道异或是 "同0异1" ,基本的运算规则如下:
0 ⊕ 0 = 0 0 ⊕ 1 = 1 1 ⊕ 0 = 1 1 ⊕ 1 = 0 0 \oplus 0=0\\ 0 \oplus 1=1\\ 1 \oplus 0=1\\ 1 \oplus 1=0 0⊕0=00⊕1=11⊕0=11⊕1=0

所以当我们初始化一个res=0,之后遍历整个数组,对每个数都做异或运算,这样只要出现两次的数就会自己和自己异或"消除掉"了,最后剩下的数就相当于与0异或还是它自己,也就是我们要找的只出现一次的数了。

2.代码(位运算,异或)

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res=0;
        for (auto v:nums){
            res^=v;
        }
        return res;
    }
};

三、其他解法

这里当然就得补充一下咱们刚刚提到的集合的做法了(在学了在学了!)

1.集合增删法

思路就不赘述了,直接上代码。

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
    	// acm的话记得包含<unordered_set>头文件
        unordered_set<int> s; // 定义无序集合,查询/增删效率为O(1)
        
        for (int num : nums) {
            if (s.count(num)) { // 集合中已有该数字(出现第二次)
                s.erase(num);   // 从集合删除
            } else {            // 集合中无该数字(出现第一次)
                s.insert(num);  // 加入集合
            }
        }
        
        // 最终集合中只有一个元素,返回该元素(*s.begin()取第一个元素)
        return *s.begin();
    }
};

2.哈希表统计次数

先用哈希表来存储「数字 → 出现次数」,接着遍历数组统计每个数字的出现次数,最后再遍历哈希表,找到出现次数是1次的数字,就是我们的答案啦。

cpp 复制代码
#include <vector>
#include <unordered_map> // 哈希表头文件
using namespace std;

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> count_map; // key=数字,value=出现次数
        
        // 统计每个数字的出现次数
        for (int num : nums) {
            count_map[num]++; // 不存在的key会自动初始化为0,再+1
            /*也可以写成下面这样,更好理解一点:
            看一下num在不在这个哈希表中,如果不在哈希表中,则查找到的是哈希表的尾后迭代器,那就需要新增。
            if (count_map.find(num) != count_map.end()) {
			    count_map[num] += 1;
			} else {
			    count_map[num] = 1;
			}*/
        }
        
        // 遍历哈希表找次数=1的数字
        for (auto& pair : count_map) {
            if (pair.second == 1) { // pair.second 是次数
                return pair.first;  // pair.first 是数字
            }
        }
        
        return -1; // 题目保证有解,仅防止编译报错
    }
};

3.集合求和差值

这个稍微有点技巧性(我觉得),这里我们用到的是这样一个公式:
唯一数 = 2 × ( 集合所有元素和 ) − ( 数组所有元素和 ) 唯一数=2×(集合所有元素和)−(数组所有元素和) 唯一数=2×(集合所有元素和)−(数组所有元素和)

  • 集合存储所有唯一元素,因此「集合和 ×2」等价于「所有元素都出现 2 次的总和」;
  • 数组总和 = 「唯一数 ×1」 + 「其余数 ×2」;
  • 两者的差值就是唯一数(其余数的 2 倍被抵消,只剩唯一数)。
cpp 复制代码
#include <vector>
#include <unordered_set>
#include <numeric> // 求和函数 accumulate 的头文件
using namespace std;

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_set<int> s(nums.begin(), nums.end()); // 集合存储所有唯一元素
        
        // 手动遍历求和
        long long sum_set = 0;
        for (int num : s) {
            sum_set += num;
        }
        
        // 也可以用STL的accumulate函数,但acm要记得包含<numeric>头文件
        // long long sum_set = accumulate(s.begin(), s.end(), 0LL);//0LL表示以 long long 类型初始化累加值,否则 accumulate 会默认用 int 累加,可能溢出
        
        // 计算数组所有元素的和
        long long sum_nums = accumulate(nums.begin(), nums.end(), 0LL);
        
        return 2 * sum_set - sum_nums;
    }
};

四、错误回顾

不会用集合和哈希表。

相关推荐
寻寻觅觅☆5 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
偷吃的耗子6 小时前
【CNN算法理解】:三、AlexNet 训练模块(附代码)
深度学习·算法·cnn
化学在逃硬闯CS6 小时前
Leetcode1382. 将二叉搜索树变平衡
数据结构·算法
ceclar1237 小时前
C++使用format
开发语言·c++·算法
Gofarlic_OMS7 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
夏鹏今天学习了吗7 小时前
【LeetCode热题100(100/100)】数据流的中位数
算法·leetcode·职场和发展
忙什么果8 小时前
上位机、下位机、FPGA、算法放在哪层合适?
算法·fpga开发
董董灿是个攻城狮8 小时前
AI 视觉连载4:YUV 的图像表示
算法
ArturiaZ9 小时前
【day24】
c++·算法·图论
大江东去浪淘尽千古风流人物9 小时前
【SLAM】Hydra-Foundations 层次化空间感知:机器人如何像人类一样理解3D环境
深度学习·算法·3d·机器人·概率论·slam