LeetCode(191 & 461):位1的个数 Number of 1 Bits & 汉明距离 Hamming Distance(Java)

234 篇文章 1 订阅
177 篇文章 0 订阅

2019.9.14 #程序员笔试必备# LeetCode 从零单刷个人笔记整理(持续更新)

github:https://github.com/ChopinXBP/LeetCode-Babel

之前在剑指Offer里有刷过:#数据结构与算法学习笔记#剑指Offer10:位运算:求二进制中1的个数+四种解法比较+测试用例(Java、C/C++)

位1的个数问题要求求出数字n中二进制1的个数,比较四种解法:

1.转换为二进制字符串对字符‘1’的个数进行计算:比较投机取巧,但是比较通用,尤其在涉及大数运算的时候。

2.二进制从左向右移位并&1:初看简洁方便,但是在输入负数的时候会陷入死循环。

3.将1从右向左移位并和原数比较:正解,不会陷入死循环。

4.原数减1再和原整数相&,会把整数最右边的一个1变成0,计算原数变成0的运算次数:正解,思维比较出彩。

求两个数字的汉明距离,也就是统计两个数字异或之后二进制位1的个数。


比特位计数问题由位1的个数问题升级而来,要求求出0-n所有数的二进制1的个数,同样也有四种解法:

1.复用上述四种方法依次计数

2.动态规划+最高有效位

base = 1开始,将范围在[0, base)的数最高位补1,可以生成[base, 2*base)的所有数,不断循环直至num即可。状态转移方程:

dp[base + offset] = dp[offset] + 1, base = 2^k > offset;

3.动态规划+最低有效位

每一个数字i的二进制1的个数 = i右移一位的数字二进制1的个数 + 最低位是1的情况。动态转移方程:

dp[i] = dp[i>>1] + (i&1);

4.动态规划+最后设置位

参考上述方法4,i&(i-1)可以去掉最右边的1,因此可以有状态转移方程:

dp[i] = dp[i & (i - 1)] + 1;

传送门:位1的个数

Write a function that takes an unsigned integer and return the number of ‘1’ bits it has (also known as the Hamming weight).

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

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:

输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。


/**
 *
 * Write a function that takes an unsigned integer and return the number of '1' bits it has (also known as the Hamming weight).
 * 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
 *
 */

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


传送门:比特位计数

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1’s in their binary representation and return them as an array.

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

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

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

进阶:
给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
要求算法的空间复杂度为O(n)。
你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的__builtin_popcount)来执行此操作。


/**
 *
 *  Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.
 *  给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
 *
 */

public class CountingBits {
    //依次计数
    public int[] countBits(int num) {
        int[] result = new int[num + 1];
        for(int i = 0; i <= num; i++){
            result[i] = Solution(i);
        }
        return result;
    }

    public int Solution(int num){
        int result = 0;
        while(num != 0){
            num &= num - 1;
            result++;
        }
        return result;
    }

    //动态规划+最高有效位
    public int[] countBits2(int num) {
        int[] result = new int[num + 1];
        int offset = 0;
        int base = 1;
        //base = 1开始,将范围在[0, base)的数最高位补1,可以生成[base, 2*base)的所有数,不断循环直至num即可
        //状态转移方程dp[base + offset] = dp[offset] + 1, base = 2^k > offset
        while(base <= num){
            while(offset < base && base + offset <= num){
                result[base + offset] = result[offset] + 1;
                offset++;
            }
            offset = 0;
            base <<= 1;
        }
        return result;
    }

    //动态规划+最低有效位
    public int[] countBits3(int num) {
        int[] result = new int[num + 1];
        //每一个数字i的二进制1的个数 = i右移一位的数字二进制1的个数 + 最低位是1的情况
        //状态转移方程dp[i] = dp[i>>1] + i&1;
        for(int i = 1; i <= num; i++){
            result[i] = result[i >> 1] + (i & 1);
        }
        return result;
    }

    //动态规划+最后设置位
    public int[] countBits4(int num) {
        int[] result = new int[num + 1];
        //i&(i-1)可以去掉最右边的1,因此可以有状态转移方程dp[i] = dp[i & (i - 1)] + 1;
        for(int i = 1; i <= num; i++){
            result[i] = result[i & (i - 1)] + 1;
        }
        return result;
    }
}




传送门:汉明距离

The Hamming distance between two integers is the number of positions at which the corresponding bits are different.

Given two integers x and y, calculate the Hamming distance.

Note: 0 ≤ x, y < 2^31.

两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。

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

注意:0 ≤ x, y < 2^31.

示例:
输入: x = 1, y = 4
输出: 2
解释:
1   (0 0 0 1)
4   (0 1 0 0)
       ↑   ↑
上面的箭头指出了对应二进制位不同的位置。



/**
 *
 * The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
 * Given two integers x and y, calculate the Hamming distance.
 * 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
 * 给出两个整数 x 和 y,计算它们之间的汉明距离。
 *
 */

public class HammingDistance {
    //汉明距离表示两个相同长度数字对应位不同的数量
    public int hammingDistance(int x, int y) {
        return Integer.bitCount(x ^ y);
    }
}




#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值