Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.

Note:

  1. The given integer is guaranteed to fit within the range of a 32-bit signed integer.
  2. You could assume no leading zero bit in the integer’s binary representation.

Example 1:

Input: 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.

Example 2:

Input: 1
Output: 0
Explanation: The binary representation of 1 is 1 (no leading zero bits), and its complement is 0. So you need to output 0.

Subscribe to see which companies asked this question


【题目分析】

给定一个正整数,对该数的二进制表示形式,从最高位的1开始向后按位取反。

【思路】

如果我们能知道该数最高位的1所在的位置,就可以构造一个长度和该数据所占位置一样长的一个掩码mask,然后概述和mask进行异或即可。

例如:5的二进制是101,我们的构造的掩码为mask=111,两者异或则为010,即是所要的结果。

【java代码1】

 public class Solution {
public int findComplement(int num) {
int mask = 1, temp = num;
while(temp > 0) {
mask = mask << 1;
temp = temp >> 1;
}
return num^(mask-1);
}
}

【java代码2】

 public class Solution {
public int findComplement(int num) {
int mask = (Integer.highestOneBit(num) << 1) - 1;
return num^mask;
}
}

Integer.highestOneBit(i)是一个什么样的函数呢?

首先来补充一点背景知识。
 
1、在计算机系统中,数值一律使用补码来表示和存储。主要原因是使用补码可以将符号位和其它位统一处理;同时,减法也可按照加法来处理。另 外,   两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。
- 补码与原码的转换过程几乎相同。
    - 数值的补码表示(分两种)
        - 正数的补码:与原码相同
        - 负数的补码:符号位位1,其余位位该数绝对值的原码按位取反;然后整个数加1
    - 已知一个数的补码,求原码的操作分为两种情况
        - 如果补码的符号位“0”,表示是一个正数,所以补码就是该数的原码
        - 如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位位1,其余各位取反,然后整个数加1。
2、移位运算符就是在二进制的基础上对数字进行平移。Java按照平移的方向和填充数字的规则分为三种:<<左移,>>带符号右移 和>>>无符号右移。
3、 在Java的移位运算中,byte、short和char类型移位后的结果会变成int类型,对于byte、short、char和int进行移位时,对于char、short、char和int进行移位操作时,规定实际移动的次数是移动次数和32的余数,也就是移位33次和移位1次得到的结果相同。移动long型的数值时,规定实际移动的次数是移动次数和64的余数,也就是移动65次移位1次得到相同的结果。
    (1) <<  运算规则:按二进制形式吧所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
    语法格式:
         需要移位的数字<<移位的次数
         例如:4<<2 ,则是将数字4左移2位
     计算过程
         4<<2
        Java中一个int数占四个字节,那么4的二进制数字为00000000 00000000 00000000 00000100,然后把该数字左移两位。其它的数字都朝右平移两位,最后在低位(右侧)的两个空位补零。则得到的最终结果是00000000 00000000 00000000 00010000,即转换为十进制数16。
         在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
         在溢出的前提前,则不符合这个规律。读者可以尝试输出(long)1610612736*4和1610612736<<2这两个结果进行比对。
    (2)>>运算规则:按二进制形式吧所有的数字都向右移动对应的位置,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1。
     语法格式:
         需要移位的数字>>移位的次数
         例如:-4>>2和4>>2,则是将数字 -4和4右移2位
     计算过程
         4>>2
         Java中一个int数占四个字节,同样4的二进制为00000000 00000000 00000000 00000100,然后把该数字右移两位。其它的数字都朝左平移两位,最后在高位补符号位(该数是正数,全补零),得到的结果是00000000 00000000 00000000 00000001,即使十进制的1。数学意义就是右移移位相当于除2,右移n位相当于除以2的n次方。
        4>>2
         由于负数在计算机中是以补码的形式存储的,那么-4的二进制为11111111 11111111 11111111 11111100,然后把该数字右移两位,其它数字都朝左平移两位,最后在高位补符号位(该数是负数,全补一),得到的结果是11111111 11111111 11111111 11111111(补码格式),即是十进制的-1。
    (3)>>>运算规则:按二进制形式吧所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补零。正数运算结果与带符号右移相同,对于负数来说则不同。
         对于4>>>2和-4>>>2运算,可以通过上述例子进行类推。
 
了解了Java的位运算之后,来看下  Integer.highestOneBit (i) 这个函数的实现代码:
 
 publicstaticinthighestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
 
1、第一步的作用是把最高位1右移移位,并与原数据按位取或。那么这就使得最高位和它的下一位是连续两个1。
2、第二步的作用是把刚刚移位得到连续两个1继续右移两位并与原数据按位取或。那么这就使得最高两位和它的下两个连续位组成四个连续的1。
3、 以此类推,最终得到的i是从开始的最高位到结束全是1。并减去i不带符号的右移一位,即可得到一个int数据的最高位的值。
4、上述情况是针对于i不为零和负数的情况,如果i为零,那么得到的结果始终为零。如果i位负数,那么得到的结果始终是-2147483648。即等于Integer.MIN_VALUE。(原因在于负数的最高位始终为1,即是负数的符号位)
 
此函数的最重要理解点在与要始终把握二进制的最高位进行运算处理,那么对于函数中的右移一位、两位、四位、八和十六位就好理解了。同理,对于long类型的取最高位运算应该需要加一条语句 i|=(i>>32); 原因在于long类型在Java中是64位的。
Long类型的hightestOneBit(i)代码如下:
 public static long highestOneBit(long i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
i |= (i >> 32);
return i - (i >>> 1);
}

LeetCode 476. Number Complement的更多相关文章

  1. LeetCode#476 Number Complement - in Swift

    Given a positive integer, output its complement number. The complement strategy is to flip the bits ...

  2. LeetCode 476. Number Complement (数的补数)

    Given a positive integer, output its complement number. The complement strategy is to flip the bits ...

  3. LeetCode 476 Number Complement 解题报告

    题目要求 Given a positive integer, output its complement number. The complement strategy is to flip the ...

  4. LeetCode: 476 Number Complement(easy)

    题目: Given a positive integer, output its complement number. The complement strategy is to flip the b ...

  5. 【leetcode】476. Number Complement

    problem 476. Number Complement solution1: class Solution { public: int findComplement(int num) { //正 ...

  6. 【LeetCode】476. Number Complement (java实现)

    原题链接 https://leetcode.com/problems/number-complement/ 原题 Given a positive integer, output its comple ...

  7. [LeetCode&Python] Problem 476. Number Complement

    Given a positive integer, output its complement number. The complement strategy is to flip the bits ...

  8. 476. Number Complement

    题目 Given a positive integer, output its complement number. The complement strategy is to flip the bi ...

  9. 476. Number Complement 二进制中的相反对应数

    [抄题]: Given a positive integer, output its complement number. The complement strategy is to flip the ...

随机推荐

  1. MVC 控制器激活

    MVC 控制器激活 ASP.NET MVC 控制器激活(三) 前言 在上个篇幅中说到从控制器工厂的GetControllerInstance()方法来执行控制器的注入,本篇要讲是在GetControl ...

  2. SQLSERVER 数据库性能的的基本 MVC + EF + Bootstrap 2 权限管理

    SQLSERVER 数据库性能的基本 很久没有写文章了,在系统正式上线之前,DBA一般都要测试一下服务器的性能 比如你有很多的服务器,有些做web服务器,有些做缓存服务器,有些做文件服务器,有些做数据 ...

  3. c#通用多线程基类,以队列形式

    c#通用多线程基类,以队列形式 个人原创.欢迎转载.转载请注明出处.http://www.cnblogs.com/zetee/p/3487084.html 多线程这个概念大家都很熟悉,对于winfor ...

  4. mac 下nginx加入开机启动

    通过brew install nginx后设置开机启动项 sudo cp /usr/local/opt/nginx/*.plist /Library/LaunchDaemonssudo launchc ...

  5. 图解Javascript之Function

    好东西分享给大家,但要尊重事实!!!因此特别说明:本图非我本人亲自所作,乃我大天朝网友所绘制.个人感觉此图,覆盖全面,细节考虑甚周全,因此分享给大家,同时在此特别感谢网友的无私分享!

  6. DevExpress 学习使用之 TreeList

    1. 必须先添加列,否则不能显示任何节点内容 2. 如果是代码添加列时,一定要写明 VisibleIndex = 几,没有这句,不显示 3. 顶级结点用 TreeList.AppendNode 来添加 ...

  7. Unable to start activity异常的解决方案

    当时我正在测试一个用户身份验证组件.使用的是android内置的Accounts API.当时的情况是,需要在App2中调用App1的用户身份验证组件,但是不知道为什么登入界面总是无法正常开启.后来我 ...

  8. MongoDB学习之--增删改查(2)

    昨天简单介绍了官方驱动操作MongoDB进行增删查操作的,今天继续介绍更新操作..... 方法简介 官方驱动中更新操作使用collection的Update方法,有泛型和非泛型两个版本: 其签名如下( ...

  9. IceMx.Mvc 我的js MVC 框架 三、动手来写一个评论模块儿

    介绍 本人菜鸟,一些自己的浅薄见解,望各位大神指正. 本框架有以下优点 1.简单(调用简单.实现简单.不过度设计) 2.视图.控制器.模型分离(分离对于维护十分有必要) 3.组件化(每一个mvc模块儿 ...

  10. 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的选择

    目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的选择 ASP.NET Web API能够根据请求激活目标HttpController ...