LeetCode之路:136. Single Number

来源:互联网 发布:淘宝首页钻展多少钱 编辑:程序博客网 时间:2024/06/05 16:15

一、引言

这是一道非常非常有趣,题目要求非常非常简单,做出来也非常非常容易,但是最优解却非常非常令人无奈的一道题:

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?

大概意思非常简单,我们获得一个整型数组,其中的元素呢,只有一个是单着的,其他都是成双的,让我们找到这个单个的值并返回。

题目要求算法复杂度在线性程度,并且尽量减少额外的存储空间的利用。

这是一道,怎么说呢,看上去非常非常简单,但是想要达到题设要求又比较困难的题目。不如这样,然我们先来探索,能够用什么样的方法来解决这个问题。

二、鄙人不才,想出了两个方法

首先,要找到这个单着的元素,我们需要干什么呢?

比较。

对的,比较,那么找到计数为 1 的不就可以了吗?

于是乎,map 呼之而来:

// use std::map , runtime = 23 msclass Solution1 {public:    int singleNumber(vector<int> &nums) {        map<int, int> map;        for (auto i : nums) ++map[i];        for (auto j : map) if (j.second == 1) return j.first;    }};

注释里面的 runtime 是我在 LeetCode 上实跑出来的计时值。

类似的,想到了 map,自然也能想到 set,思路是一样的:

// use std::set , runtime = 25 msclass Solution2 {public:    int singleNumber(vector<int> &nums) {        set<int> set;        for (auto i : nums)            if (set.find(i) == set.end()) set.insert(i);            else set.erase(i);            return *set.begin();    }};

哈哈,使用 set 反而比使用 map 还要慢,估计是因为 find 方法的缘故吧。

那么问题来了,这两个方法都不是 O(n) 复杂度的算法,并且使用了额外的 nums.size()个存储空间,有什么好的方法呢?

我百思不得其解.
我百思不得其解..
我百思不得其解…

于是乎,点开了 Discuss.
于是乎,点开了 Discuss..
于是乎,点开了 Discuss

三、XOR is always the trick…

看到这个评论,内心是非常戏剧性的:

XOR is always the trick

哈哈哈,又被异或给坑了的感觉油然而生…

让我们看看这段代码:

// use xor , runtime = 13 msclass Solution3 {public:    int singleNumber(vector<int> &nums) {        int single = 0;        for (auto i : nums) single ^= i;        return single;    }};

看不懂吧?

没事,有个外国兄弟解释的非常清楚:

For anyone who didn’t understood why this works here is an explanation. This XOR operation works because it’s like XORing all the numbers by itself. So if the array is {2,1,4,5,2,4,1} then it will be like we are performing this operation
((2^2)^(1^1)^(4^4)^(5)) => (0^0^0^5) => 5.
Hence picking the odd one out ( 5 in this case).

看明白了吗?看不懂我来解释解释。

也就是说,我们遍历的时候,循环异或赋值本身,因为
相同为0,不同为1
异或原则,总有一个单着的无法异或掉,前面所有的相同的异或掉只剩下了一堆 0, 而 0 又异或这个单着的值,而又由于在计算机中,非 0 值均为真值,这里自然就返回了不同为真的值 5。

真的非常非常的奇妙!

异或的妙用我已经见了不少了,博客里零零碎碎也记了很多。

最后以那个外国兄弟的感慨结尾:

exactly :) XOR is always the trick

0 0