https://home.cnblogs.com/group/topic/8550.html

算法笔记1-位运算

1.位运算

位运算符

  • 在处理整形数值时,可以直接对组成整形数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位(? ? )
  • &(与)、| (或)、^(异或)、~ (非/取反)
  • ">>"和"<<"运算符将二进制位进行右移或者左移操作
  • ">>>"运算符将用0填充高位; >>运算符用符号位填充高位,没有<<<运算符
  • 对于int型,1<<35与1<<3是相同 的,而左边的操作数是long型时需对右侧操作数模64
  • 与:都为1结果为1,或:有一个为1结果为1,异或:二者不同时结果为1
a b ~a a&b a|b a^b
1 1 0 1 1 0
0 1 1 0 1 1
0 0 1 0 0 0
  • 判断奇偶数 x&1=1为奇数 =0为偶数 原因:奇数最后一位是1,&1后为1,偶数最后一位为0,&1后为0

  • 获取二进制位是1还是0 (两种解决方案)
    86的二进制第5位是1还是0?

  1. 1先左移4位和86与运算,结果再右移,和为1则为,为0则为0
  2. 86右移4位,然后结果为和1与运算,结果1则为,为0则为0
    86>>4&1
  • 交换两个整数变量的值
int a=2,b=1;
a=a^b;
b=a^b;
a=a^b;
System.out.println("a=="+a+",b=="+b);
  • 不用判断语句,求整数的绝对值
int a=-88;
System.out.println((a^a>>31)+(a>>>31));
结果:88
  • 异或,可以理解为不进位加法:1 +1=0 , 0+0=0 , 1+0=1 .

    性质
    1、交换律可任意交换运算因子的位置,结果不变
    2、结合律(即(ab)c == a(bc) )
    3、对于任何数x ,都有x^x=0 , x^0=x,同自己求异或为0 ,同0求异或为自己
    1 1 0 1
    ^1 1 0 1
    ————
    0 0 0 0
    4、自反性ABB=A^0=A ,连续和同一一个因子做异或运算,最终结果为自己

题1:找出唯一成对的数

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

import java.util.Arrays;
import java.util.Random;

public class Main {
    public static void main(String[] args) {
        int N=11;
        int[] arr=new int[N];
        for (int i = 0; i <arr.length-1 ; i++) {
            arr[i]=i+1;
        }
        arr[N-1]=new Random().nextInt(N-1)+1;
        int index=new Random().nextInt(N);
        int t;
        t=arr[N-1];
        arr[N-1]=arr[index];
        arr[index]=t;
        System.out.println(Arrays.toString(arr));
        int x=0;
        for (int i = 0; i <N-1 ; i++) {
            x=x^(i+1);
        }
        for (int i = 0; i <N ; i++) {
            x^=arr[i];
        }
//		x^x=0,出现两次的消去,剩下出现三次的
        System.out.println(x);
//        辅助空间方法
        int[] h=new int[N];
        for (int i = 0; i <N ; i++) {
            h[arr[i]]++;
        }
        for (int i = 0; i < N; i++) {
            if(h[i]==2){
                System.out.println(i);
            }
        }
    }
}

题2:找出落单的那个数

一个数组里除了某一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。

题3:二进制中1的个数

请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。
例: 9的二进制表示为1001,有2位是1

import java.util.Scanner;

public class _1的个数 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int N=sc.nextInt();
        System.out.println(Integer.toString(N,2));

        int count=0;
        for (int i = 0; i < 32; i++) {
            if((N&1<<i)==1<<i){
                count++;
            }
        }
        System.out.println(count);
//      另一种解法
        count=0;
        while(N!=0){
            N=(N-1)&N;
            count++;
        }
        System.out.println(count);
    }
}

题4:是不是2的整数次方

用一条语句判断一个整数是不是2的整数次方。

if(((N-1)&N)==0){
    System.out.println("yes");
}else{
    System.out.println("no");
}

题5:将整数的二进制奇偶位互换

1&保留,0&置零,0^保留

public class _奇偶位交换 {
    public static void main(String[] args) {
        int a=6;
        System.out.println(m(a));
       	//结果为9
    }
    private static int m(int i){
        int ou=i&0xaaaaaaaa;//和1010 1010 ...做与运算得到偶位
        int ji=i&0x55555555;//和0101 0101 ...做与运算得到奇位
        return (ou>>1)^(ji<<1);
    }
}

题6:0~1间浮点实数的二进制表示

  • 给定一个介于0和1之间的实数, (如0.625) ,类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25.0.12.....)。
  • 如果该数字无法精确地用32位以内的-进制表示,则打印“ERROR”
public class _浮点数二进制表示 {
    public static void main(String[] args) {
        double m=0.625;
        StringBuilder re=new StringBuilder("0.");
        while(m>0){
            m=m*2;//乘2:挪整
            if(m>=1){//判断整数部分
                re.append("1");
                m=m-1;//消除整数部分
            }else{
                re.append("0");
            }
        }
        if(re.length()>34){
            System.out.println("ERROR");
            return;
        }
        System.out.println(re);
    }
}

题7:出现k次与出现1次

数组中只有-一个数出现了1次,其他的数都出现了k次,请输出只出现了1次的数。
2 个相同的2 进制数做不进位加法,结果为0
10个相同的10进制数做不进位加法,结果为0
k 个相同的k 进制数做不进位加法,结果为0


public class _07_出现K次 {
    public static void main(String[] args) {
        int[] arr = {2, 2, 2, 9, 7, 7, 7, 3, 3, 3, 6, 6, 6, 0, 0, 0};
        int len = arr.length;
        char[][] kRadix = new char[len][];
        int k = 3;

        int maxLen = 0;
        //转成k进制字符数组
        //对于每个数字
        for (int i = 0; i < len; i++) {
            //求每个数字的三进制字符串并翻转,然后转为字符数组
            kRadix[i] = new StringBuilder(Integer.toString(arr[i], k)).reverse().toString().toCharArray();
            if (kRadix[i].length > maxLen)
                maxLen = kRadix[i].length;
        }
        //不进位加法
        int[] resArr = new int[maxLen];
        for (int i = 0; i < len; i++) {
            //  不进位加法
            for (int j = 0; j < maxLen; j++) {
                if (j >= kRadix[i].length)
                    resArr[j] += 0;
                else
                    resArr[j] += (kRadix[i][j] - '0');
            }
        }
        int res = 0;
        for (int i = 0; i < maxLen; i++) {
            res += (resArr[i] % k) * (int) (Math.pow(k, i));// 8%3=2,
        }
        System.out.println(res);
    }
}

posted @ 2020-02-04 15:35  xcsxchen  阅读(275)  评论(0编辑  收藏  举报