今天在刷力扣的时候一不小心就刷入了位运算的专场,好家伙,那可真是血雨腥风啊,不过总的来说,位运算确实是解决问题的一种不错的方法,简洁,方便,快捷,还好理解,一开始确实是不好理解,但是只要你绕开了那个弯就很好理解了,思路都是比较清晰的,下面我来讲几道我遇到的位运算的题目。
- 第一道 位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
这道题目我用了两种办法解决,用位运算的知识去求解和暴力求解,
下面我们先来看一下暴力求解:
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
String s = Integer.toBinaryString(n);
int count=0;
for(int i=0;i<s.length();i++){
if(s.charAt(i) == '1'){
count++;
}
}
return count;
}
}
暴力求解很简单,就是把这一串二进制数变成一个字符串然后遍历这个字符串,如果有1的话我们的计数器就加一,最后返回count表示字符串中包含1的个数。
第二种方法是位运算来求解:
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count = 0;
int mask = 1;
for (int i = 0; i < 32; i++) {
if ((n & mask) != 0) {
count++;
}
mask <<= 1;
}
return count;
}
}
由题意得知我们输入的是一个32位的二进制数,所以我们循环32次,每一次都判断(n & mask),根据与运算的性质可以得出如果都是1的话结果就是1,如果有一个是0的话结果就是0,mask永远等于1,所以只有当n==1的时候if语句才会成立。所以两个方法都有异曲同工之处,都是判断某一项是不是1。
- 第二题 汉明距离
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。
输入: x = 1, y = 4
输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
上面的箭头指出了对应二进制位不同的位置。
这个题我用最原始的方法来进行求解,因为根据题意的值是让我们求两个整数的二进制数,所以我们可以根据求一个整数的二进制数的方法来求解。
class Solution {
public int hammingDistance(int x, int y) {
//return Integer.bitCount(x ^ y);
//最原始最直观的办法
int count = 0;
while(x!=0 || y!=0){
if(x%2 != y%2){
count++;
}
x=x/2;
y=y/2;
}
return count;
}
}
判断两个二进制数的某位是否相等,所以我们先除2,然后取余,然后判断两个数是否相等。结束条件就是两个整数最后都为0。
- 第三题 颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
本题与"整数反转"一题很像,无非就是一个是十进制,一个是二进制罢了。
整数反转题目链接:https://leetcode-cn.com/problems/reverse-integer/
整数反转核心代码:y = y * 10 + x % 10; x = x / 10;
然后我们由此可以得到启发用位运算,运算32位,然后有一个ans负责相加和得到最终的结果,还有负责左移右移达到减少或增加效果的位运算。
代码实现:
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
//return Integer.reverse(n);
int ans = 0;
for(int i=0;i<32;i++){
//n&1 与运算 可以判断n是否为偶数 如果是偶数,n&1返回0;否则返回1,为奇数。
ans <<= 1;//二进制数先左移一位,即取到末尾
ans+=(1 & n);//然后把末尾的值给ans
n>>=1;//n随即右移减去末尾
}
return ans;
}
}
此题的关键在于取出n的最后一位,如何取到呢?用位运算(1 & n)可以根据末尾是偶数还是奇数来得到0或1,我们得到之后让向左开拓一位后的ans加上这个末尾的值,然后n的末尾的值被取了出来,再取倒数第二位的值,所以我们用n>>=1
来去掉最后一位,让本来的倒数第二位变成倒数第一位,依次循环32次,最终得到的ans就是反过来的二进制数。
- 第四题 杨辉三角
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
输入: 5
输出:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
关于杨辉三角形呢并不是位运算的问题,但是我觉得这个题目很有意思,也很常见,所以就把他拿出来了,放在这里简单的讲一下实现过程。
首先由图我们可以得知这是一个需要一个嵌套循环的一个典型例子,每一行即内层循环首尾都是1,并且从第二位开始,就是上一行(i-1)行的j-1个和j个相加的和,以此类推我们可以得到最终结果。
核心代码:res.add(ret.get(i-1).get(j-1)+ret.get(i-1).get(j));
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
for(int i=0;i<numRows;i++){
List<Integer> res = new ArrayList<>();
for(int j=0;j<=i;j++){
if(j==0 || j==i){
res.add(1);
}else{
res.add(ret.get(i-1).get(j-1)+ret.get(i-1).get(j));
}
}
ret.add(res);
}
return ret;
}
}
好了,今天的分享就先到这里了,希望同学们快乐刷题,快乐AC每一道题。然后也希望接下来我的算法比赛会有好的成绩,加油!
就酱~