Hi 大家好,我是张小猪。欢迎来到『宝宝也能看懂』系列特别篇 - 30-Day LeetCoding Challenge
这是一个 leetcode 官方的小活动,地址在这里(如果被重定向回中文站了,去掉域名里的 -cn
即可)。活动内容很简单,从 4 月 1 号开始,每天会选出一道题(国内时间中午 12 点更新),在 24 小时内完成即可获得一点小奖励。虽然奖励似乎也没什么用,不过作为一个官方的打卡活动,小猪还是来打一下卡吧,正好作为每天下班回家后的娱乐。
这里是 4 月 1 号的题,也是题目列表中的第 136 题 -- 『只出现一次的数字』
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4
EASY
这道题似乎没什么好讲的,大概是作为活动的开篇,预热一下,吸引围观,激励用户参与。
下面给出几个方案,供小伙伴们参考。
其实这是个凑数的方案(哈哈哈,没想到吧)。小猪相信不会有小伙伴们这么去写的,毕竟直接就到 O(n^2) 了,实在是太浪费了。权且作为最最基础的实现吧。
const singleNumber = nums => { const arr = []; for (const n of nums) { const idx = arr.indexOf(n); idx === -1 ? arr.push(n) : arr.splice(idx, 1); } return arr.pop(); };
用 Set
代替了方案 1 中的数组,使得查询和删除都快了很多。不过代码还是太多了,并且也得基于额外的数据结构和空间,并不推荐。
const singleNumber = nums => { const set = new Set(); for (const n of nums) { set.has(n) ? set.delete(n) : set.add(n); } for (const x of set.keys()) return x; };
用位操作代替了前两种方案里对于额外数据结构和空间的依赖。小猪觉得这个方案算是这道题的标准实现吧,才不会告诉你前两种方案是为了写文章才凑出来的呢 hia hia hia O(∩_∩)O
稍微解释一下异或这个位操作吧,它的行为逻辑可以理解为两个值不同则为 true
,相同则为 false
。如下表:
0 ^ 0 === 0 0 ^ 1 === 1 1 ^ 0 === 1 1 ^ 1 === 0
那么基于这个运算逻辑,我们可以发现,对于两个相同的数值进行异或运算,那么结果一定是 0。再看看我们题目中的数据,正好是成对的数字加上一个单独的数字。这时候再加上异或这个运算可以满足交换律和结合律,于是我们那些成对的数字运算完后正好为 0,而 0 与一个数字进行异或预算便是这个数字本身。
基于这个思路,我们可以得到如下的代码:
const singleNumber = nums => { let ret = 0; for (const n of nums) ret ^= n; return ret; };
当然,都写成这样了,不如我们就直接一行吧:
const singleNumber = nums => nums.reduce((prev, cur) => prev ^ cur, 0);
关于异或操作的一些实际应用场景,这里再补充几个栗子吧。
let a = 10; let b = 20; a = a ^ b; b = b ^ a; a = b ^ a; console.log(a, b) // 20, 10
稍微解释一下过程吧:
a
。b
中两个数不同的位取反,相同的位保持不变,于是 b 就变成了 a,然后保存进变量 b
中。b
中两个数不同的位取反,相同的位保持不变。注意,这时候的 b
中的值其实是 a,所以运算后得到的值是 b,然后保存进变量 a
里。b
,b 就进了 a
。let a = 10; let b = 20; while (b !== 0) { const a2 = a ^ b; const b2 = (a & b) << 1; a = a2; b = b2; } console.log(a) // 30
同理,不过这里面还用到了与操作和左移操作。原理其实和加法是一样的,就是按位相加,然后需要进位的地方就进位。不过在二进制中,可能的情况会比较少。具体如下:
这是 『30-Day LeetCoding Challenge』 的第一题,没有太多可以说的,于是就稍微拓展了一点关于异或操作的内容。希望可以帮到有需要的小伙伴。
如果觉得不错的话,记得『三连』哦。小猪爱你们哟~ >.<