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

四、错误回顾

不会用集合和哈希表。

相关推荐
少许极端12 小时前
算法奇妙屋(四十六)-二分答案
算法·二分答案
漂流瓶jz13 小时前
UVA-120 煎饼 题解答案代码 算法竞赛入门经典第二版
数据结构·c++·算法·排序·aoapc·算法竞赛入门经典·uva
paeamecium13 小时前
【PAT甲级真题】- Stack (30)
数据结构·算法·pat考试·pat
黎阳之光13 小时前
黎阳之光核工厂202应急管控平台|全域实景孪生,筑牢核安全最后一道防线
大数据·人工智能·算法·安全·数字孪生
优秀13513 小时前
计算机基础面试重点知识
网络·面试·职场和发展
莫等闲-13 小时前
代码随想录一刷记录Day31——leetcode56. 合并区间 738.单调递增的数字
数据结构·c++·算法·leetcode
克里普crirp13 小时前
短波通信的可用频率计算方法
人工智能·算法·机器学习
剑挑星河月13 小时前
45.跳跃游戏Ⅱ
数据结构·算法·leetcode
hqyjzsb14 小时前
AI培训课程怎么设计才有效?
人工智能·职场和发展·aigc·产品经理·学习方法·业界资讯·设计语言
MegaDataFlowers14 小时前
1.两数之和
算法