leetcode136题解

leetcode 136.Single Number

题目

Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
翻译过来就是,一堆数字里面,除了一个元素只出现一次外,其余都出现了两次。找出那个只出现一次的。
例如,【2,2,1】 程序输出结果应为1.

解题思路

光看题目的话,这道题很简单。稍微想想大概就有4种算法:
1. 双重循环。
这是最容易想到的,一个一个数比较就行。此处不给出具体代码,但需要注意的是这种算法的时间复杂度为O(n^2),并不能AC,会超过时间限制。

  1. 用一个数组标记某个元素是否出现过。
    我刚看到题目时就是这个思路,因为之前做过一道类似的题目——找寻只出现一次的ASCII码。但在做这道题时我发现好像行不通,ASCII码可以通过一个bool【256】的数组来标记,在本题中因为输入的数字大小不确定,所以没法建立一个合适大小的数组,用new的话可能又比较浪费空间。所以这种想法GG。

  2. 稍稍改变一下思路,排序+比较相邻元素 好像行得通的样子。
    具体思路就是:先对输入数组排序,然后比较相邻元素,步长为2.这里要介绍一下STL里的sort排序函数,用的是快速排序,时间复杂度为O(nlogn)。不用自己写排序算法,程序就非常简单了。
    详见AC代码思路3

  3. 使用STL中的set
    unordered_set是C++11中刚刚加入的,它基于哈希表,一个存储唯一(Unique,即无重复)元素的关联容器,容器中的元素无特别的次序关系。该容器允许基于值地快速元素检索。这里不做具体介绍,这里用它是因为其检索十分快速,我们可以用find函数很快寻找是否有相同元素,然后再做删除或插入操作即可。
    详见AC代码思路4

  4. 用异或,从位操作的角度考虑。
    可以看到leetcode里面要求的时间复杂度前几种算法已经满足了,但上述几种算法都需要额外的数据储存空间。而leetcode要求的是不使用额外的存储空间,这个我想了半天也没有想法。后来参考的leetcode上的大神代码才恍然大悟。嗯,和大神差距还是非常非常大的。
    算法很简单,就是用异或运算符。说几个很容易证明的结论,A^0=A,A^A=0.即A与0的异或是其自身,而两个相同数字的异或结果为0.知道了这个,算法也就很容易了,将数组逐个异或,结果就是只出现过一次的值。
    详见AC代码思路5

AC代码如下

思路3:

//时间32ms
class Solution {
 public:
int singleNumber(vector<int>& nums) {
      sort(nums.begin(),nums.end());
       int index=0;
       while(index<nums.size()-1){
        if(nums[index]==nums[index+1])
            index+=2;
        else
            return nums[index];
       }

return nums[index];
}
};

思路4:

//19ms
class Solution {
public:
int singleNumber(vector<int>& nums) {
 unordered_set<int> ans;
for(int i = 0;i < nums.size();++i){
    if(ans.find(nums[i]) == ans.end()) 
         ans.insert(nums[i]);
    else ans.erase(nums[i]);
}
auto it = ans.begin();
return *it;
}
};

思路5:

//13ms
class Solution {
public:
int singleNumber(vector<int>& nums) {
   int result=0;
   for(int i=0;i<nums.size();i++){
     result^=nums[i];
   }
   return result;
}
};

总结

这道题在leetcode上是easy难度,但要完全实现时间复杂度线性,无需额外空间,如果没有考虑到位操作,很难实现。
我们现在来看看每个思路运行的时间,可以看到排序+比较 最慢,可能是因为排序耗费了较多时间;用unordered_set的运行时间提高了不少,可以看到选择合适的数据结构很重要;最后的异或算法自然是运行时间最短,另外不需要额外空间。如果面试官限制了不允许使用STL及内置函数,那这道题异或算法无疑是面试官最想听到的答案。
最后总结一下,遇到这种可能有大量数据、空间复杂度要求特别严苛,普通数据结构或算法没法达到的,就可以考虑考虑位操作了。对bit的操作,一般来说,时间复杂度和空间复杂度都十分优秀。

最后一些话

今天收到了摩根IT暑期实习的拒信,有点伤心,自己确实能力不够,知识积累也不多,好像也没啥可抱怨的。Talk is cheap,show your code. 慢慢积累,慢慢进步。与诸君一起进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值