算法:位运算

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法:位运算相关的知识,希望对你有一定的参考价值。

位运算

位运算:与 &,或 |,非 ~,异或 ^, 左移 << , 右移 >>
        >>> : 运算符用0填充高位
        >> : 运算符用符号位填充高位
        判断奇数与偶数:x & 1 == 1 , x为奇数 ; x & 1 == 0, x为偶数

 题1:找出唯一成对的数
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。
每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
算法思路:利用异或可以消除重复元素,将0和1-1000分别异或,再和arr数组元素分别异或,消除重复元素,剩下的一个元素即是要找的元素。
public class FindNumber {
    public static void main(String[] args){
        int N = 1001 ;
        int [] arr = new int [N] ;
        for(int i=0; i<N-1; i++){ //将1-1000存储到数组中
            arr[i] = i + 1 ;
        }
        arr[N - 1] = (int)(Math.random() * 999 + 1) ; //最后一个数字是随机数
        for(int i=0; i<arr.length; i++){
            System.out.println(arr[i] + " ") ;
        }
        System.out.println() ;

        int value = 0 ;
        for(int i=1; i<N; i++){ //0与其它值异或得到其它值
            value = value ^ i ;
        }
        for(int j=0; j<N; j++){ //异或可以消除重复的值
            value = value ^ arr[j] ;
        }
        System.out.println(value) ;
    }
}
题2:判断十进制数对应二进制数1的个数
输入一个十进制数字,判断对应二进制数各位上共有多少个1 ?
思路1:number与1按位与,然后1依次左移,number & (1 << i) 等于 1 << i, 则说明number对应二进制该位置为1.
public class CountOne {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in) ;
        int number = input.nextInt() ;
        int count = 0 ;
        for(int i=0; i<32; i++){
            if((number & (1 << i)) == (1 << i)){
                count ++ ;
            }
        }
        System.out.println(count) ;
    }
}
思路2:将number依次按位右移,然后和1按位与,如果结果为1,则可以说明number对应位置为1
import java.util.Scanner;

public class CountOneNumber {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in) ;
        int number = input.nextInt() ;
        int count = 0 ;
        for(int i=0; i<32; i++){
            if(((number >>> i) & 1 ) == 1){
                count ++ ;
            }
        }
        System.out.println(count) ;
    }
}
思路3:将number和number-1进行按位与运算,消除最低位,直至number等于0
import java.util.Scanner;

public class CountOneNumber {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in) ;
        int number = input.nextInt() ;
        int count = 0 ;
      
       while(number != 0){
           number = (number - 1) & number ;
           count ++ ;
       }
        System.out.println(count) ;
    }
}
 题目3:0~1间浮点实数的二进制表示
键盘输入一个介于0和1之间的实数, (如0.625), 类型为double,打印它的二进制表示(0.101),
 因为小数点后的二进制分别表示0.5,0.25,0.125......)如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”
 思路:小数,乘2,取整;整数,除2,取余
import java.util.Scanner;

public class PrintBinaryNumber {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in) ;
        double number = input.nextDouble() ;
        StringBuilder result = new StringBuilder("0.") ;
        while(number > 0){
            double value = number * 2 ;
            if(value >= 1){ //乘2,大于等于1,则在结果后面追加1
                number = value - 1 ;
                result = result.append(1) ;
            }
            else{ //乘2小于等于1,则在结果后面追加0
                number = value ;
                result = result.append(0) ;
            }
            if(result.length() > 34){ //不能用32位表示,则打印ERROR
                System.out.println("ERROR") ;
            }
        }
    }
}
题目4: 键盘输入一个正整数,判断一个数字是否是2的整数次方,是则输出YES,否则输出NO。
思路:该正整数对应的二进制数各位上一共只有一个1,因此只需要判断整数数对应二进制数各位上共有1的个数即可。

import java.util.Scanner;

public class TwoPowerDemo {
    public static boolean judge(int number){
        int count = 0 ;
        for(int i=0; i<32; i++){
            if((number & (1 << i)) == (1 << i)){
                count ++ ;
            }
        }
        if(count == 1){
            return true ;
        }
        return false ;
    }
    public static void main(String[] args){
        Scanner input = new Scanner(System.in) ;
        int number = input.nextInt() ;
        if(judge(number)){
            System.out.println("YES") ;
        }else{
            System.out.println("NO") ;
        }
    }
}
题目5:将键盘输入的十进制整数对应的二进制整数的奇偶位互换
思路:将整数与0xaaaaaaaa按位与,提取偶数位,将整数与0x55555555按位与,提取出奇数位,然后将提取出的偶数位右移一位,将提取出的奇数位左移一位,然后将偶数位与奇数位进行异或处理就是将奇数位与偶数位互换。
import java.util.Scanner;

public class SwapOddEven {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in) ;
        int number = input.nextInt() ;
        int even = number & 0xaaaaaaaa ;
        int odd = number & 0x55555555 ;
        int result = (even >> 1) ^ (odd << 1) ;
        System.out.println(result) ;
    }
}
题目6: 出现k次与出现1次
数组中只有一个数出现了1次, 其他的数都出现了k次, 请输出只出现了1次的数。(假设k等于3)
思路1:将每个数字转换成k进制字符数组并翻转,然后做不进位加法,求出对应的数字就是只出现1次的数字
public class PrintSpecialNumber {
    public static void main(String[] args){
        int [] arr = {2,2,2,4,4,4,1,7,7,7,3,3,3,6,6,6,0,0,0} ;
        int length = arr.length ;
        char [][] elements = new char [length][] ;
        int k = 3;
        int maxLength = 0 ;
        //对每个数字,转成k进制字符数组
        for(int i=0; i<length; i++){
            //求每个数字的三进制字符串并翻转,然后转为字符数组
            elements[i] = new StringBuilder(Integer.toString(arr[i],k)).reverse().toString().toCharArray() ;
            if(elements[i].length > maxLength){//记录二维数组的最大长度
                maxLength = elements[i].length ;
            }
        }
        //做不进位加法
        int [] resArray = new int [maxLength] ;
        for(int i=0; i<length; i++){
            for(int j=0; j<maxLength; j++){
                if(j >= elements[i].length) {
                    resArray[j] += 0;
                }
                else{
                    resArray[j] += (elements[i][j] - '0') ;
                }
            }
        }
        int result = 0 ;
        for(int i=0; i<maxLength; i++){
            result += (resArray[i] % k) * (int)Math.pow(k,i) ;
        }
        System.out.println(result) ;
    }
}
思路2:HashMap键值对的方法,将数组元素存为键,数组元素出现的次数存为值,找到对应键的值等于1,则该键就是只出现1次的数字。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class HashMapDemo {
    public static int findKey(int [] arr){
        Map<Integer, Integer> map = new HashMap<>() ; //键和值都是Integer类型的HashMap对象
        for(int i=0; i<arr.length; i++){
            if(map.containsKey(arr[i])){ //键存在
               int value = map.get(arr[i]) ; //得到对应的值
               map.put(arr[i],value+1) ; //将对应的键值存入到HashMap
            }
            else{//键不存在
                map.put(arr[i],1) ; 
            }
        }
        Iterator <Integer> iterator = map.keySet().iterator() ;//迭代器对象
        while(iterator.hasNext()){//遍历迭代器对象
            int key = iterator.next() ;
            if(map.get(key) == 1){ //对应键的值等于1,则只出现1次
                return key ;
            }
        }
        return -1 ;
    }
    public static void main(String[] args){
        int [] arr = {1,1,1,2,2,2,4,4,4,3,5,5,5} ;
        if(findKey(arr) != -1){
            System.out.println(findKey(arr)) ;
        }
    }
}

以上是关于算法:位运算的主要内容,如果未能解决你的问题,请参考以下文章

算法进阶:0x01 位运算

0x01 基本算法-位运算 a^b

数据结构与算法-位运算

算法-位运算加法

位运算的操作与算法

数字位运算操作与算法简单示例