算法中的与、异或运算

简介: 算法中的与、异或运算

与运算

认识&

& 按位与操作,按二进制位进行"与"运算。运算规则:(有 0 则为 0)

  • 0 & 0 = 0;
  • 0 & 1 = 0;
  • 1 & 0 = 0;
  • 1 & 1 = 1;

-x的含义 与 x & (-x)

-x 的值, 其实就是在x的值的基础上进行按位取反(~x)之后在增加1所得,即x & -x == x & (~x + 1)

x为偶数

x = 0000 0100 1110   // 假设x为偶数,比如0000 0100 1110
~x = 1111 1011 0001 // 取反后就是1111 1011 0001   
~x+1 = 1111 1011 0001 + 1 = 1111 1011 0010   // 再加1就等于1111 1011 0010
x & (~x + 1) = 0000 0000 0010        //x & (-x)的结果就是0000 0000 0010
复制代码

x为奇数

x = 0000 0100 1111    // 假设x为奇数,比如 0000 0100 1111
~x = 1111 1011 0000  // 取反后为1111 1011 0000
~x+1 = 1111 1011 0001 //由于~x的值一定是偶数,因此加1时必不会产生进位
x & (~x + 1) = 0000 0000 0001  // x & (~x + 1)结果就是 0000 0000 0001,最后一位必定为1,其他位必定为0
复制代码

结论:

  • x为偶数,x & (-x)的二进制表达式只会有一位保留为1
  • x为奇数,x & (-x)的二进制表达式最后一位必定为1,其它为0
  • x为0时,x & (-x)的二进制表达式为0x & (-x) 一般是用来获取某个二进制数的最低位的1所对应的值

异或运算

运算符号为:⊕(代码中就是^)。

如果a、b两个值不相同,则异或结果为1;如果值相同,则为0 用1表示真,0表示假,则异或运算法则为:0⊕0=0,0⊕1=1,1⊕0=1,1⊕1=0。

异或运算也被常称为不进位加法: 10110⊕00111=10001

性质

  • 满足交换律、结合律
  • 0⊕a=a、a⊕a=0 (注意1⊕a!=a)

异或运算在计算机中的应用

举个🌰——交换值:

int a = 甲
int b = 乙
a=a⊕b;   //a=甲⊕乙,b=乙
b=a⊕b;   //a=甲⊕乙,b=甲⊕乙⊕乙=甲⊕0=甲
a=a⊕b;   //a=甲⊕乙⊕甲=0⊕乙=乙,b=甲
复制代码

注意:能用这个方式的前提是,a与b所指向的是不同的内存。

LeetCode中奇妙的异或运算

LeetCode-136. 只出现一次的数字

var singleNumber = function(nums) {
    let xor = 0;
    for(let i =0;i<nums.length;i++){
        console.log(i)
        xor^=nums[i]
    }
    console.log(1^87, 0^87)
    return xor
};
复制代码

题目变形

给定一个非空整数数组,除了某个元素只出现奇数次以外,其余每个元素均出现偶数次。找出那个只出现了奇数次的元素。要求时间复杂度为O(N)O(N)O(N),空间复杂度为O(1)O(1)O(1)

思路:0逐个对数组中的元素进行异或,最后剩下的数就是只出现奇数次的元素(由于出现偶数次的数异或后就是0)

LeetCode-260. 只出现一次的数字 III

var singleNumber = function(nums) {
    let eor = 0;
    for(let i=0;i<nums.length;i++){
        eor^=nums[i]
    }
    let rightOne = eor & -eor;
    let type1 = 0;
    let type2 = 0;
    for(const num of nums){
        if(num & rightOne){
            type1 ^= num
        }else{
            type2 ^= num
        }
    }
   return([type1, type2])
};
复制代码

题目变形

给定一个非空整数数组,有两个元素出现奇数次,其余每个元素均出现偶数次。找出只出现了奇数次的元素。要求时间复杂度为O(N)O(N)O(N),空间复杂度为O(1)O(1)O(1)

  • 思路:假设出现奇数次的两个元素是x和y,那么0逐个对数组中的元素进行异或的结果为eor(eor=x^y,且eor不为0,eor必然有一个位置上为1,假设这个位置为k,那么在k位,x和y不相同);找到eor中为1的某一位,假设为第k位,按k是否为1将所有元素分为两组,这样的话,x和y分别位于不同组中;不同组中对子元素进行异或,最后结果分别就是x和y
  • 难点:如何找到eor中最右为1的位置

有关于位元算的题目

136. 只出现一次的数字

137. 只出现一次的数字 II

260. 只出现一次的数字 III

剑指 Offer II 004. 只出现一次的数字

剑指 Offer 15. 二进制中1的个数

190. 颠倒二进制位

191. 位1的个数

231. 2 的幂

338. 比特位计数

342. 4的幂

371. 两整数之和

405. 数字转换为十六进制数

461. 汉明距离

476. 数字的补数

477. 汉明距离总和

526. 优美的排列

1178. 猜字谜

1711. 大餐计数

有关链接:

我是如何进微软的?

七天刷爆LeetCode,顶级算法大神



相关文章
|
3月前
|
算法 Java C++
试题 算法训练 集合运算
试题 算法训练 集合运算
25 1
|
3月前
|
算法
算法基础:高精度运算
算法基础:高精度运算
58 0
|
10月前
|
算法 搜索推荐 C++
【C++STL基础入门】vector运算和遍历、排序、乱序算法
【C++STL基础入门】vector运算和遍历、排序、乱序算法
152 0
|
9月前
|
存储 算法
【算法基础】高精度运算
【算法基础】高精度运算
36 0
|
4天前
|
算法
聊聊一个面试中经常出现的算法题:组合运算及其实际应用例子
聊聊一个面试中经常出现的算法题:组合运算及其实际应用例子
|
2月前
|
算法 Java
Java数据结构与算法:位运算之与、或、异或运算
Java数据结构与算法:位运算之与、或、异或运算
|
2月前
|
算法
数据结构和算法学习记录——层序遍历(层次遍历)、二叉树遍历的应用(输出二叉树中的叶节点、求二叉树的高度、二元运算表达式树及其遍历、由两种遍历序列确定二叉树)
数据结构和算法学习记录——层序遍历(层次遍历)、二叉树遍历的应用(输出二叉树中的叶节点、求二叉树的高度、二元运算表达式树及其遍历、由两种遍历序列确定二叉树)
24 0
|
3月前
|
算法 C++
c++算法学习笔记 (4)高精度运算
c++算法学习笔记 (4)高精度运算
|
算法 Python
算法创作|用python解决简单的数学运算
算法创作|用python解决简单的数学运算
75 0
|
算法 C++
【C++算法图解专栏】一篇文章带你掌握高精度加减乘除运算
【C++算法图解专栏】一篇文章带你掌握高精度加减乘除运算
131 0

热门文章

最新文章