返回
位运算 - 巧妙求解 LeetCode 260 - 只出现一次的数字 3
前端
2024-01-14 00:59:40
数组中可能包含重复的数字,但我们保证其中一定存在两个只出现一次的数字。你的任务是找出这两个独一无二的数字。
/**
* 给定一个包含重复数字的数组 nums ,返回其中唯一出现的两个数字。
*
* 示例 1:
* 输入:nums = [1,2,1,3,2,5]
* 输出:[3,5]
* 解释:[5, 3] 也是有效的答案。
*
* 示例 2:
* 输入:nums = [-1,0]
* 输出:[-1,0]
*
* 示例 3:
* 输入:nums = [0,1,0]
* 输出:[1]
*
* 示例 4:
* 输入:nums = [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]
* 输出:[2, 4]
*/
const singleNumber = (nums) => {
// 第一步:计算所有数字的异或值
let xor = 0;
for (const num of nums) {
xor ^= num;
}
// 第二步:找到异或值二进制表示中第一个为 1 的位置
let i = 0;
while (xor & (1 << i) === 0) {
i++;
}
// 第三步:将数组分为两部分,一部分是异或值为 1 的数字,另一部分是异或值为 0 的数字
const group1 = [];
const group2 = [];
for (const num of nums) {
if (num & (1 << i)) {
group1.push(num);
} else {
group2.push(num);
}
}
// 第四步:在两部分中分别找出只出现一次的数字
const result = [];
for (const num of group1) {
if (group1.filter((n) => n === num).length === 1) {
result.push(num);
}
}
for (const num of group2) {
if (group2.filter((n) => n === num).length === 1) {
result.push(num);
}
}
return result;
};
在这个算法中,我们使用了位运算来巧妙地找出两个只出现一次的数字。具体步骤如下:
-
计算所有数字的异或值 :异或运算符(^)可以将两个数字的二进制位逐位异或,相同则为 0,不同则为 1。因此,将数组中所有数字的异或值计算出来,就可以得到一个只包含两个只出现一次的数字的异或值。
-
找到异或值二进制表示中第一个为 1 的位置 :异或值二进制表示中第一个为 1 的位置,就是两个只出现一次的数字在二进制表示中不同的地方。
-
将数组分为两部分 :根据异或值二进制表示中第一个为 1 的位置,将数组分为两部分,一部分是异或值为 1 的数字,另一部分是异或值为 0 的数字。
-
在两部分中分别找出只出现一次的数字 :在两部分中分别找出只出现一次的数字。由于两部分的数字都只出现一次,因此我们可以通过遍历数组,并统计每个数字出现的次数,来找出只出现一次的数字。
使用这种方法,我们可以在 O(n) 的时间复杂度内找到两个只出现一次的数字。这种方法简洁高效,并且很容易理解和实现。
我希望这篇文章对您有所帮助。如果您有任何问题或建议,请随时告诉我。