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

来源:互联网 发布:知乎ios源码 编辑:程序博客网 时间:2024/06/14 13:22

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;        }    }

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

0 0
原创粉丝点击