位运算——数0的个数

最简单的方法

移位来运算:N>>=1;然后用N 同1进行“与”运算,来判断末尾是否为1

下面有更快的方法;

快速的方法:判断某一位置是否是1的一个方法,v&=(v-1);

最经典:

?

位操作比除、余操作的效率高了很多。但是,即使采用位操作,时间复杂度仍为O(log2v),log2v为二进制数的位数。那么,还能不能再降低一些复杂度呢?如果有办法让算法的复杂度只与"1"的个数有关,复杂度不就能进一步降低了吗?

同样用10 100 001来举例。如果只考虑和1的个数相关,那么,我们是否能够在每次判断中,仅与1来进行判断呢?

为了简化这个问题,我们考虑只有一个1的情况。例如:01 000 000。

如何判断给定的二进制数里面有且仅有一个1呢?可以通过判断这个数是否是2的整数次幂来实现。另外,如果只和这一个"1"进行判断,如何设计操作呢?我们知道的是,如果进行这个操作,结果为0或为1,就可以得到结论。

如果希望操作后的结果为0,01 000 000可以和00 111 111进行"与"操作。

这样,要进行的操作就是 01 000 000 &(01 000 000 - 00 000 001)= 01 000 000 &00 111 111 = 0。

因此就有了解法三的代码:

?

?    循环中直接计算1的数量(即后面的方法3)

如何只数‘1‘的个数?如果一个数字至少包含一个‘1‘位,那么这个数字减1将从最低位开始依次向高位借位,直到遇到第一个不为‘0‘的位。依次借位使得经过的位由原来的‘0‘变为‘1‘,而第一个遇到的那个‘1‘位则被借位变为‘0‘。

36 d = 100100 b

36-1 d = 100011 b

如果最低位本来就是‘1‘,那么没有发生借位。

现在把这2个数字做按位与:n & (n-1)的结果是什么?

2个数字在原先最低为‘1‘的位以下(包括这个位)的部分都不同,所以结果是保留了其他的‘1‘位。

36 & (36-1) d = 100000 b

这个结果刚好去掉了最低的一个‘1‘位

int bit_count(unsigned int n)

{

int count;

for(count = 0; n; n &= n - 1)

{

count++;

}

return count;

}

由于直接跳过‘0‘位,这个方法比上面的要略微快一些。

时间: 2024-10-03 22:20:15

位运算——数0的个数的相关文章

位运算和关于两个数交换的多种方法

我们知道,位运算在计算中有着广泛的应用. 在计算机的各种编程语言中位运算也是一种不可缺少的运算,尤其是在计算机的底层实现代码中. 以下我们就来介绍一下位运算. 1.左移运算<<  左移右移都是移动二进制数 0000-0000 0000-0000 0000-0000 0000-1100     =12 向左移动一位变为(右边缺几位就补几个0) 0000-0000 0000-0000 0000-0000 0001 1000       =24 再向左移一位 0000-0000 0000-0000

位运算(1的个数;2.判断奇偶)

1. 1的个数 int NumberOf1(int n){ int count = 0; while(n) { ++count; n=(n-1)&n; } } 同样一个问题,位运算可以提高程序的运行效率. 下面讲一下关于奇偶性的判断. 常规方法 public static boolean isOdd(int i){ return i % 2 != 0; } 位运算方法 public static boolean isOdd(int i){ return (i & 1) != 0; } 说明

【宋红康程序思想学习日记1】运用位运算思想实现两个数的互换

/** 位运算思路的一些解决办法. 交换m=12与n=5的值.*/class WeiExercise1{ public static void main(String[] args) { //方法一 /*int temp=0; int m=12; int n=5; temp=m; m=n; n=temp;*/ //方法二 /*int m=12; int n=5; m+=n; n=m-n; m=m-n;*/ //方法三 位运算 (m^n)^m==n,(m^n)^m==n int m=12;// 1

UVa 818Cutting Chains (暴力dfs+位运算+二进制法)

题意:有 n 个圆环,其中有一些已经扣在一起了,现在要打开尽量少的环,使所有的环可以组成一条链. 析:刚开始看的时候,确实是不会啊....现在有点思路,但是还是差一点,方法也不够好,最后还是参考了网上的题解,大神们的代码就是不一样, 但还是看了好久才看懂.首先是用二进制法进行暴力,因为 n 最大才是15,不会超时的,然后就是在暴力时判断打开这些环时,剩下的是不是还存在环, 如果存在那么不是不行的,然后再判断是不是有的环有两个分支以上,因为一个环如果成链那么最多只有两个分支,所以多于两个的也是不对

位运算(&amp;、|、^)与逻辑运算(&amp;&amp;、 ||)区别

刚无意在一篇文章中看到了位运算(&.|)和逻辑运算(&&.||)的介绍,想起了自己薄弱的基础知识,于是百度了几把总结了下. 首先从概念上区分下,位运算是将运算符两边的数字换算成二进制(例:0000010001)后比较相同位置上的0.1进行运算的.逻辑运算即比较运算符两边的逻辑值(true或false).概念比较抽象,下边借助实际例子比较下. 位运算 先将每个数转换成二进制,然后进行,位或(|)表示相对应的每位至少有一个为1,则结果为1,只有两个都为0,结果才为0.位与(&)

有关位运算的题

位运算 与& 0&0=0 1&0=0 0&1=0 1&1=1 或| 0|0=0 1|0=1 0|1=1 1|1=1 异或^ 0^0=0 1^0=1 0^1=1 1^1=0 题目: 实现一个函数,输入一个整数,输出该数的二进制表示中1的个数,例如9的二进制是1001,有两个1,输入9,输出1 程序1.0 写法1:模除法 int CountOne(int n) { int count = 0; while (n) { int ret = 0; ret = n % 2;

FZU1892接水管游戏-BFS加上简单的状态压缩和位运算处理

原题地址:http://acm.fzu.edu.cn/problem.php?pid=1892 Problem 1892 接水管游戏 Accept: 108    Submit: 498 Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem Description 接水管游戏的规则如下: 1.在N*N大小的方格上有两个特别的水管,分别为进水口和出水口: 2.有7种1*1大小的水管需要放在这N*N大小的方格内,使得水流能够从进水口经过这些

位运算相关内容整理

位运算相关内容整理 1) 负数 负数的右移:负数右移的话,由于要保持它是负数,所以负数的二进制的左边补1.如果一直右移的话,最后就就变成0xFFFFFFFF 即-1 如: -4>>1 为-2 :-4>>2为-1 负数的左移:跟正整数左移一样,右边补0.左移总是在低位补零,高位丢失,因而负数左移后可能会变成正数. int x = 0x8fff0000; cout << (x << 1); // 输出为536739840 cout << (-2 &l

基础位运算基本原理和应用

微信公众号 位运算是编程语言的基础,在看源码的时候会看到很多位运算代码,但是在项目代码中很少会看到位运算.因为应用代码中,有很多判断和计算都可以直接用数值的判断和计算完成,没有必要去用位运算,以至于这些基础的东西慢慢用的越来越少,慢慢也就忘了.导致的一个结果就是看源代码很费力,因为大量的位运算逻辑,看不懂.作为程序员感觉数据位运算是非常必要,有点如下: 看源码时能够更好的理解 位运算更接近计算机的习惯,执行的效率会更高 装逼利器,在项目中使用位运算,体现逼格 N种基本的位运算 位运算 -- 与运