zoukankan      html  css  js  c++  java
  • 位运算问题

    位运算问题

    异或 (^ )

    只出现一次的数字I 136题:

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
    说明:
    你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

    分析:

    根据 A ^ A=0 ; 0 ^ A=A 将整个数组俩俩异或 最后剩的就是只出现一次的元素

    代码:

    public int singleNumber(int[] nums) {
            int a=0;
             for(int i=0;i<nums.length;i++){
                 
                 a=a^nums[i];
             }
            return a;
    }
    

    只出现一次的数字III 260题:

    给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

    示例:

    输入: [1,2,1,3,2,5]
    输出: [3,5]
    

    分析:

    一次遍历不够,要两次。第一次得到两个单数的异或;第二次利用技巧将数组分成两个集合,两个集合都只有一个单数,其余数都成对。。。

    代码:

    public int[] singleNumber(int[] nums) {
            int diff=0;
           
           //第一趟遍历  和I相同 目的是求出所求的两个单身数的XOR
            for (int num:nums) {    
                diff^=num;
            }
            diff&=-diff;      //elegent!因为上一步后diff中肯定至少有一位为1  
            //这一步的目的是找到最靠右的那个1(当然不找最右的也一样)作为二趟遍历中的判断标志位   例如diff为:000100
           
            int[] res={0,0};          //保存要找的那两个单身数的数组
           
           //第二趟遍历
            for (int num:nums){    
                if ((num&diff)==0){      /*判断是为了分成两个集合XOR 这两个集合中各自包含一个单身数 
                                           并且每个集合中除了那个单身数都是成对的(两个相同的数对于diff中的那一个标志位                                       一定也一样啊,所以一定会判断到一个集合中)
                                            每个集合内全部XOR就能得到那个单身数
                                         */
                    res[0]^=num;
                }else {
                    res[1]^=num;
                }
            }
            return res;
        }
    

    只出现一次的数字II 137题:

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
    说明:
    你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

    分析:

    这题参考博客上的做法 好理解一些: 考虑每个元素的为一个32位的二进制数,这样每一位上出现要么为1 ,要么为0。对数组,统计每一位上1 出现的次数count,必定是3N或者3N+1 次。让count对3取模,能够获得到那个只出现1次的元素该位是0还是1

    还有一种简单的异或方法 discuss

    代码:

     public int singleNumber(int[] nums) {
            int res=0;
            for (int i=0;i<32;i++){
                int mask=1<<i;
                int count=0;
                for (int j=0;j<nums.length;j++){
                    if ((nums[j]&mask)!=0){
                        count++;
                    }
                }
                if (count%3!=0){
                    res=res|mask;
                }
            }
            return res;
        }
    

    求众数 169题:

    给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
    你可以假设数组是非空的,并且给定的数组总是存在众数。

    分析:

    这题方法很多 排序,哈希表,摩尔投票,count bits,位运算。用count bits和137题差不多,也是32位,按位统计(比较慢)。

    代码:

    位运算:

    public int majorityElement(int[] num) {
    
        int ret = 0;
    
        for (int i = 0; i < 32; i++) {
    
            int ones = 0, zeros = 0;
    
            for (int j = 0; j < num.length; j++) {
                if ((num[j] & (1 << i)) != 0) {
                    ++ones;
                }
                else
                    ++zeros;
            }
    
            if (ones > zeros)
                ret |= (1 << i);
        }
        
        return ret;
    }
    

    摩尔投票:

     public int majorityElement(int[] nums) {
            int major=nums[0],count=1;
            for (int i = 1; i <nums.length ; i++) {
                if (count==0){
                    major=nums[i];
                    count++;
                }else if (major==nums[i]){
                    count++;
                }else count--;
                
            }
            return major;
        }
    

    缺失数字 268题:

    给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

    示例:

    输入: [9,6,4,2,3,5,7,0,1]
    输出: 8
    

    分析:

    这题主要的方法有两种:哈希表 或者 位元算 。相比之下位运算的空间复杂度只有O(1),所以更好。
    利用异或性质 A ^ B ^ B=A;

    代码:

    public int missingNumber(int[] nums) {
            int res=nums.length;
            for (int i = 0; i <nums.length ; i++) {
                res=res^i^nums[i];
            }
            return res;
        }
    

    移位 (<< ; >> ; >>>)

    颠倒二进制位 190题:

    颠倒给定的 32 位无符号整数的二进制位。

    示例:

    输入: 43261596
    输出: 964176192
    解释: 43261596 的二进制表示形式为 00000010100101000001111010011100 ,
         返回 964176192,其二进制表示形式为 00111001011110000010100101000000 。
    

    分析:

    右移位,每次取最低位;加到结果,结果左移位。(32bit)

    代码:

    public int reverseBits(int n) {
            int res=0;
            for (int i = 0; i <32 ; i++) {
                res=res<<i+(n&1);
                n=n<<1;
            }
            return res;
        }
    

    位1的个数 191题:

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

    分析:

    注意条件中的无符号整数条件。思路就是移位,&1,逐位统计。

    还要注意这里的移位:右移有两种,一种无符号右移位>>>;一种有符号右移位>> 。区别在于移位后拿什么补空位,>>是哪符号位补(0或1),>>>拿0补

    <<      :     左移运算符,num << 1,相当于num乘以2
    
    >>      :     右移运算符,num >> 1,相当于num除以2
    
    >>>    :     无符号右移,忽略符号位,空位都以0补齐
    

    代码:

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

    数字范围按位与 201题:

    给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。

    分析:

    当m!=n时,从m到n中肯定存在一个奇数一个偶数,而 奇数&偶数 的最后一位为0,所以最后结果的最后一位一定为零。我们将m和n的结尾cut掉,再赋值给m和n,直到m==n ,最后再在m后边补上等于被cut掉的位数的0。

    代码:

    public int rangeBitwiseAnd(int m, int n) {
          int i = 0; // i means we have how many bits are 0 on the right
          while(m != n){
            m >>= 1;
            n >>= 1;
            i++;  
          }  
          return m << i;  
        }
    

    与 (&)

    2的幂 231题:

    给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

    示例:

    输入: 1
    输出: true
    解释: 2^0 = 1
    

    分析:

    如果一个数(正数)是2的幂,那么它的二进制表示中一定只有一个1。所以可以统计二进制中1的个数来判断,但更简单的是 n&(n-1)看结果是否为0。

    代码:

    public boolean isPowerOfTwo(int n) {
             if(n<=0) return false;
            if((n&(n-1))==0){
                return true;
            }
            else return false;
        }
    

  • 相关阅读:
    关于postman与shiro权限验证问题
    springboot对shiro进行mock单元测试
    深入理解spring注解之@ComponentScan注解
    springboot项目启动,但是访问报404错误
    通过jedis连接redis单机成功,使用redis客户端可以连接集群,但使用JedisCluster连接redis集群一直报Could not get a resource from the pool
    重装系统后ORACLE数据库恢复的方法
    ORA-03113: end-of-file on communication channel 解决方法
    ORA-03113:通信通道的文件结尾-完美解决方案
    由于Windows和Linux行尾标识引起脚本无法运行的解决
    在cmd命令行中弹出Windows对话框(使用mshta.exe命令)
  • 原文地址:https://www.cnblogs.com/10zhang/p/9598223.html
Copyright © 2011-2022 走看看