新年第一篇文章,先祝人人新年快乐!!那末接下来进入正文。
媒介
前阵子突发奇想,倏忽最先刷leetcode。个中刷到了一道有意义的题目,发明这道题是当时秋招的时刻,腾讯口试官曾问过我的题目。因而分享给人人看下。
题目形貌
给定一个非空整数数组,除了某个元素只涌现一次之外,其他每一个元素均涌现两次。找出谁人只涌现了一次的元素。
开端解法
这道题第一眼看过去,思绪挺简朴的,我们只须要保护一个对象来纪录每一个元素涌现的次数,运用元素的值作为key,元素涌现的次数作为value。以后再遍历这个对象,找到value为1的key。对应的key就是谁人元素。代码以下:
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
增添限定
是吧,这道题很简朴,那我为何要说它有意义呢?
由于题目内里实在另有一个限定:
你的算法应当具有线性时候复杂度。 你能够不运用分外空间来完成吗?
重点在于不运用分外空间。我们上面那种解法,创建了一个新的对象来贮存效果,显著是不可的。那末有无方法能够只运用本来的数组来完成这个功用呢?
终究解法
我们能够思索下,一个数组里,一切的数字都涌现两次,除了一个我们要找的数字只涌现一次。那末,我们有无方法将两个雷同的数字给过滤掉呢?
好啦,不卖关子了,之前有相识过的人应当就晓得解决方案了,假如之前没相识过这方面东西的人,能够继承往下看。
解决方案:异或操纵
异或运算是关于二进制数字而言的,比如说一个有两个二进制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