🧮 Algorithm Notebook
1、算法准备
1.1 牛客网编程OJ的典型输入输出
2、算法框架
2.1 动态规划
2.1.1 斐波那契数列
2.1.2 背包问题
2.1.3 贪心算法
2.1.4 序列和数组类问题
2.1.5 编辑距离
2.1.6 高楼扔鸡蛋
2.1.7 股票问题系列通解
2.1.8 最长有效括号
2.1.9 剪绳子
2.1.10 正则表达式匹配
2.2 二分查找
2.2.1 二分查找框架
2.2.2 搜索旋转排序数组
2.3 链表
2.3.1 反转链表
2.3.2 相交链表
2.3.3 合并链表
2.3.4 链表中倒数第k个节点
2.3.5 复制带随机指针的链表
2.4 排序算法
2.4.1 常见排序算法
2.5 二叉树
2.5.1 二叉树遍历
2.5.2 岛屿问题
2.5.3 二叉树路径问题
2.5.4 构造二叉树
2.6 回溯算法
2.6.1 回溯算法解题框架
2.6.2 N皇后
2.7 数组
2.7.1 删除有序数组中的重复项
2.7.2 滑动窗口最大值
2.7.3 调整数组顺序使奇数位于偶数前面
2.7.4 螺旋矩阵
2.7.5 多数元素
2.7.6 最大数
2.7.7 和为s的两个数字
2.7.8 构建乘积数组
2.7.9 两数之和
2.8 字符串
2.8.1 最小覆盖子串
2.8.2 比较版本号
2.8.3 验证IP地址
2.8.4 基本计算器 II
2.8.5 字符串解码
2.8.6 移掉 K 位数字
2.8.7 无重复字符的最长子串
2.8.8 第一个只出现一次的字符
2.8.9 翻转字符串里的单词
2.8.10 字符串转换整数 (atoi)
2.8.11 字符串四则运算
2.9 栈
2.9.1 最小栈
2.9.2 弹出序列
2.10 数学
2.10.1 用 Rand7() 实现 Rand10()
2.10.2 只出现一次的数字
2.10.3 整数反转
2.10.4 求1+2+…+n
2.10.5 二进制中1的个数
2.10.6 幂运算
2.10.7 1~n 整数中 1 出现的次数
2.10.8 数字序列中某一位的数字
2.10.9 丑数
2.10.10 n个骰子的点数
2.10.11 圆圈中最后剩下的数字
2.10.12 不用加减乘除做加法
2.10.13 x 的平方根
2.11 设计
2.11.1 LRU 缓存机制
-
+
tourist
register
Sign in
二进制中1的个数
# 1 题目 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为 汉明重量).)。 **提示:** * 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 * 在 Java 中,编译器使用 二进制补码 记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 **示例 1:** ```txt 输入:n = 11 (控制台输入 00000000000000000000000000001011) 输出:3 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 ``` **示例 2:** ```txt 输入:n = 128 (控制台输入 00000000000000000000000010000000) 输出:1 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 ``` **示例 3:** ```txt 输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n = -3) 输出:31 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 ``` **提示:** * 输入必须是长度为 32 的 二进制串 。 # 2 解题思路 > 对于数学相关的题目,要学会使用**位运算**来解决。 ## 2.1 逐位判断 ### 2.1.1 问题分析 1. **根据与运算定义**,**设二进制数字 $n$**,则有: 1. **若 $n \& 1 = 0$**,**则 $n$ 二进制最右一位为 0**。 2. **若 $n \& 1 = 1$**,**则 $n$ 二进制最右一位为 1**。 2. **根据以上特点**,**考虑以下循环判断**: 1. **判断 $n$ 最右一位是否为 1**,**根据结果计数**。 2. **将 $n$ 右移一位**(本题要求把数字 $n$ 看作无符号数,因此使用**无符号右移**操作)。 ### 2.1.2 参考代码 ```java /** * 剑指 Offer 15. 二进制中 1 的个数(版本 1:逐位判断) * @param n * @return */ public int hammingWeightV1(int n) { int res = 0; while (n != 0) { res += n & 1; n >>>= 1; } return res; } ``` ## 2.2 巧用 $n \& (n - 1)$ ### 2.2.1 问题分析 1. 如果一个整数不等于 0,那么该整数的二进制表示中至少有一位是 1。 2. 先假设这个数的**最右边一位是 1**,那么**减去 1 时**,**最后一位变成 0**,而**其他所有位都保持不变**,也就是**最后一位相当于做了取反操作**,**由 1 变成了 0**。 3. 接下来假设**最后一位不是 1 而是 0**的情况,如果该整数的二进制表示中**最右边的 1 位于第 $m$ 位**,那么**减去 1 时**,**第 $m$ 位由 1 变成 0**,而**第 $m$ 位之后的所有 0 都变成了 1**,整数中**第 $m$ 位之前的所有位都保持不变**,例如一个二进制数 1100,他的第二位是从右边数起的第一个 1,减去 1 后,第二位变成 0,他后面的两位 0 变成 1,而前面的 1 保持不变,因此得到的结果是 1011。 4. 在前面两种情况中,我们发现**把一个整数减去 1**,**都是把最右边的 1 变成 0**,**如果他的右边还有 0**,**则所有的 0 都变成 1**,**而他左边的所有位都保持不变**,接下来我们**把一个整数和他减去 1 的结果做与运算**,**相当于把他最右边的 1 变成 0**,还是以前面的 1100 为例,他减去 1 的结果是 1011,我们再把 1100 和 1011 做位与运算,得到的结果是 1000,我们把 1100 最右边的 1 变成了 0,结果刚好就是 1000。 5. 我们把上面的分析总结起来就是,**把一个整数减去 1**,**再和原整数做与运算**,**会把该整数最右边的 1 变成 0**,**一个整数的二进制表示中有多少个 1**,**就可以进行多少次这样的操作**。 ### 2.2.2 参考代码 ```java /** * 剑指 Offer 15. 二进制中 1 的个数(版本 2:巧用 n & (n - 1)) * @param n * @return */ public int hammingWeightV2(int n) { int res = 0; while (n != 0) { res++; n = n & (n - 1); } return res; } ``` # 参考文献 1. [剑指 Offer 15. 二进制中 1 的个数](https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof)。 2. [面试题 15. 二进制中 1 的个数(位运算,清晰图解)](https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/solution/mian-shi-ti-15-er-jin-zhi-zhong-1de-ge-shu-wei-yun)。 3. 《剑指 Offer(第 2 版)》。
ricear
June 18, 2022, 10:42 a.m.
©
BY-NC-ND(4.0)
转发文档
Collection documents
Last
Next
手机扫码
Copy link
手机扫一扫转发分享
Copy link
Markdown文件
share
link
type
password
Update password