LeetCode中位运算相关题目

这阶段刷完了 LeetCode 上有关位运算的题目,感觉位运算还是挺难,很难get到点,有空还是要去加强学习,要掌握 与&、异或^、或|、非~,还有算术左移、算术右移、无符号右移 。还有 Java 中 Integer 类中常见位运算的方法(三个)。
需要注意以下几点:

1. 与&、异或^、或|、非~

x ^ 1s = ~x
x & 0s = 0      x & 1s = x 
x | 0s = x       x | 1s = 1s 
n&(n-1)     去除 n 的位级表示中最低的那一位
n&(-n) 得到 n 的位级表示中最低的那一位
n-n&(~n+1) 去除 n 的位级表示中最高的那一位。

2. 移位运算:

>> n 为算术右移,相当于除以 2n;
>>> n 为无符号右移,左边会补上 0。
<< n 为算术左移,相当于乘以 2n。

3. Java中位运算方法:**

static int Integer.bitCount();           // 统计 1 的数量
static int Integer.highestOneBit();      // 获得最高位
static String toBinaryString(int i);     // 转换为二进制表示的字符串
  1. 不用额外变量交换两个整数
    效率也比较快,感觉还是挺威的。
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;

以下是相关题目:

260. 只出现一次的数字 III
题目描述:

定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

示例 :

输入: [1,2,1,3,2,5]
输出: [3,5]

注意:
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

解题思路:

两个不相等的元素在位级表示上必定会有一位存在不同。将数组的所有元素异或得到的结果为不存在重复的两个元素异或的结果。

public int[] singleNumber(int[] nums) {
    int diff = 0;
    for (int num : nums) diff ^= num;
    diff &= -diff;  // 最后一位,利用这一位就可以将两个元素区分开来。
    int[] ret = new int[2];
    for (int num : nums) {
        if ((num & diff) == 0) ret[0] ^= num;
        else ret[1] ^= num;
    }
    return ret;
}
136.数组中唯一一个不重复的元素
题目描述:

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

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1
示例 2:

输入: [4,1,2,1,2]
输出: 4
解题思路:

算法应该具有线性时间复杂度,故应该使用位运算来解决问题,位运算还是比较快的。利用异或运算性质,两个相同的数异或的结果为 0

public int singleNumber(int[] nums) {
    int ret = 0;
    for (int n : nums) ret = ret ^ n;
    return ret;
}
268.找出数组中缺失的那个数
题目描述:

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

示例 1:

输入: [3,0,1]
输出: 2
示例 2:

输入: [9,6,4,2,3,5,7,0,1]
输出: 8

说明:
你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?

解题思路:

跟上题解法类似。

public int missingNumber(int[] nums) {
    int ret = 0;
    for (int i = 0; i < nums.length; i++) {
        ret = ret ^ i ^ nums[i];
    }
    return ret ^ nums.length;
}
231.判断一个数是不是 2 的 n 次方
题目描述:

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

示例 1:

输入: 1
输出: true
解释: 20 = 1
示例 2:

输入: 16
输出: true
解释: 24 = 16
示例 3:

输入: 218
输出: false
解题思路:
  1. 可以利用 1000 & 0111 == 0 这种性质求解
    class Solution {
     public boolean isPowerOfTwo(int n) {
         int res = n & (n - 1);
         return n > 0 && res == 0;
     }
    }
  2. 也利用Java API Integer.bitCount() 求解
    public boolean isPowerOfTwo(int n) {
     return n > 0 && Integer.bitCount(n) == 1;
    }
    
##### [461统计两个数的二进制表示有多少位不同](https://leetcode-cn.com/problems/hamming-distance/)
###### 题目描述:
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。

给出两个整数 x 和 y,计算它们之间的汉明距离。

注意:

0 ≤ x, y < 231.

示例:

输入: x = 1, y = 4

输出: 2

解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑

上面的箭头指出了对应二进制位不同的位置。


###### 解题思路:
1. 可以使用 z&(z-1) 去除 z 位级表示最低的那一位。
~~~ java
public int hammingDistance(int x, int y) {
    int z = x ^ y;
    int cnt = 0;
    while (z != 0) {
        z &= (z - 1);
        cnt++;
    }
    return cnt;
}
  1. 也可以按照常规思路 统计 1 的个数
    class Solution {
     public int hammingDistance(int x, int y) {
         int num = x ^ y;
         int count = 0;
         String numStr = Integer.toBinaryString(num);
         for (char c : numStr.toCharArray()) {
             if (c == '1') {
                 count++;
             }
         }
         return count;
     }
    }
371.实现整数的加法
题目描述:

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

示例 1:

输入: a = 1, b = 2
输出: 3
示例 2:

输入: a = -2, b = 3
输出: 1
解题思路:

a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进位。

class Solution {
    public int getSum(int a, int b) {

        while (b != 0) {
            int carry = a & b;
            a = a ^ b;
            b = carry << 1;

        }
        return a;
    }
}

   转载规则


《LeetCode中位运算相关题目》 ForeverSen 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Linux学习笔记(一) Linux学习笔记(一)
 我们得程序大多数都是运行在 Linux 上面得,因此平时或多或少接触了不少Linux 命令,最近在公司也用到了相关得命令,其中不外乎查看日志,排除错误,部署程序(目前没部署过公司程序)、编写脚本。因此有必要好好学习一波,这次主要学习命令
下一篇 
我所理解的 Dubbo 我所理解的 Dubbo
 在公司实习这段时间,虽然知道公司是使用 Dubbo 来调用服务的,但是没有深入理解Dubbo的原理,以及为什么要使用 Dubbo,因此重新深入学习了 Dubbo,总结下: 1. 官方文档Dubbo中文官方文档感觉无论学习什么,看官方文档
2019-06-20
  目录