algorighm/leetcode/简单/异或运算.js
2024-06-17 21:28:36 +08:00

129 lines
5.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 异或运算是一种位运算相同为0不同为1比如110 ^ 001结果为111也可看成无进位加法这点非常有用
*/
/**
* 使用疑惑交换两个变量的值
*/
function swap() {
let a = 1;
let b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(a);
console.log(b);
}
/**
* 比较两个数,返回其中较大的那个
*/
function getMax(a, b) {
let flag = (a - b) >>> 31; // 如果b大的话结果就是个负数负数的符号位为1
return a * (flag ^ 1) + b * flag;
/* 解释:比较两个数的大小最直观的方式就是作差,然后判断差是否大于零,如果大于零则说明
被减数大如果小雨零则说明减数大我们只要拿到最高位如果是1我们就返回减数b否则
返回减数a这个时候我们需要找到某种运算在falg为1的时候它要为0flag为0的时候它要为1
所以我们把flag^1,并分别把(flag^1)和flag分别作为a,b的乘数相加的结果就是我们要求
的最大数。这里面之所以没有用到判断是因为,位本身就表示一种状态。
*/
}
/**
* https://leetcode.cn/problems/missing-number/
* 给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
* @param {number[]} nums - 如果把缺失的数补上,排序后下标和值是一一对应的
*/
function missingNumber(nums) {
let eorAll = 0,
eorHas = 0;
for (let i = 0; i < nums.length; i++) {
eorAll ^= i;
eorHas ^= nums[i];
}
eorAll ^= nums.length;
return eorAll ^ eorHas;
}
/*
分析按照题目要求如果没有缺少那个数的话0-n应该是n+1个数而且和下标一一对应因为
它们是连续的,只有那个多出的数是没有下表与其对应的(这里的对应表示它们的值相等),根据异或
的运算特点两个相同的数做异或运算的结果为0任何数和0做运算为本身我们只需把所有下标异或的结果
和所有值异或的结果做一次异或运算就可以得到多出来的那个数,如果之间缺少一个数的话数组中最后一个值
对应的是数组下标,所以也要把数组下标异或上。
*/
/**
* https://leetcode.cn/problems/single-number/
* 数组中1种数出现了奇数次其他的数都出现了偶数次,返回出现了奇数次的数。
* @param {number[]} nums - 这个数组里面有某个数只出现了奇数次
*/
function singleNumber(nums) {
let eor = 0;
for (let num of nums) {
eor ^= num;
}
return eor;
}
/**
* 原理这个很简单两个相同的数异或结果为0任何数和0异或结果为本身如果数组中所有
* 的除了一中出现奇数次,其余数属出现偶数次,那么异或的结果必定是这个出现奇数次的数,因为
* 所有偶数次的数异或结果为00在和这个出现奇数次的数异或结果为这个奇数次的数。
*/
/**
* 给你一个整数数组 nums其中恰好有两个元素只出现一次其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
* @param {number[]} nums
* @return {number[]}
*/
function DoubleNumber(nums) {
let eor1 = 0;
for (let num of nums) {
// 把所有的数值都异或一遍,最后留下的结果就是两个奇数次数异或的结果
eor1 ^= num;
}
// 由于异或的性质两个数异或的结果如果某位上是1则说明这两个数原本这位上一位为1一位为0只需
let rightOne = eor1 & -eor1; // 重要技巧与eor1 &~eor1 + 1等价效果为取出最右侧的1
let eor2 = 0;
for (let num of nums) {
if ((num & rightOne) === 0) {
// 数组中的所有数要么这位是0要么是1,刚好分开了a和b
eor2 ^= num;
}
}
return [eor2, eor1 ^ eor2];
}
/**
* 思路把所有数都异或起来最后留下的数就是a和b异或的结果a和b在某位上肯定是不相等的假设a在某位上是1
* b在某位上是0那么这位上异或的结果就是1而这个一刚好就是异或结果最右侧的1再来看整个数组的数由于是
* 二进制那么所有的数在这位上要么是1要么是0其中a,和b也分别在这两组数中现在我们只需要求出a或者求出b
* 那么eor1 ^ a 的结果就是b,eor1 ^ b的结果就是a
*/
/**
* https://leetcode.cn/problems/single-number-ii/
* 给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
* @param {number[]} nums
* @return {number}
*/
var singleNumberOne = function (nums) {
let ans = 0;
for (let i = 0; i < 32; i++) {
let total = 0; // 统计每一位上的和
for (let num of nums) {
total += (num >> i) & 1;
}
// 判断total是否能被三除净如果除不尽这个位置就是1
if (total % 3 !== 0) {
ans |= 1 << i;
}
}
return ans;
};
/**
* 思路:我们统计每个数每一位上的数值累加总和,首先我们不考虑只出现一次的那个数,其余出现
* 三次的数累加起来对3求模的结果一定是0我们再把多出的那个数考虑进去如果多出的那个数某
* 位上面是0那么求模的结果还是0如果是1那么total求模的结果就是1而这个1我们要把它放到
* 对应的位置上去对nums的所有数的每一位都做处理后所得的结果就是只出现一次的那个数。
*/