Hi 你们好,我是张小猪。欢迎来到『宝宝也能看懂』系列特别篇 - 30-Day LeetCoding Challengegit
这是一个 leetcode 官方的小活动,地址在这里(若是被重定向回中文站了,去掉域名里的 -cn
便可)。活动内容很简单,从 4 月 1 号开始,天天会选出一道题(国内时间中午 12 点更新),在 24 小时内完成便可得到一点小奖励。虽然奖励彷佛也没什么用,不过做为一个官方的打卡活动,小猪仍是来打一下卡吧,正好做为天天下班回家后的娱乐。github
这里是 4 月 1 号的题,也是题目列表中的第 136 题 -- 『只出现一次的数字』算法
给定一个非空整数数组,除了某个元素只出现一次之外,其他每一个元素均出现两次。找出那个只出现了一次的元素。shell
说明:segmentfault
你的算法应该具备线性时间复杂度。 你能够不使用额外空间来实现吗?数组
示例 1:数据结构
输入: [2,2,1] 输出: 1
示例 2:spa
输入: [4,1,2,1,2] 输出: 4
EASYcode
这道题彷佛没什么好讲的,大概是做为活动的开篇,预热一下,吸引围观,激励用户参与。blog
下面给出几个方案,供小伙伴们参考。
其实这是个凑数的方案(哈哈哈,没想到吧)。小猪相信不会有小伙伴们这么去写的,毕竟直接就到 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』 的第一题,没有太多能够说的,因而就稍微拓展了一点关于异或操做的内容。但愿能够帮到有须要的小伙伴。
若是以为不错的话,记得『三连』哦。小猪爱大家哟~ >.<