位运算:你必须掌握的几个小技巧

位运算

    • LeetCode371:两整数之和
    • 解题思路
    • 代码实现
    • LeetCode268:缺失数字
    • 解题思路
    • 代码实现
    • LeetCode136:只出现一次的数字
    • 解题思路
    • 代码实现
    • LeetCode137:只出现一次的数字-Ⅱ
    • 解题思路
    • 代码实现
    • 剑指offer56-Ⅰ:数组中数字出现的次数
    • 解题思路
    • 代码实现
    • LeetCode191:1的位数
    • 解题思路
    • 代码实现
    • LeetCode231:2的幂
    • 解题思路
    • 代码实现
    • 剑指offer64:求1+2+....+n
    • 解题思路
    • 代码实现
    • 总结

不要纠结,干就完事了,熟练度很重要!!!多练习,多总结!!!

LeetCode371:两整数之和

不使用运算符 + 和 - ,计算两整数 a 、b 之和。

解题思路

位运算求解,你必须要知道的两个位运算技巧:
异或”是一个无进位加法,说白了就是把进位砍掉。比如01^01=00。

”可以用来获取进位,比如01&01=01,然后再把结果左移一位,就可以获取进位结果。
上述两个步骤即可实现相加,知道进位为0时,结束!!!

代码实现

class Solution {
     
    public int getSum(int a, int b) {
     
        while (b!=0){
     
            int temp=a^b;
            b=(a&b)<<1;
            a=temp;
        }
        return a;
    }
}

LeetCode268:缺失数字

给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。

解题思路

位运算遵循一个原则:两个相同的数,使用异或可以相消除,显而易见,在本题中只需将所有元素依次与0~n进行异或运算即可求出缺失的那个值!!!

代码实现

class Solution {
     
    public int missingNumber(int[] nums) {
     
        int res=0;
        for (int i=0;i<nums.length;i++){
     
            res^=(nums[i]^i);
        }
        return res^nums.length;
    }
}

LeetCode136:只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

解题思路

由题意只除了一个只出现一次的数字外,其余数字均出现了两次,那还是可以采用异或运算,即两个相同的数字异或为0.很简单,上代码!!!

代码实现

class Solution {
     
    public int singleNumber(int[] nums) {
     
        int res=0;
        for(int num:nums){
     
            res^=num;
        }
        return res;
    }
}

LeetCode137:只出现一次的数字-Ⅱ

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。说明:你的算法应该具有线性时间复杂度。你可以不使用额外空间来实现吗?

解题思路

本题对上述做了一些改进,变成了其余元素出现三次!但是位运算中并没有直接的使得三个相同的数字运算为0的方法,所以我们需要自己进行构造!!!怎么构造?异或就是同一个位上,有两个1清零的过程,那么我们需要构造同一个位上,三个1清零的过程,其实就是让其二进制的每一位相加,再对3进行取模!!!(ps:如果再出个相同数字出现4次的哪?方法同理!)

代码实现

class Solution {
     
    public int singleNumber(int[] nums) {
     
        int number=0,res=0;
        for (int i=0;i<64;i++){
     
            number=0;
            for(int num:nums){
     
                number+=(num>>i)&1;
            }
            res|=(number%3)<<i;
        }
        return res;
    }
}

剑指offer56-Ⅰ:数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例 1:

输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

解题思路

从上面题目我们现在知道如果只要一个只出现一次的数字,那么将数组的元素全部异或就行了。现在是出现有两个只出现一次的数字,那么怎么办呢?
我们如果最后可以实现一个数组划分,即将只出现一个的两个数字划分到两个不同数组,其余重复元素也要相同的元素都在一个数组
如果我们可以把所有数字分成两组,使得:
1.两个只出现一次的数字在不同的组中;
2.相同的数字会被分到相同的组中。

那么对两个组分别进行异或操作,即可得到答案的两个数字。依据什么来划分这两个数组是关键点。
按照例子[4,1,4,6]来举例,关键点在分组上: 4 ->100 ;1 ->001; 6 ->110; 4 ->100 ; 所有数字异或值为 k(这里是111),只要找到一个k中,位数为1的任意位来作为mask(mask就是区分两个数组的工具,原因很简单,mask就是寻找两个只出现一次数字中其二进制对应中哪一位是不同的,通过这个可以将两个不同数字分离)( 这里用的是 while((k & mask) == 0) { mask <<= 1; } ),显然第一位就是mask,mask这个位号表示的是那两个不重复数的二进制(001、110)在这个位号上不同时为0或1的位置,那么锁定这样的位置后,以同样方法(使用(num & mask) == 0),将mask位不为1的剔出来为一组,而另一组中必然会有mask位为1的数,这样就实现了不重复的两个数分到了不同组,而那些重复数必然被分到相同的组中,最终被抵消。

代码实现

class Solution {
     
    public int[] singleNumbers(int[] nums) {
     
        int k=0;
        for (int num:nums){
     
            k^=num;
        }
        int mask=1;
        while ((k&mask)==0){
     
            mask<<=1;
        }
        int a=0,b=0;
        for (int num:nums){
     
            if ((num&mask)==0){
     
                a^=num;
            }else {
     
                b^=num;
            }
        }
        return new int[]{
     a,b};
    }
}

LeetCode191:1的位数

编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。

解题思路

你当然可以通过移位,逐次计算每一位是否为1进行统计,但这还不是最优!你可以对于任意一个数,将 n 和 n-1 进行 & 运算,我们都可以把 n 中最低位的 1 变成 0。逐次运算知道全0!!!

代码实现

public class Solution {
     
    public int hammingWeight(int n) {
     
        int count=0;
        while (n!=0){
     
            n=n&(n-1);
            count++;
        }
        return count;
    }
}

LeetCode231:2的幂

给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

解题思路

对于符合2的幂次的数,对其进行二进制可以看出满足最高位为1,其余为0的情况。那么n-1就是最高位为0其余全1的数字,我们只需进行n&(n-1)运算看其是否是全0即可判断是否是2的幂次!!!

代码实现

class Solution {
     
    public boolean isPowerOfTwo(int n) {
     
        return (n>0)&&(n&(n-1))==0;
    }
}

剑指offer64:求1+2+…+n

求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

解题思路

这是一个很经典的老题了,用的是递归求解,但又不能使用条件语句,所以给命名了一个boolean变量!可以当作条件语句使用,作为递归的停止条件!很巧妙

代码实现

class Solution {
     
    public int sumNums(int n) {
     
        boolean b=n>0&&((n+=sumNums(n-1))>0);
        return n;
    }
}

总结

本题来源于Leetcode中 归属于位运算类型题目。
同许多在算法道路上不断前行的人一样,不断练习,修炼自己!
如有博客中存在的疑问或者建议,可以在下方留言一起交流,感谢各位!

觉得本博客有用的客官,可以给个赞鼓励下! 嘿嘿

你可能感兴趣的:(大厂手撕代码必知必会,leetcode,算法)