【Leecode笔记】第十八周下(1.5-1.8)位运算专题

【第一题】丢失的数字

在这里插入图片描述

分析:
1.位运算异或。
2.求和。由1到n项的数列和-目前的sum
3.哈希表/桶

//1.位运算异或。
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:38.9 MB, 在所有 Java 提交中击败了63.68% 的用户
class Solution{
    public int missingNumber(int[] nums){
        int res = nums.length;
        for(int i = 0;i < nums.length;i++){
            res ^= nums[i] ^i;
        }
        return res;
    }
}
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:39.1 MB, 在所有 Java 提交中击败了36.75% 的用户
class Solution {
    public int missingNumber(int[] nums) {
        int sum = 0;
        for(int i = 0;i < nums.length;i++){
            sum += nums[i];
        }
        return nums.length *(nums.length + 1)/2-sum;
    }
}

【第二题】数字转换为十六进制数

在这里插入图片描述

分析:

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.7 MB, 在所有 Java 提交中击败了52.89% 的用户
class Solution {
    public String toHex(int num) {
        if(num == 0){return "0";}
        char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        StringBuilder sb = new StringBuilder();
        while(sb.length() < 8 && num!=0){
            sb.append(chars[num & 0xf]);
            num >>=4;
        }
        return sb.reverse().toString();
    }
}

【第三题】2的幂

在这里插入图片描述

分析:
方法一:n&n-1 == 0?
方法二:n & -n == n?

//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了80.26% 的用户
class Solution {
    public boolean isPowerOfTwo(int n) {
        if(n <=0) return false;
        if((n & n-1) == 0){
            return true;
        }
        return false;
    }
}
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了89.05% 的用户
class Solution {
    public boolean isPowerOfTwo(int n) {
		return (n > 0) && (n & -n);
	}
}

【第四题】插入

在这里插入图片描述

分析:首先构造二进制位,根据需要插入的起始位和终止位,(也就是说,把起始位到终止位的部分都设置成0,其他的都是1),然后N=N&n,目的是使N的i-j位全部为0,便于下一步的插入。然后把M左移i位,这样末尾就是第i-j位,最后把M和N进行或运算,得出结果。
在这里插入图片描述

class Solution{
	public static insertBits(int N,int N,int i,int j){
		int n = ~((-1 >>>(31-j))&(-1<<i));
		N = N&n;
		M = M<<i;
		N=M|N;
		return N;
	}
}

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了43.37% 的用户
class Solution {
    public int insertBits(int N, int M, int i, int j) {
        int mask = ~(((1 << (j-i+1))-1) << i);
        N&=mask;
        M = M<<i;
        return M|N;
    }
}

【第四题】两整数之和

在这里插入图片描述

分析:两个整数a,b。假如没有进位,那么a^b就是两者之和;假如有进位,让无进位相加的结果与进位不断地异或,直到进位为0.

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了24.37% 的用户
class Solution {
    public int getSum(int a, int b) {
        int sum,carry;
        sum = a^b;
        carry = (a & b) <<1;
        if(carry !=0){
           return getSum(sum,carry); 
        }
        return sum;
    }
}

【第五题】位1的个数

分析:
方法一:移位操作,假如末尾是1,count++,然后算术右移(不考虑符号位)。
方法二:

//执行用时:1 ms, 在所有 Java 提交中击败了95.41% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了68.12% 的用户
public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int cnt = 0;
        while(n !=0){
            n &= (n-1);
            cnt++;
        }
        return cnt;
    }
}

【第六题】二进制手表(挖坑等回溯算法)

https://leetcode-cn.com/problems/binary-watch/
在这里插入图片描述

分析:二进制手表第一排的四个灯表示(0-11),第二排的6个灯表示分钟(0-59),都是根据二进制位,亮灯为1,不亮为0.
给定亮灯数目,返回所有可能的时间。其实就是判断1的个数

要注意的是小时和分钟的格式,小时(是几位就是几位),分钟(一律两位数,不足两位高位补零)。

【第七题】多数元素

在这里插入图片描述

分析:这个题可以分成两道题做。

方法一:排序+双指针;
方法二:直接排序求中位数;
方法三:位运算(假如该数为众数,那么出现该数的次数一定大于n/2,同理它的二进制位上每个1的个数也大于n/2,只要统计每一位1出现的次数大于n/2的相加得出结果即可。假如出现最多次数的是0,那么没有一个数出现的1大于n/2,直接返回0即可);
方法四:哈希表(杀鸡用牛刀的意思)
方法五:投票法(假如只有两种元素,那么可以直接用flag消除法。多种元素和消除法一样的思路,投票法,最后剩下的那个数一定是众数)

//执行用时:3 ms, 在所有 Java 提交中击败了43.19% 的用户
//内存消耗:41.7 MB, 在所有 Java 提交中击败了66.36% 的用户
class Solution {
    public int majorityElement(int[] nums) {
        if(nums.length == 1 || nums.length == 2){return nums[0];}
        // if(nums.length == 2){
        //     // if(nums[0] == nums[1]){
        //     //     return nums[0];
        //     // }else{
        //     //     return 0;
        //     // }
        //     return nums[0];
        // }
        Arrays.sort(nums);
        
        int count = 1;
        int i = 0,j = 1;
        while(j < nums.length){
            if(nums[j] == nums[i]){
                count++;
                j++;
            }else{
                if(count > nums.length/2){
                    return nums[i];
                }else{
                    i = j;
                    j++;
                }
            }
        }
        return count > nums.length/2? nums[i]:0;
    }
}
//执行用时:2 ms, 在所有 Java 提交中击败了74.14% 的用户
//内存消耗:41.6 MB, 在所有 Java 提交中击败了80.18% 的用户
class Solution {
    public int majorityElement(int[] nums) {
        if(nums.length == 1 || nums.length == 2){return nums[0];}
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
}
class Solution{
	public int majorityElement(int[] nums) {
        int result = 0, k = nums.length >> 1;
        for (int j = 0; j < 32; j++) {
            int count = 0;
            for (int num : nums) {
                count += num >> j & 1;
                if (count > k) {
                    result += 1 << j;
                    break;
                }
            }
        }
        return result;
    }
}
//执行用时:3 ms, 在所有 Java 提交中击败了43.19% 的用户
//内存消耗:44.4 MB, 在所有 Java 提交中击败了5.03% 的用户
class Solution{
	public int majorityElement(int[] nums){
		int count = 0;
		Integer candidate = null;
		for(int num:nums){
			if(count == 0){candidate = num;}
			count+=(num == candidate)?1:-1;
		}
		return candidate;
	}
}

【第八题】二进制表示中质数个计算置位

在这里插入图片描述分析:简简单单统计个数,简简单单判断质数。不是吧,看完官方题解表示还能这么搞?

//执行用时:41 ms, 在所有 Java 提交中击败了18.66% 的用户
//内存消耗:35.2 MB, 在所有 Java 提交中击败了77.65% 的用户
class Solution {
    public int countPrimeSetBits(int L, int R) {
        int cnt = 0;
        for(int i = L;i <= R;i++){
            if(isPrime(countOne(i))){
                cnt++;
            }
        }
        return cnt;
    }
    
    public int countOne(int n){
        int count = 0;
        while(n!=0){
            if((n & 1) == 1){
                count++;
            }
            n = n>>>1;
        }
        return count;
    }

    public boolean isPrime(int n){
        if(n == 1){return false;}
        
        for(int i = 2;i <= Math.sqrt(n);i++){
            if(n % i == 0){
                return false;
            }
        }
        return true;
    }
}
class Solution {
    public int countPrimeSetBits(int L, int R) {
        int ans = 0;
        for (int x = L; x <= R; ++x)
            if (isSmallPrime(Integer.bitCount(x)))
                ans++;
        return ans;
    }
    public boolean isSmallPrime(int x) {
        return (x == 2 || x == 3 || x == 5 || x == 7 ||
                x == 11 || x == 13 || x == 17 || x == 19);
    }
}

【第九题】配对交换

在这里插入图片描述

分析:

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了46.26% 的用户
class Solution {
    public int exchangeBits(int num) {
        int ans = 0;
        for (int i = 0; i < 30; i += 2) {
        	//取每个奇数位
            int a = num & (1 << i);
            //取每个偶数位
            int b = num & (1 << (i + 1));
            //将偶数位设置为a,将奇数位设置为b
            ans |= (a << 1);
            ans |= (b >> 1);
        }
        return ans;
    }
}
//这个题解太妙了
/*思路的话就是分别取出奇数位和偶数位,移动后做或运算。
题目规定 num 是int范围的数
0x55555555 = 0b0101_0101_0101_0101_0101_0101_0101_0101
0xaaaaaaaa = 0b1010_1010_1010_1010_1010_1010_1010_1010
用这两个数做与运算,就可以把奇数位和偶数位取出来,
然后位左移奇数位,右移偶数位,再把奇数位和偶数位做或运算

作者:releng-xing
链接:https://leetcode-cn.com/problems/exchange-lcci/solution/wei-yun-suan-jie-jue-by-releng-xing/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
class Solution {
    public int exchangeBits(int num) {
        //奇数
        int odd = num & 0x55555555;
        //偶数
        int even = num & 0xaaaaaaaa;
        odd = odd << 1;
        even = even >>> 1;
        return odd | even;
    }
}


【第十题】颠倒二进制位

在这里插入图片描述

分析:初始化变量res存放num的位,每次获取num的最后一位,和res相或,然后将num右移,将res左移,循环32次,最后的结果就是res

//执行用时:1 ms, 在所有 Java 提交中击败了99.97% 的用户
//内存消耗:38.3 MB, 在所有 Java 提交中击败了38.97% 的用户
class Solution{
	public int reverseBits(int n){
		int res = 0;
		for(int i = 0;i < 32;++i){
			res = res << 1;
			res = n&1 | res;
			n = n >> 1;
		}
		return res;
	}
}

【第十一题】消失的数字

在这里插入图片描述

分析:重拳出击后发现,击败17%。
方法一:排序+数组元素与下标对比
方法二:异或(数字、下标一起异或,假如数字存在,那么必定有和它相同的下标,根据异或的交换律,就有异或结果为0,异或结果就是消失的那个数)
方法三:等差数列求和公式-sum

//执行用时:6 ms, 在所有 Java 提交中击败了17.77% 的用户
//内存消耗:39 MB, 在所有 Java 提交中击败了45.90% 的用户
class Solution {
    public int missingNumber(int[] nums) {
        Arrays.sort(nums);
        for(int i = 0;i < nums.length;i++){
            if(i!=nums[i]){
                return i;
            }
        }
        return nums.length;
    }
}
//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:38.8 MB, 在所有 Java 提交中击败了74.32% 的用户
class Solution{
    public int missingNumber(int[]nums){
        int result=nums.length;
        for(int i=0;i<nums.length;i++){
            result^=i^nums[i];
        }
        return result;
    }
}

【第十二题】交替位二进制数

在这里插入图片描述

分析:
方法一:移位,直接取末尾数比较。
方法二:String str = Integer.toBinaryString(n);对字符串进行操作

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.2 MB, 在所有 Java 提交中击败了64.31% 的用户
class Solution {
    public boolean hasAlternatingBits(int n) {
        while(n!=0){
            int num1 = n&1;
            n >>=1;
            int num2 = n&1;
            if(num1 == num2){
                return false;
            }
        }
        return true;
    }
}

【第十三题】4的幂

在这里插入图片描述

分析:除了0以外,假如末尾有偶数个0,且首位为1,就是4的幂。也就是说,只有1个1,且出现在奇数位。

//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了85.12% 的用户
class Solution{
    public boolean isPowerOfFour(int num){
        //检查是不是2的幂
        return (num > 0) && ((num & (num-1)) == 0 && (num % 3 == 1));
    }
}
//执行用时:1 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了81.43% 的用户
class Solution {
    public boolean isPowerOfFour(int n) {
        if(n < 0){return false;}
        if(n == 1){return true;}
        int temp = n;
        int Total = 0;//统计位数
        int countZero = 0;//统计0的个数
        while(n !=0){
            if((n&1) == 0){
                countZero++;
            }
            Total++;
            n >>=1;
        }
        temp = temp >> (Total-1);//保存首位
        if(temp == 1 && countZero+1==Total && countZero%2==0){
            return true;
        }
        return false;
    }
}

【第十四题】汉明距离

在这里插入图片描述

分析:重拳出击!

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35 MB, 在所有 Java 提交中击败了85.31% 的用户
class Solution {
    public int hammingDistance(int x, int y) {
        int count = 0;
        while(x !=0 || y !=0){
            if((x&1)!=(y&1)){
                count++;
            }
            x >>= 1;
            y >>= 1;
        }
        while(x!=0){
            x >>=1;
            count++;
        }
        while(y!=0){
            y >>=1;
            count++;
        }
        return count;
    }
}

【第十六题】翻转数位

在这里插入图片描述

分析:题意——将一个数位从0变为1,找出最长的1的长度。
注意负数!注意二进制32位全为1的数!注意注意二进制位是全1,但是不是32个1的数!

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35 MB, 在所有 Java 提交中击败了93.35% 的用户
class Solution {
    public int reverseBits(int num) {
        if(num == 0){return 1;}
        int maxLen = 0,curLen = 0;
        //只允许一次翻转
        boolean flag = true;
        int num1 = 0;
        //记录二进制位总数
        int count1 = 0;
        //记录1的个数
        int count2 = 0;
        while(num !=0){
            if((num & 1) == 1){
                curLen++;
                if(flag == false){
                    num1++;
                }
                count2++;
            }else{
                //第一次翻转
                if(flag == true){
                    curLen++;
                    flag = false;
                    
                }else{
                    //之后遇到0则num1重新计数
                    maxLen = Math.max(maxLen,curLen);
                    curLen = num1+1;
                    num1 = 0;
                }
            }
            //System.out.println(num&1);
            num >>>=1;
            count1++;
        }
        if(count1 == count2 && count1 < 32){
            curLen++;
        }
        maxLen = Math.max(maxLen,curLen);
        return maxLen;
    }
}

【第十七题】最大数值

在这里插入图片描述

分析:相减看是负数还是正数(看最高位是否为1)

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.3 MB, 在所有 Java 提交中击败了52.85% 的用户
class Solution {
    public int maximum(int a, int b) {
        long val = (long)a - (long)b;
        int[] r = new int[]{a,b};
        return r[(int)(val >>> 63)];
    }
}

【第十八题】数字的补数

在这里插入图片描述

分析:假如输入的数为num,num取反:num ^ (num.length个1)。

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了28.37% 的用户
class Solution {
    public int findComplement(int num) {
        int temp = num;
        int flag = 0;
        while(temp!=0){
            flag++;
            //相当于右移操作
            temp /=2;
        }
        return num^(int)(Math.pow(2,flag) - 1);
    }
}

【第十九题】整数转换

在这里插入图片描述

分析:其实就是输出两者的二进制位有几个不同——汉明距离。
两者异或之后,看1的个数。每执行一次x = x&(x-1),会将x用二进制表示时最右边的一个1变为0,将所有的1都变为0,这时就统计出了二进制位中1的个数。

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.2 MB, 在所有 Java 提交中击败了55.59% 的用户
class Solution {
    public int convertInteger(int A, int B) {
        int x = A ^ B;
        int cnt = 0;
        while(x !=0){
            x &= (x-1);
            cnt++;
        }
        return cnt;
    }
}

【第二十题】不用加号的减法

在这里插入图片描述

分析:手动实现进位。
在这里插入图片描述

//执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
//内存消耗:35.4 MB, 在所有 Java 提交中击败了31.25% 的用户
class Solution{
	public int add(int a,int b){
		while(b !=0){
			int sum = (a ^ b);
			int carry = (a & b) << 1;
			//迭代处理
			a = sum;
			b = carry;
		}
		return a;
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值