题目信息

题目地址:https://leetcode-cn.com/problems/number-of-1-bits/

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

提示:

  • 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
  • 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 输入必须是长度为 32二进制串

进阶

  • 如果多次调用这个函数,你将如何优化你的算法?

题解一:辗转相除

首先理清主逻辑,判断一组个其中有多少个1,对二进制来说每个位只有0或者1,对我们熟悉的十进制来说有0,1,2 ~ 9。如果是十进制怎么判断这个位是非0呢,立马就知道是除以10

110 (十进制)
先判断个位是0还是非0
110除以10 可整除说明个位是0,留下11进一步判断11
11除以10 不能整除说明是非0,计数加一 留下1...

也就是说我们一步一步去判断每个位是否是0即可,对二进制来说非0也就是1,那么1的计数加一。

public int hammingWeight(int n) {// 计数1的个数int num = 0;while(n != 0){// 取余非0则余1,当前位是1if(n%2 != 0) num++;// 迭代n,直到n最后一个非0在个位则出循环n = n/2;}//记下最后一位非0数return ++num;
}

image-20210904165820519

那么这里有个问题就是对于负数是错误的,因为负数的二进制以补码呈现,像上述测试用例是-3,按照我们的上述逻辑应该是两个一和正3一样,就算加上最高位符号位的负号1也只能是三个一,但实际上负数以补码呈现的就像上述结果实际上是31个一

因此上述解只是在数字层面的二进制是没问题的,在代码里面因为一些编译的问题就对负数就不行了

题解二:位运算

既然上述解是这样的问题,那我们就不去在数字层面弄,就按照它的规则去数一的个数,也不用转换什么的。其实是和解法一差不多的。因为把解法一翻译一下会变成如下:

public int hammingWeight(int n) {int num = 0;while(n != 0){if((n&1) != 0) num++;n = n>>1;}return ++num;
}

翻译就是把除运算换成位移运算,除以一个进制位就等于向右位移一次,对个位取余就等于与1进行与运算。这样逻辑上虽然和上面一样但是对于负数就不一样了

在代码中对于正数来说除以2和向右位移一位是一样的,负数就不一样了因为是一个补码串,你位移它就是用这个串去位移,数的就是这个串,但你除以2得到的结果是和它的绝对值除2是一样的然后加个负号。如下:

3(8位)
0000 0011-3
1111 1101按除以2来,-3的结果也就是两个一
所以就用位运算,就不用管转换的问题了

但上面的代码是有问题的,上面的循环是为了循环到最高位的非0数,遍历完毕,这样不用遍历整个32位

对于负数来说就有问题,负数位移永远没有尽头,所以得改成for循环就循环这32位即可

public int hammingWeight(int n) {int num = 0;for(int i = 0; i < 32; i++){if((n&1) != 0) num++;n = n >> 1;}return num;
}

时间与空间复杂度都是O(1)

image-20210904230718590

题解三:位运算优化

前面题解一不用遍历完32为比如00010100 只用遍历到最高位的1即可也就是遍历5个。到了题解二位运算不能去判断是因为负数的二进制一直往右位移也永远不会等于0会进入无限循环

所以只能找另外的方式怎么一步一步的计数1的出现并且在数字里面去掉或者变为0,直到最后一个1处理完,整个数就是0了就没必要继续遍历了。这个方法就是n & (n-1),可以演示一下:

数字7也就是 0111
0111 & 0110 = 0110
0110 & 0101 = 0100
0100 & 0011 = 0000

也就是所每次都会去掉一个一,这个时候就可以计数一下。直到最终是0了,也就统计完最后一个1了。

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

image-20210904234047268

空间上去了一点可能是少了for循环的i

总结

这一题的话,主要是对于负数在Java里它的一个计算结果和常规是不一样的(这里不展开),因此就用位运算也就不存在转换。第二点就是对于一个int类型的整数它是32位,那么判断32位里有多少个1时,要不要遍历完32位才能出结果?这里就会有两个迭代方式一个是每次位移一个也就是丢掉最右边的数直到数字为0了后面也就不要遍历了,另一个是每次将最低位的1变为0,后者是更优的。因为001011对于第一种要遍历4次也就是每次丢一个直到最终数字为0,第二种方式只需要3次n & (n-1)能直接跳到最低位的1处理成0,中间的0都是直接跳过。n & (n-1)这个运算可以留意一下。还有一种最差的解法也就是转二进制串再数个数这样就没什么意义了相当与遍历了两次Integer.toBinaryString(n)

往期推荐

13 罗马数字转整数

204 计数质数

155 最小栈

198 打家劫舍

70 爬楼梯

扫描二维码获取

更多精彩

yournotes.cn

本文分享自微信公众号 - IT那个小笔记(qq1839646816)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

LeetCode初级算法之其他:191 位1的个数相关推荐

  1. leetcode初级算法5.加一

    leetcode初级算法5.加一 仅为个人刷题记录,不提供解题思路 题解与收获 我的解法:(总结在代码中) public int[] plusOne(int[] digits) {//获取digits ...

  2. leetcode初级算法4.只出现一次的数字

    leetcode初级算法4.只出现一次的数字 仅为个人刷题记录,不提供解题思路 题解与收获 我的解法: public static int singleNumber(int[] nums) {if(n ...

  3. Leetcode 初级算法 - 数学

    Leetcode 初级算法 - 数学 原始地址:https://github.com/jerrylususu/leetcode-easy 二级标题格式:[章节内题号] [题库内题号] [题目标题] 1 ...

  4. LeetCode初级算法(数组)解答

    这里记录了LeetCode初级算法中数组的一些题目: 加一 本来想先转成整数,加1后再转回去:耽美想到测试的例子考虑到了这个方法的笨重,所以int类型超了最大范围65536,导致程序出错. class ...

  5. leetcode初级算法6.字符串转整数(atoi)

    leetcode初级算法6.字符串转整数(atoi) 仅为个人刷题记录,不提供解题思路 题解与收获 我的解法: public int myAtoi(String s) {//避免魔法值先设spaceS ...

  6. leetcode初级算法4.两个数组的交集 II

    leetcode初级算法4.两个数组的交集 II 仅为个人刷题记录,不提供解题思路 题解与收获 我的解法:(总结在代码中) public int[] intersect(int[] nums1, in ...

  7. leetcode初级算法3.存在重复元素

    leetcode初级算法3.存在重复元素 仅为个人刷题记录,不提供解题思路 题解与收获 我的解法: Arrays.sort(nums);for(int i = 0; i < nums.lengt ...

  8. Leetcode 初级算法 - 设计问题

    Leetcode 初级算法 - 设计问题 原始地址:https://github.com/jerrylususu/leetcode-easy 二级标题格式:[章节内题号] [题库内题号] [题目标题] ...

  9. 剑指 Offer 15. 二进制中1的个数 + 191. 位1的个数(n(n-1)实例)

    一.题目:剑指 Offer 15. 二进制中1的个数 请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数.例如,把 9 表示成二进制是 1001,有 2 位是 1.因此, ...

  10. 领扣-191 位1的个数 Number of 1 Bits MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

最新文章

  1. java json转map
  2. Android实战——第三方服务之Bmob后端云的推送服务的集成和使用(三)
  3. vue、cnpm不是内部文件_安装了vue-loader vue-template-compiler成功后运行 vue-loader -V提示不是内部文件...
  4. java 图类_Java集合类,一张图说清楚!
  5. “中兴捧月”报文监视器的实现
  6. 轻松构建Tomcat源码
  7. 行程日志2010-03-16沙井一村(1)
  8. java中native的详解
  9. matlab竞赛论文模板,美赛数学建模比赛论文模板.doc
  10. 100个人奇数枪毙Java,在JAVA中用for循环编写程序计算1~100之间的奇数之和
  11. Linux上使用rpm安装Java jdk
  12. 计算机毕业设计Java多媒体网络教学(源码+系统+mysql数据库+lW文档)
  13. mac java 配置环境变量配置_Mac 配置环境变量的方法
  14. 如何用HTML和css实现拼图,怎样使用DIV+CSS实现拼图
  15. latex显示错误:Text line contains an invalid character. l.1
  16. android切换夜间模式吗,Android切换夜间模式
  17. Java复制一个文件到新文件夹中,并对新文件重命名
  18. 【csv乱码】csv文件打开乱码的情况
  19. 图论中的聚类系数(Clustering coefficient)简单介绍
  20. 白银之手服务器人物不显示,白银之手 - 萌娘百科 万物皆可萌的百科全书

热门文章

  1. ctfshow SQL注入Web171-174
  2. Search For Free —— 新闻爬虫及爬取结果的查询网站
  3. 折半查找判定数及平均查找长度(一定要看这 能看懂的)
  4. 创建具体的产品,并继承产品抽象类
  5. SimpleDateFormat日期格式转换及时间戳转换
  6. 工程师在美国为何成职场上的香饽饽(转自新浪乔磊)
  7. ChatGPT的各项超能力从哪儿来?万字拆解追溯技术路线图来了
  8. [mysql语法错误]--Cannot load connection class because of underlying exception
  9. 使用vue-quill-editor实现富文本编辑器(封装带移入提示)
  10. 牛人面试时英文自我介绍