136. 只出现一次的数字
1.题目简介
2.题解
本题思路参考了某位大大的题解,链接:https://leetcode.cn/problems/single-number/solutions/5118/xue-suan-fa-jie-guo-xiang-dui-yu-guo-cheng-bu-na-y/
2.1 数组/哈希表解法
思路
这里很容易想法就是成对存储:数(键)和数出现的次数(键值),所以使用数组和哈希表存储都是比较容易想到的。
但是有一个关键问题(且该算法只使用常量额外空间),而这两种方法都要使用额外的空间,空间代价为o(n)
代码(这里只展示使用哈希表的解法,数组思路同理)
class Solution {
public:
int singleNumber(std::vector<int>& nums) {
std::unordered_map<int,int> map;
for (int num:nums){
map[num]++;
}
for (auto pair:map){
if (pair.second == 1) return pair.first;
}
return 0;
}
};
结果展示
这里是能过通过测试用例的,但是明显空间使用率过低
2.2暴力枚举
思路
如果想要减少空间使用,那就并不能使用数组/哈希表记录每个元素的出现次数,也就是一个时间点,我最多只能知道一个元素的出现次数
很容易想到的便是暴力枚举(两层for循环),外层循环从数组中挑出一个元素,内层循环将其与数组全员(除本身外)比较,若有相同即return
代码
class Solution {
public:
int singleNumber(vector<int>& nums) {
for (int i = 0; i < nums.size(); i++){
for(int j = 0; j < nums.size(); j++)
{
if (nums[i] == nums[j] && i != j) break;
else if(j == nums.size() - 1) return nums[i];
}
}
return false;
}
};
结果展示
并没有通过,因为这里的时间代价是o(n^2),超出了时间限制
2.3 快排+寻找
思路
如何将时间代价从o(n^2)减少到o(n)是最大的问题,快排可以将时间代价减少到O(nlogn)
这里是可以在快排途中判断并且获取答案的,这里博主偷懒,直接使用了封装好的快排,在之后进行判断;
总体算两部分,快排O(nlogn),寻找o(n),结合一下时间代价还是O(nlogn)
代码
class Solution {
public:
int singleNumber(std::vector<int>& nums) {
int count = 0;
std::sort(nums.begin(),nums.end());
for (int i = 0; i < nums.size(); i++) {
if (i == nums.size() - 1 && count == 0) return nums[i];
if (nums[i] == nums[i+1]) count++;
else if(count) count = 0;
else return nums[i];
}
return false;
}
};
结果展示
2.4 异或(最优解)
思路
这里主要利用异或归零律和交换律,恒等律
举个例子就懂了
代码
class Solution {
public:
int singleNumber(std::vector<int>& nums) {
int temp = nums[0];
for (int i = 1; i < nums.size(); i++){
temp = temp ^ nums[i];
}
return temp;
}
};