位运算专题

异或:相同为0,相异为1,无进位相加

位运算专题_第1张图片

约定:给定的所有数从左到右依次是从低位到高位,下标从0开始

一)给定一个数,判断它的二进制位表示中的第X位是0还是1

1)(N>>X)&1,先将x位右移动到最低位,然后再将这个数和1进行按位与操作,如果这个最低位是1,那么经过与1进行按位与结果就是1,如果这个X位是0,那么经过和1进行按位与结果就是0

二)为运算的优先级:能加括号就加括号,先运算的加上括号

三)将一个数N的二进制表示的第X位修改成1,其余位保持不变

位运算专题_第2张图片四)将一个数N的二进制表示的第X位修改成0,其余位保持不变(必须让最终的数位的决定权在于原始的这个数)

位运算专题_第3张图片

五)提取一个数中二进制表示中最右侧的1:lowbit

N&(-N)

将N变成-N的操作是将N进行按位取反,然后再加1,

本质上就是将最右侧的1,(不包含这个1)左边的区域全部取反,最终结果就是N&(-N)

位运算专题_第4张图片

六)干掉一个数二进制中表示的最右侧的1(最低位的1变成0)

N-1本质上就是让最右侧的1(包含最右侧的1)右边的数全部按位取反,左侧保持不变

(因为从最低位0到最右侧的1区间之间减1减不动所以要进行借位)

N&(N-1)

一)只出现一次的数字

260. 只出现一次的数字 III - 力扣(Leetcode)

第一步:将数组中所有的元素进行异或操作,最终得到一个异或值,因为是不同的两个数字,所以说这个数字肯定不是0

第二步:取异或值最后一个二进制位是1的数,如果这个数是1,那么代表着这两个数字在这一位上不同,要么一个数字在这一位上是1,要么是一位数字在这一位上面是0

第三步:根据这一位上面的值进行分组,将这两个不同的数字分别分到两个不同的组上面,每一个组分别进行异或,最终两个组得到的值就是最终的结果

通过与这个 mask 进行与操作,如果为 0 的分为一个数组,为 1 的分为另一个数组。这样就把问题降低成了:“有一个数组每个数字都出现两次,有一个数字只出现了一次,求出该数字”,对这两个子问题分别进行全异或就可以得到两个解,也就是最终的数组了

class Solution {
    public int[] singleNumber(int[] nums) {
        int temp=0;
        for(int i=0;i

二)位1的个数:

191. 位1的个数 - 力扣(Leetcode)

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count=0;
     for(int i=0;i<=31;i++){
         if(((n>>i)&1)==1) count++;
      }
      return count;
    }
}
public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count=0;
        while(n!=0){
            n=n&(n-1);
            count++;
        }
        return count;
    }
}

无符号右移:不论正负,高位均补0

右移:若正数,高位补0,负数,高位补1,一句话概括:高位补符号位

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count=0;
        while(n!=0){
            if((n&1)==1) count++;
            n=n>>>1;//左边只能补0
        }
    return count;
    }
}

三)比特位计数:

338. 比特位计数 - 力扣(Leetcode)

1)按位与操作: 

class Solution {
    public int[] countBits(int n) {
        int[] array=new int[n+1];
       for(int i=0;i<=n;i++){
           int count=0;
           int temp=i;
           while(temp!=0){
               temp=temp&(temp-1);
               count++;
           }
           array[i]=count;
       }
       return array;
    }
}

       

2)动态规划:

2.1)首先定义一个状态表示:dp[i]表示i位置的数二进制1的个数

2.2)根据状态表示推到状态转移方程:

0->0000

1->0001

2->0010

3->0011

4->0100

5->0101

6->0110

dp[i]=dp[i>>1]+i&1

class Solution {
    public int[] countBits(int n) {
        int[] dp=new int[n+1];
        dp[0]=0;
        dp[1]=1;
//从左向右进行填表
        for(int i=1;i<=n;i++){
            dp[i]=dp[i>>1]+(i&1);
        }
    return dp;
    }
}

四)汉明距离:

461. 汉明距离 - 力扣(Leetcode)

思路:把两个数转化成二进制,看看两个数的二进制中有多少比特位不相同,根据异或运算的特性,相同为0,不同为1所以只需要统计两个二进制数异或的结果中有多少比特位是1即可

class Solution {
    public int hammingDistance(int x, int y) {
        int temp=x^y;
        int count=0;
        while(temp!=0){
            temp=temp&(temp-1);
            count++;
        }
    return count;
    }
}

五)判断字符是否唯一

面试题 01.01. 判定字符是否唯一 - 力扣(Leetcode)

解法1:哈希表

遍历这个字符串中的所有字符,如果这个字符在哈希表中没有出现过,那么直接存放到哈希表里面,如果这个字符已经在哈希表中出现过了,那么直接返回false

这里面的时间复杂度是O(N),空间复杂度还是O(N)

解法2:不需要创建一个真正的哈希表,使用字符数组进行代替即可hash[26]

位运算专题_第5张图片

class Solution {
    public boolean isUnique(String str) {
        char[] array=str.toCharArray();
        int[] countArray=new int[32];
        for(int i=0;i0) return false;
            countArray[array[i]-'a']++;
        }
    return true;
    }
}

 

你可能感兴趣的:(算法,数据结构)