新年第一篇文章,先祝你们新年快乐!!那么接下来进入正文。javascript
前阵子突发奇想,忽然开始刷leetcode。其中刷到了一道有意思的题目,发现这道题是当时秋招的时候,腾讯面试官曾经问过个人题目。因而分享给你们看下。java
给定一个非空整数数组,除了某个元素只出现一次之外,其他每一个元素均出现两次。找出那个只出现了一次的元素。git
这道题第一眼看过去,思路挺简单的,咱们只须要维护一个对象来记录每个元素出现的次数,使用元素的值做为key,元素出现的次数做为value。以后再遍历这个对象,找到value为1的key。对应的key就是那个元素。代码以下:github
function singleNumber(nums) { const obj = {}; for (let i = 0; i < nums.length; i++) { obj[nums[i]] = obj[nums[i]] ? obj[nums[i]] + 1 : 1; } for (let key in obj) { if (obj[key] === 1) { return Number(key); // 因为 key 是 string ,所以咱们这里须要转化下 } } } console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8])); // 8
是吧,这道题很简单,那我为何要说它有意思呢?
由于题目里面其实还有一个限制:面试
你的算法应该具备线性时间复杂度。 你能够不使用额外空间来实现吗?算法
重点在于不使用额外空间。咱们上面那种解法,建立了一个新的对象来储存结果,明显是不行的。那么有没有办法能够只使用原来的数组来实现这个功能呢?数组
咱们能够思考下,一个数组里,全部的数字都出现两次,除了一个咱们要找的数字只出现一次。那么,咱们有没有办法将两个相同的数字给过滤掉呢?学习
好啦,不卖关子了,以前有了解过的人应该就知道解决方案了,若是以前没了解过这方面东西的人,能够继续往下看。code
解决方案:异或操做对象
异或运算是对于二进制数字而言的,好比说一个有两个二进制a、b,若是a、b两个值不相同,则异或结果为1。若是a、b两个值相同,异或结果为0。
而javascript的按位异或(即^操做)操做,则会对两个数字相应的每一对比特位执行异或操做。
好比说 1 ^ 2,本质上实际上是1和2的每一对比特位执行异或操做,等价于下面
00000000000000000000000000000001 // 数字1对应的二进制 ^ 00000000000000000000000000000010 // 数字2对应的二进制 = 00000000000000000000000000000011 // 数字3对应的二进制
所以1^2的结果就为3啦。
那么若是两个相同的数字进行异或操做,结果就可想而知,答案为0啦。
若是是0和任何一个数字异或呢?结果是数字自己。
咱们举个栗子:
假设咱们有一个数组,里面元素为[a, a, c, c, b, b, d]。那么咱们对数组里的全部元素进行按位异或操做,即a ^ a ^ c ^ c ^ b ^ b ^ d,是否是就等价于0 ^ 0 ^ 0 ^ d = d。而d就是数组里只出现一次的元素。
那么咱们能够扩展一下,对于任意知足某个元素只出现一次之外,其他每一个元素均出现两次的数组,是否是能够经过这种方式来获得那个只出现一次的元素。
这样一来的话,咱们是否是有了这个问题的解决办法了?咱们只须要遍历数组,将全部的值取异或,最终剩下的值,就是那个只出现一次的数字。代码以下:
/** * 只存在一次的数字 * https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/1/array/25/ * @param {number[]} nums * @return {number} */ function singleNumber(nums) { for (let i = 1; i < nums.length; i++) { nums[0] ^= nums[i]; } return nums[0]; }; console.log(singleNumber([2, 2, 1, 4, 4, 5, 5, 1, 8]));
这道面试题主要考验面试者对异或的理解,以及能不能活学活用,将这道题与异或联系在一块儿。固然,最重要的仍是多学习、多刷题、多看书。这样才能不断进步。
本文地址在->本人博客地址, 欢迎给个 start 或 follow