其他 - 位运算 - 一个二进制数里, 有多少个 1
-
概述
- 常见的简单面试题
- 很多博客也讲过这道题
- 仅仅是自己的简单积累, 没有什么标新立异的想法
- 位运算
- 常见的简单面试题
-
背景
-
大学我就没学好计算机基础和组成原理
- 老师太仁慈
- 当时自己觉得, 这些东西, 用处不大
- 现在想想, 还是太幼稚了
-
面试碰到过类似的题
- 新浪微博
- 作业帮
- 也是恶心
- 唯独作业帮终面, 问过我技术
- 还是 tm 位运算
- 还是看我一个不会, 接着又问了一个
- 多谢不招之恩
-
牢骚发完, 开始说正题
-
1. 问题: 一个二进制数里, 有多少个 1
-
概述
- 常见面试题
- 只记录思路, 不具体实现
-
问题
- 一个二进制数里, 有多少位是 1
-
准备
-
硬件
- 假设硬件就都能满足
- 范围就定在 int 里面吧
- 假设硬件就都能满足
-
软件
- 语言自选
- 毕竟只记录思路
- 语言自选
-
-
其他
- 健壮性, 输出 相关的东西, 我也不考虑
2. 思路
1. 思路1: 转化为字符类, 统计 1 的个数
-
概述
- 转化后统计
-
思路
- 转化为 String 或者 char 数组
- 统计 1 的个数
-
优劣
-
优势
- 思路简单直接
- 现成 api 直接使用
-
劣势
- 容易被面试官否决
- 他们就想考你二进制, 你用 api 把他们打发了, 会觉得有一丢丢没面子
- 性能有劣势
- 转化后遍历, 性能确实有损失
- 实际中, 系统代码我不清楚, 业务代码基本都是先跑通, 然后就没有然后了
- 容易被面试官否决
-
2. 思路2: 位运算, 和 1 作与, 然后 右移
-
概述
- 和 思路1 类似
- 使用了 二进制 相关的运算
-
思路
-
结束条件
- 输入a 为 0
-
一轮循环
- 做与
- 将 输入a 和 1 作 与操作
- 统计
- 与的结果b
- 1: 计数加1
- 0: 计数不变
- 与的结果b
- 位移
- 将 输入a 右移 一位
- 最低位丢了就丢了吧
- 当然, 你也可以把 1 向左移动一位
- 将 输入a 右移 一位
- 做与
-
-
优劣
-
优势
- 本质上还是 思路1 的延续
- 简单直接
- 可读性好
- 使用了 二进制, 一定程度上, 堵住了 面试官 的嘴
- 本质上还是 思路1 的延续
-
劣势
- 如果面试官还想要 骚操作, 这个操作显然不够骚
- 我并不觉得, 这个是 太大的劣势
- 性能问题
- 老实说, 这个思路的性能, 还有地方可以改进
- 比如, 我判断 10000001, 我需要走 8 轮循环
- 如果面试官还想要 骚操作, 这个操作显然不够骚
-
3. 思路3: 位运算, 更骚的操作
-
概述
- 另一种 位运算 的思路
-
思路
-
结束条件
- 输入为 0
-
一轮循环
- 减1
- 对 输入a 减1, 得到 b
- 计数
- 计数 加一
- 作与
- 将 a 和 b 作与
- 将 与 的结果, 赋值给 a, 继续下一轮
- 减1
-
-
疑问: 为什么这个方法可以
-
问题
- 这种方法是如何做到题目要求的
- 有 理论依据 吗
-
结果
-
首先, 我无法解决 理论依据
- 十进制 转 二进制 的短除法, 都有 数学推理
- 这个我自己么想出来, 也没找到
-
但是可以通过 观察, 来获得相关的信息
-
-
表格
aa - 1a & (a - 1)001 000 000 010 001 000 011 010 010 100 011 000 101 100 100 110 101 100 111 110 101 -
结论
- a = 1, a 和 (a - 1) 作与, 确实可以消掉一个 1
- a > 1, 高位的 1, 也可以这样消掉
- 一次, 只消掉 一个1
- 而且每次, 都只会消掉 最靠右 的那个 1
- 为啥是这样, 我也没搞懂...
-
-
优劣
- 优势
- 逼格高, 面试官喜欢
- 效率高
- 有几个 1, 就 只用循环几次
- 碰到 100000001 这种, 就会少很多轮循环
- 劣势
- 思路不那么好想
- 我也没想通, 我只是靠观察, 硬记住了规律
- 代码可读性, 没有前两个强
- 思路不那么好想
- 优势
3. 其他
1. 与
-
操作
- 和 全0 与, 置 0
- 和 全1 与, 不变
-
应用
- 子网掩码
- 只关注我想关注的部分
- 其他部分直接忽视
- 子网掩码
2. 或
- 操作
- 和 全1 或, 置 1
- 和 全0 或, 不变
3. 非
- 操作
- 取反
4. 异或
-
操作
- 和 全1 异或, 取反
- 和 全0 异或, 不变
- 和 自己 异或, 得0
-
应用
- 面试题: 很多数, 只有一个数出现了一遍, 怎么找那个数
- 遍历集合, 异或 所有的数, 是一个比较简单的思路
- 面试题: 很多数, 只有一个数出现了一遍, 怎么找那个数
尽量尝试解释清楚; 自己校对能力有限, 如果有错误欢迎指出