zoukankan      html  css  js  c++  java
  • Algorithm:位运算的这些小技巧你知道吗?

    位运算的巧妙之处

    算法中,位运算可以巧妙运用在一下几个方面:

    1、判断奇偶数 => x&1

    2、判断数x中第k ( 从右至左 ) 位是1还是0

    ​ 法1:( x >> ( k - 1 ) ) & 1

    ​ 法2:x & ( 1 << ( k - 1 ) )

    3、交换两个整数变量 a , b 的值

    a = a ^ b;
    b = b ^ a;
    a = a ^ b;
    

    这里为什么能这样做,在后面的异或运算中会说明;

    4、不用判断语句,求整数绝对值

    return (value ^ (value >> 31))-(value >>31)
    

    同样在异或运算中说明;

    应用

    二进制中1的个数

    描述:实现一个函数,输入一个正整数,输出该数二进制表示中1的个数。

    例:9的二进制表示为1001,有2位是1;

    思路:循环运用判断x的第k位是否为1的方法;

    int count=0;
    while(value)
    {	
    	count += value & 1;
    	value = value >> 1;
    }
    return count;
    

    方法二:

    &运算有这样一个性质:a = ( a - 1 ) & a ; 这样a就能消除最低位的一个1

    思路:利用这一性质,我们可以每次将value-1,然后与自己&,能做多少次这样的操作就说明有多少个1;

    int count=0;
    while(value)
    {
    	value = (value - 1) & value;
    	count++;
    }
    return count;
    

    异或运算的巧妙之处

    性质

    异或又称不进位加法,两个数相异或,对应位相同则为0,不同则为1;

    具有以下性质:

    1、a ^ a = 0;

    2、0 ^ a = a;

    3、异或具有交换律和结合律

    ​ b ^ c = c ^ b;

    ​ a ^ b ^ c = a ^ ( b ^ c) = ( a ^ b ) ^ c;

    4、( -1 ) ^ a =!a;

    应用

    交换两个变量的值

    交换变量a,b的值

    a = a ^ b;
    b = b ^ a;
    a = a ^ b;
    

    利用异或运算的交换律和结合律,可以得到如下:

    1、a = a ^ b;

    2、b = b ^ a;

    把1式代入2式中,此时 b = b ^ ( a ^ b ) ,则 b = b ^ b ^ a = a;

    3、a = a ^ b;

    将1式和 b = a 代入3式,则 a = a ^ b ^ a = b;

    不用判断语句,求整数绝对值

    return (value ^ (value >> 31))-(value >>31)
    

    1、若value为正数,则value二进制表示中最高位一定为0,那么 value >> 31 =0;

    value ^ (value >> 31) = value ^ 0 = value;

    value - (value >> 31) = value - 0 = value;

    即正数的绝对值仍是自身;

    2、若value为负数,则value二进制表示中最高位一定为1,那么 value >> 31 = 111…1 ,一共32个1,即-1;

    value ^ (value >> 31) = ! value;

    而负数以补码形式存放,补码等于绝对值的原码取反+1;

    那么这里 ! value - (value >> 31) => ! value +1 即得到的是value的绝对值;

    如果理解有困难,可以看这个例子:

    如何找唯一成对的数?

    问题描述:1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,在不用辅助存储空间的前提下,设计一个算法,将它找出来;

    思路:根据异或性质1: a ^ a = 0;可以用来去重;

    令T = 1 ^ 2 ^ 3 ^… ^ 1000 ;

    那么遍历数组的同时将当前数字与 T 异或,在数组中只出现一次的数字会与 T 中的该数字相抵消,从而去重;最终会剩下重复的那个元素,因为它在数组和T中一共出现3次;

    举一个只有11个数的例子: 重复的元素在任意位置出现都是可以找出来的;

    int T=0;
    for(int i=1;i<=1000;i++)
    {
    	T=T^i;      
    }
    for(int i=0;i<=1000;i++)
    {
    	T=T^A[i];
    }
    return T;
    

    如有错误,感谢指正!

  • 相关阅读:
    C++之用程序理解浅拷贝
    es6 | 新增语法 | 总结
    http协议 | http缓存
    Mobx | 强大的状态管理工具 | 可以用Mobx来替代掉redux
    nohup和&后台运行,进程查看及终止
    MIME Type介绍 Content-Type 各种定义
    Meta http-equiv属性详解(转)
    sublme text 3 快捷键
    【坑】【数组的坑】1、对象assign复制的假深度,2、数组slice复制的坑,3、还有数组map复制的坑
    Proxy监听对象的数据变化,处理绑定数据很有用
  • 原文地址:https://www.cnblogs.com/Luweir/p/14147373.html
Copyright © 2011-2022 走看看