【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;
    }
};

四、错误回顾

不会用集合和哈希表。

相关推荐
青少儿编程课堂18 分钟前
蓝桥杯+全国青少年信息素养大赛+电子学会PythonC/C++考级:最长公共子序列LCS解析
c++·python·算法·bfs·信息学竞赛
圣保罗的大教堂1 小时前
leetcode 3727. 最大交替平方和 中等
leetcode
倚楼听风语2 小时前
Kotlin 协程与 suspend 原理详解
java·算法·kotlin
Xin7702 小时前
LeetCode 200. 岛屿数量(DFS 深度优先遍历法)
leetcode
程序员清风2 小时前
双指针与滑动窗口:高效处理连续区间
开发语言·算法
代钦塔拉2 小时前
【C++/Qt 进阶】设计模式系列(2):工厂模式——从游戏角色到披萨店
c++·算法·设计模式
思茂信息2 小时前
电磁仿真学涉及哪些算法?
人工智能·算法·数学建模·matlab·emc·电磁仿真·仿真辐射
糖果豆豆2 小时前
让 AI 自查三遍,它只会把错的说得更像对的——检查的人和被检查的,是同一个
算法·架构
总裁余(余登武)4 小时前
K-means算法改进(Python版)
python·算法·kmeans
灯澜忆梦4 小时前
【面向对象编程c++】| 指针与自定义数据类型
开发语言·c++·算法