剑指offer(C++)-JZ15:二进制中1的个数(算法-位运算)

简介: 剑指offer(C++)-JZ15:二进制中1的个数(算法-位运算)

题目描述:

输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。

数据范围:−2^31<=n<=2^31−1

即范围为:−2147483648<=n<=2147483647

示例:

输入:

10


返回值:

2


说明:

十进制中10的32位二进制表示为0000 0000 0000 0000 0000 0000 0000 1010,其中有两个1。

解题思路:

本题考察位运算。三种解题思路。


1)循环按位比较


      暴力循环,对每个位的1进行统计即可。


2)位运算公式n&(n-1)


      位运算公式n&(n-1),可以将数字最右边的1变为0。比如1011,减一后为1010,与运算得到1010;又比如1010,减一后为1001,与运算得到1000。


      利用该性质进行循环,当n为0后,退出循环停止计数即可。


3)分治法


      以32位1的数字A为例,1111 1111 1111 1111 1111 1111 1111 1111。采用分而治之的思想解题,下面将一步步为大家展示分治法的流程。


3.1)分16组


      32位每两位为一组,设定16组01,再来16组10。


      0x55555555 = 0101 0101 0101 0101  0101 0101 0101 0101


      0xaaaaaaaa = 1010 1010 1010 1010  1010 1010 1010 1010


      与数字A进行与运算可以得到每组中1的个数,比如11和01得到01,11和10得到10,然后10右移1变为01,01+01得到10也就是2,即11中1的个数。


      经过上述计算后,数字A变为A1:1010 1010 1010 1010  1010 1010 1010 1010。


3.2)分8组


      32位每四位为一组,设定8组0011,再来8组1100。


      0x33333333 = 0011 0011 0011 0011  0011 0011 0011 0011


      0xcccccccc = 1100 1100 1100 1100  1100 1100 1100 1100


      与数字A1进行与运算可以得到每组中1的个数,比如1010和0011得到0010,1010和1100得到1000,然后1000右移2变为0010,0010+0010得到0100也就是4,即1111中1的个数。聪明的同学到这里已经发现规律了,可以认为是两组两位数合为一组四位数。


      经过上述计算后,数字A1变为A2:0100 0100 0100 0100  0100 0100 0100 0100。


3.3)分4组


      32位每八位为一组,设定4组0000 1111,再来4组1111 0000。


      0x0f0f0f0f = 0000 1111 0000 1111  0000 1111 0000 1111


      0xf0f0f0f0 = 1111 0000 1111 0000  1111 0000 1111 0000


      与数字A2进行与运算可以得到每组中1的个数,比如0100 0100和0000 1111得到0000 0100,0100 0100和1111 0000得到0100 0000,然后0100 0000右移4变为0000 0100,0000 0100+0000 0100得到0000 1000也就是8,即1111 1111中1的个数。每组数最后的结果其实就是该组数里1的个数。


      经过上述计算后,数字A2变为A3:0000 1000 0000 1000  0000 1000 0000 1000。


3.4)分2组


      32位每十六位为一组,设定2组0000 0000 1111 1111,再来2组1111 1111 0000 0000。


      0x00ff00ff = 0000 0000 1111 1111  0000 0000 1111 1111


      0xff00ff00 = 1111 1111 0000 0000  1111 1111 0000 0000


      与数字A3进行与运算可以得到每组中1的个数,比如0000 1000 0000 1000和0000 0000 1111 1111得到0000 0000 0000 1000,0000 1000 0000 1000和1111 1111 0000 0000得到0000 1000 0000 0000,然后0000 1000 0000 0000右移8变为0000 0000 0000 1000,0000 0000 0000 1000+0000 0000 0000 1000得到0000 0000 0001 0000也就是16,即1111 1111 1111 1111中1的个数。


      经过上述计算后,数字A3变为A4:0000 0000 0001 0000  0000 0000 0001 0000。


3.5)分1组


      32位为一组。


      0x0000ffff = 0000 0000 0000 0000  1111 1111 1111 1111


      0xffff0000 = 1111 1111 1111 1111  0000 0000 0000 0000


      与数字A4进行与运算可以得到每组中1的个数,就是0000 0000 0001 0000加0000 0000 0001 0000等于0000 0000 0010 0000,也就是32。


      之所以用这个数字A,是因为这个数字能很直观地get到这个方法的逻辑。


      经过上述计算后,数字A4变为A5:0000 0000 0000 0000  0000 0000 0010 0000。也就是最终结果。

测试代码:

1)循环按位比较

class Solution {
public:
    // 1的个数
    int  NumberOf1(int n) {
        int count = 0;
        //遍历32位
        for(int i = 0; i < 32; ++i){
            //按位比较
            if((n & (1 << i)) != 0)   
                count++;
        }
        return count;
     }
};

2)位运算公式n&(n-1)

class Solution {
public:
    // 1的个数
    int NumberOf1(int n) {
        int count = 0;
        // 当n为0时停止比较
        while(n){  
            n &= n - 1;
            count++;
        }
        return count;
     }
};

3)分治法

class Solution {
public:
    // 1的个数
    int NumberOf1(int n) {
        int temp = n;
        // 0x55555555 = 0101 0101 0101 0101  0101 0101 0101 0101
        // 0xaaaaaaaa = 1010 1010 1010 1010  1010 1010 1010 1010
        temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa) >> 1);
        // 0x33333333 = 0011 0011 0011 0011  0011 0011 0011 0011
        // 0xcccccccc = 1100 1100 1100 1100  1100 1100 1100 1100
        temp = (temp & 0x33333333) + ((temp & 0xcccccccc) >> 2);
        // 0x0f0f0f0f = 0000 1111 0000 1111  0000 1111 0000 1111
        // 0xf0f0f0f0 = 1111 0000 1111 0000  1111 0000 1111 0000
        temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0) >> 4);
        // 0x00ff00ff = 0000 0000 1111 1111  0000 0000 1111 1111
        // 0xff00ff00 = 1111 1111 0000 0000  1111 1111 0000 0000
        temp = (temp & 0x00ff00ff) + ((temp & 0xff00ff00) >> 8);
        // 0x0000ffff = 0000 0000 0000 0000  1111 1111 1111 1111
        // 0xffff0000 = 1111 1111 1111 1111  0000 0000 0000 0000
        temp = (temp & 0x0000ffff) + ((temp & 0xffff0000) >> 16);
        return temp;
     }
};


相关文章
|
7天前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
38 15
|
6天前
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
4月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
124 1
|
25天前
|
存储 监控 算法
员工屏幕监控系统之 C++ 图像差分算法
在现代企业管理中,员工屏幕监控系统至关重要。本文探讨了其中常用的图像差分算法,该算法通过比较相邻两帧图像的像素差异,检测屏幕内容变化,如应用程序切换等。文中提供了C++实现代码,并介绍了其在实时监控、异常行为检测和数据压缩等方面的应用,展示了其实现简单、效率高的特点。
45 15
|
24天前
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
47 12
|
16天前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
21 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
2月前
|
负载均衡 算法 安全
探秘:基于 C++ 的局域网电脑控制软件自适应指令分发算法
在现代企业信息化架构中,局域网电脑控制软件如同“指挥官”,通过自适应指令分发算法动态调整指令发送节奏与数据量,确保不同性能的终端设备高效运行。基于C++语言,利用套接字实现稳定连接和线程同步管理,结合实时状态反馈,优化指令分发策略,提升整体管控效率,保障网络稳定,助力数字化办公。
71 19
|
2月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
61 2
|
3月前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
2月前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。