《剑指offer》——二进制中1的个数

60 篇文章 3 订阅

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~

T:

题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思考:
首先要弄明白整数、负数和0在二进制中是怎么表示的。

三个概念至少要明白:

  • 原码
  • 反码
  • 补码

这里就不多叙述,给出别人解释的相关链接:

  1. http://www.360doc.com/content/12/0801/17/6828497_227700914.shtml
  2. http://wenku.baidu.com/link?url=8ZlI8FKsNWj3nMk7P7dUwriLD342N6rlc2kZiaUj2XG-gGtXcRXc3ci2qKAX4_nq6m8mot0W8awgIzXmDTs3pfRgKjvD4BiYjX-qcSME5n3

对于一个正数(包括0),其二进制中1的个数很好统计,直接一步步的进行右移”>>“操作,如果右移之后的值是个奇数,即最后一位为1,那就统计,知道该数为0为止。

对于一个负数,就要相对复杂一些:
上图:
这里写图片描述

可以看到,如果还按照正数的统计方法,统计1的个数,这是个死循环,因为进行**>>**运算的时候,负数的最高位是补的1,1的个数永远也统计不完,而正数的最高位补的是0。

那么,反过来想:既然总位数都是32位(int类型),对于一个负数的二进制表示,能不能统计0的个数呢?

我的第一个思路就是还是沿用正数的统计方式,让负数中所有的1变为0,所有的0变为1,这样不就能统计负数中0的个数了吗?

怎么变呢?想到的一种方法是让负数与-1进行**^**运算,因为-1的二进制表示是32个1,进行异或,正好满足题意。
上图:
这里写图片描述

得到正数14,那就能进行正数方式的统计了,上代码:
code:

	package niuke.sward2offer.numberof1;
	
	/**
	 * T:二进制中1的个数
	 * 
	 * 题目描述 
	 * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
	 * 
	 * date: 2015.11.4 18:03
	 * 
	 * @author SSS
	 *
	 */
	public class Solution {

		public int NumberOf1(int n) {
			// 标记一个数是否是负数
			boolean flag = true;
			
			/**
			 *如果是一个负数,要做的有两点:
			 *1. 对flag进行标记
			 *2. 该数要和-1进行异或^
			 *
			 *和-1进行异或,是因为-1的补码表示是32个1,进行异或后,
			 *该负数的补码表示中,所有为0的位,都变为了1,就和正数一样进行1的统计,
			 *最后还要用32减去该值,因为在n为负数的情况下,统计的是其中位数为0的个数。
			 */
			if (n < 0) {
				flag = false;
				n = n ^ -1;
			}
			
			int count = 0;
			while (n != 0) {
				if (n%2 != 0) {
					count ++;
				}
				n = n>>1;
			}
			
			if (!flag) {
				count = 32 - count;
			}
			
			return count;
		}
		
		public static void main(String []args) {
			int n = 1;
			
			Solution solution  = new Solution();
			System.out.println(solution.NumberOf1(n));
		}
	}

收获:

  • 负数的右移**>>**运算,其符号位补1,而正数是补0;
  • 在计算机二进制下,任意一个数 n,满足:-n = (n ^ -1) + 1
    举个栗子:
    负数 -22,有 -22 ^ -1 = 21
    正数 9,有 9 ^ -1 = -10

升级版:

接着上面的思考,如果统计0的个数,怎么让循环结束呢?我们观察负数的**>>**运算,会发现,最后32位上的值都是1,那么这32个1代表的是什么数呢? 对! 是-1。所以,可以用-1作为循环结束条件。

如何判断中间0的个数呢?对于负奇数,其最后一位是1,负偶数,最后一位是0.

code:

	public class Solution {
	    public int NumberOf1(int n) {
	 
	        int count = 0;
	         
	        if (n < 0) {
	            count = 32;
	            while (n != -1) {
	                if (n % 2 == 0) {
	                    count --;
	                }
	                n  = n >> 1;
	            }
	            return count;
	        }
	         
	        while (n > 0) {
	            if (n % 2 != 0) {
	                count ++;
	            }
	            n >>= 1;
	        }
	         
	        return count;
	    }
	}

讨论版里看到的神级代码,确实没想到这么去做…
这里写图片描述

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值