【算法】使用位运算解算法题(C++)

news2025/4/9 4:34:55

文章目录

  • 0. 位运算 基本介绍
  • 1. 位运算基本使用 + 连带题目
    • 191.位1的个数
    • 338.比特位计数
    • 461.汉明距离
    • 136.只出现一次的数字
    • 260.只出现一次的数字III
  • 2. 使用位运算解决算法题
    • 面试题01.01.判定字符是否唯一
    • 371.两整数之和
    • 137.只出现一次的数字II
    • 面试题17.04.消失的数字
    • 面试题17.19.消失的两个数字

0. 位运算 基本介绍

我们知道,一般基本位运算分为以下几种:

  1. & 按位与:有0则为0
  2. | 按位或:有1则为1
  3. ^ 按位异或:记法有2
    • 相同为0,相异为1
    • 不进位相加(00->0, 01->1, 11->0,相当于两数相加但不进位)
  4. ~ 按位取反:对操作数按位取反,即0变为1,1变为0。
  5. << 向左移动:相当于将其乘以2的若干次方
  6. >> 向右移动:相当于将其除以2的若干次方

1. 位运算基本使用 + 连带题目

当我们理解了基础位运算,我们要确保可以解决下图红字中的基本问题

在这里插入图片描述

在这里插入图片描述

通过上图设计的题目和思路,我们可以顺势解决以下几道题:


191.位1的个数

在这里插入图片描述

思路:

在这里插入图片描述

如图,我们只需要 将n的每一位都&1 即可:

  1. 将n&1,结果更新到ret
  2. n右移一位,持续此过程直到n为0

代码:

int hammingWeight(uint32_t n) {
    int ret = 0; // 记录结果
    while (n)
    {
        ret += n & 1;
        n >>= 1;
    }
    return ret;
}

338.比特位计数

在这里插入图片描述

思路:

题目要求计算一个(1~n)范围内每个元素,二进制中1的个数

  1. 创建结果数组ret,变量count记录当前元素二进制中1的个数
  2. 将整个过程放到一个从0~n的循环中
  3. 计算当前元素位一的个数
  4. 将count给到ret,直至循环结束,返回ret

代码:

vector<int> countBits(int n) {
        vector<int> ret(n+1, 0);
        for(int i = 0; i <= n; ++i) // 统计0 ~ n中每个元素二进制位一的个数
        {
            int count = 0;
            int tmp = i;
            while(tmp) // 计算tmp中1的个数
            {
                count += tmp & 1;
                tmp >>= 1;
            }
            // 存储其1的个数
            ret[i] = count;
        }
        return ret;
    }

461.汉明距离

在这里插入图片描述

思路:

在这里插入图片描述

如图所示,我们知道异或相当于(相同为0,相异为1),只需要统计两数异或之后的结果中1的个数即就是不同位的个数,即汉明距离。

代码:

int hammingDistance(int x, int y) {
    int ret = 0;
    int tmp = x ^ y;
    // 异或后 1的个数 即为 二进制位不同位置数
    while(tmp)
    {
        ret += tmp & 1;
        tmp >>= 1;
    }
    
    return ret;
}

136.只出现一次的数字

在这里插入图片描述

思路:

题目要求找到整数数组中只出现过一次的数字,此题可以用哈希表解题,但位运算的时间空间复杂度总体更为优秀。

  1. 我们知道,a ^ a = 0; b ^ 0 = b;
  2. 根据该思路,将数组所有元素异或,剩余元素即为只出现一次的

代码:

int singleNumber(vector<int>& nums) {
    int ret = 0;
    // 将全部元素异或,结果为只出现一次的数字
    for(int i : nums){
        ret ^= i;
    }

    return ret;
}

260.只出现一次的数字III

在这里插入图片描述

思路:

  1. 首先异或所有元素,得到tmp(所求两数的异或结果)
  2. 将tmp & -tmp 得到两元素的不同位differ
  3. 根据此不同位进行划分:
    • 如果当前元素num与differ按位与的结果不等于0,则a ^= num
    • 反之, b ^= num
  4. 最后a,b即为两个只出现一次的数字。

在这里插入图片描述

代码:

vector<int> singleNumber(vector<int>& nums) {
    int tmp = 0;
    for(int num : nums) tmp ^= num; // 全部元素异或

    // 防止溢出
    int differ = (tmp == INT_MIN ? tmp : tmp & (-tmp)); // 找a,b的不同位
    int a = 0, b = 0;
    for(int num : nums)
    {	// 根据条件划分
        if((num & differ) != 0)
            a ^= num;
        else
            b ^= num;
    }

    return {a, b};
}

2. 使用位运算解决算法题

上面的题是小试牛刀,下面的题正式进行位运算算法的代码编写。

面试题01.01.判定字符是否唯一

在这里插入图片描述

思路:

上题解法利用位图思想 :我们通过将字符串的每个元素存到int型变量bitMap中(该位为0:未出现过,为1:出现过),通过判断所有位是否有1则可判断字符串的字符是否唯一。

在这里插入图片描述

代码:

 bool isUnique(string astr) {
     // 位图
     if(astr.size() > 26)    return false;

     int bitMap = 0; // 从后向前存放字母的出现次数,0代表未出现过,1代表出现过
     for(char ch : astr)
     {
         int i = ch - 'a'; // 取该字符位
         if((bitMap >> i) & 1 == 1)    return false; // 如果这一位存在,false
         bitMap |= (1 << i);
     }

     return true;
}

371.两整数之和

在这里插入图片描述

题意很清晰:即不使用±运算符计算两个整数的和

思路:

我们知道:

  1. 按位异或^ = 不进位相加,而我们需要相加的结果,则只需要找到进位即可。
  2. 而(a & b)就是进位结果,但我们进位是向前一位进位,所以进位为(a & b) << 1。重复上述步骤,直到进位为0,就得到了最终结果。

代码:

int getSum(int a, int b) {
    while(b != 0)
    {
        int nsum = a ^ b; // 不进位相加结果
        int carry = (a & b) << 1; // 进位数
        a = nsum;
        b = carry; // 重复步骤直到b==0
    }
    return a;
}

137.只出现一次的数字II

在这里插入图片描述
思路:

  1. 定义一个vector<int> count(32),用于存储nums中所有元素的二进制表示的各个位的出现次数;

  2. 对于记录完毕的count,count的每一位都有如下四种情况:
    在这里插入图片描述

    • 如图所示,即0, 1, 3n, 3n + 1四种情况
    • 而对这四种情况模3后结果有两种情况:0 和 1
  3. 将得出的结果还原到ret中(用|=还原)

代码:

int singleNumber(vector<int>& nums) {
    vector<int> count(32); // 存放数组所有元素的位

    for(int num : nums)
        for(int i = 0; i < 32; ++i) // 存
        {
            count[i] += (num >> i) & 1;
        }
// 遍历count中的32个元素,还原只出现一次的元素到ret中
    int ret = 0;
    for(int i = 0; i < 32; ++i)
    {
        ret |= (count[i] % 3) << i;
    }

    return ret;
}

面试题17.04.消失的数字

在这里插入图片描述

思路:

我们知道:a ^ a = 0 且 0 ^ b = b ,则利用这个性质,将nums中的数与0~n的所有数异或,最终结果则为消失的数字。

代码:

int missingNumber(vector<int>& nums) {
    // 位运算
    int n = nums.size();
    int miss = 0;
    for(int i = 0; i < n; ++i) // 与数组所有元素and 0~n-1的元素异或
    {
        miss ^= i ^ nums[i];
    }
    miss ^= n; // 异或n

    return miss;
}

面试题17.19.消失的两个数字

思路:

“只出现一次的数字Ⅲ” 中有个思想就是通过两元素的不同位,进行划分,这里也是一样

  1. 异或所有数:得到缺失的两个数字的异或和
  2. 获取 tmp 中最右边为 1 的位数:找到两个缺失数字的不同位
  3. 根据 differ 的值,将数组元素划分为两组进行异或操作

代码:

 vector<int> missingTwo(vector<int>& nums) {
    int tmp = 0;
    int n = nums.size() + 2; // 数组中缺失两个数字,所以数组长度为n+2

    // 1. 异或所有数
    for (int i = 1; i <= n; ++i)
        tmp ^= i;
    for (int num : nums)
        tmp ^= num;

    // 2. 获取最右边为1的位数(不同位)
    int differ = tmp & -tmp;

    // 3. 根据differ,划分数组元素进行异或
    int a = 0, b = 0;
    for (int i = 1; i <= n; ++i) {
        if (i & differ)
            a ^= i;
        else
            b ^= i;
    }
    for (int num : nums) {
        if (num & differ)
            a ^= num;
        else
            b ^= num;
    }

    return {a, b};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1353588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年12月GESP C++七级编程题转Python真题解析

七、2023年12月GESP C(Python)七级编程题 2023年12月GESP Python最高六级&#xff0c;但C与Python同级编程题相同。本篇引用2023年12月GESPC七级编程题&#xff0c;用Python实现。 【七级编程题1】 【试题名称】&#xff1a;商品交易 时间限制&#xff1a;1.0 s 内存限制&…

上海AI lab大模型微调

教程链接&#xff1a;InternLM学习教程链接 命令行演示结果&#xff1a; web演示结果

SpringBoot的基础配置

问题导入 入门案例中没有引入spring-webmvc等依赖包&#xff0c;没有配置Tomcat服务器&#xff0c;为什么能正常启动&#xff1f;我们没有配置端口号&#xff0c;为什么端口是8080&#xff1f; 起步依赖 starter SpringBoot中常见项目名称&#xff0c;定义了当前项目使用的所…

TB-C/C++

1.main函数之前之后执行的代码 设置栈指针初始化静态变量和全局变量&#xff08;.data段内容&#xff0c;已初始化且不为0&#xff09;赋初值&#xff08;.bss段内容&#xff0c;未初始化的全局变量和静态变量&#xff09;传参&#xff08;argc,argv&#xff09;atexit() 在…

【C++】HP-Socket(一): 下载、Linux上编译、Windows远程编译Linux版本

1、简介 国产、高性能、跨平台网络通信框架。 作者于2024-01-01更新了Release版本v5.9.4&#xff0c;辛苦了&#xff0c;向作者致敬&#xff01; 源码下载&#xff1a; https://gitee.com/mirrors/hp-socket https://github.com/ldcsaa/HP-Socket 2、编译 2.1 在Linux上编…

nifi详细介绍--一款开箱即用、功能强大可靠,可用于处理和分发数据的大数据组件

目录 目录 一、引言 二、NiFi 的历史背景介绍 三、NiFi 是什么&#xff1f; 核心特性 应用领域 四、NIFI 入门 五 、NiFi 工作流程 六、实际应用场景 七、优势总结 一、引言 NiFi&#xff08;Apache NiFi&#xff09;&#xff0c;全名为“Niagara Files”&#xff0…

[SDCTF 2022]jawt that down!

[SDCTF 2022]jawt that down! 打开题目&#xff0c;存在登录框 初步测试发现并不存在sql注入漏洞&#xff0c;只好扫一下目录发现有/js的路径 我们进一步扫描 访问/js/login.js看一下&#xff0c;搜索得到用户名和密码 AzureDiamond hunter2登陆成功后发现有个N 点进去提示t…

mysql生成数据库字典文档

项目交付离不开项目数据库字典文档。下面用python轻松生成交付文档字典。 一 生成doc文档数据库字典效果&#xff1a; 1 生成doc文件&#xff0c;如下图&#xff1a; 2 打开文件字典格式内容 &#xff0c;如下图&#xff1a; 二 python生成doc字典文档代码 生成doc数据库字典…

机器学习-基于Word2vec搜狐新闻文本分类实验

机器学习-基于Word2vec搜狐新闻文本分类实验 实验介绍 Word2vec是一群用来产生词向量的相关模型&#xff0c;由Google公司在2013年开放。Word2vec可以根据给定的语料库&#xff0c;通过优化后的训练模型快速有效地将一个词语表达成向量形式&#xff0c;为自然语言处理领域的应…

FA发放云桌面并与FC对接

&#xff08;7&#xff09;分配桌面&#xff08;该组为刚刚创建的域名用户和组&#xff09;&#xff0c;确认无误&#xff0c;直接发放 &#xff08;8&#xff09;可在任务中心查看发放的进度 3、FA的登录流程 &#xff08;1&#xff09;登录WI&#xff1a;客户端访问VLB&…

Java解析xml文档,判断对象是一个json是jsonArray还是jsonObject

有一篇xml文档&#xff0c;如下&#xff1a; 现在需要解析出其中的内容&#xff0c;首先需要明确的是&#xff0c;文档是由一个个的标签嵌套形成的&#xff0c;例如整个xml文件是由许多DescriptorRecord标签构成&#xff0c; <DescriptorRecord DescriptorClass "1&…

【数据结构】二叉树(一)——树和二叉树的概念及结构

前言: 本篇博客主要了解什么是树&#xff0c;什么是二叉树&#xff0c;以及他们的概念和结构。 文章目录 一、树的概念及结构1.1 树的基本概念1.2 树的相关特征1.3 树的实现 二、二叉树的概念及性质2.1 二叉树的概念2.2 二叉树的性质 一、树的概念及结构 1.1 树的基本概念 树&…

用邮件及时获取变更的公网IP--------python爬虫+打包成exe文件

参考获取PC机公网IP并发送至邮箱 零、找一个发送邮件的邮箱 本文用QQ邮箱为发送邮箱&#xff0c;网易等邮箱一般也有这个功能&#xff0c;代码也是通用的。 第一步&#xff1a;在设置中找到账户&#xff0c;找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务&#xff0c;点击获…

2024.1.3每日一题

LeetCode每日一题 2487.从链表中移除节点 2487. 从链表中移除节点 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个链表的头节点 head 。 移除每个右侧有一个更大数值的节点。 返回修改后链表的头节点 head 。 示例 1&#xff1a; 输入&#xff1a;head [5,…

全国计算机等级考试| 二级Python | 真题及解析(10)

一、选择题 1.要实现将实数型变量a的值保留三位小数,以下python可以实现的是( ) A.a%0.001 B.a//0.001 C.round(a,3) D.round(3,a) 2.在Python中要交换变量a和b中的值,应使用的语句组是( )。 A…

栈实现前缀表达式的计算

前缀表达式计算 过程分析 中缀表达式&#xff1a;&#xff08;1 5&#xff09;*3 > 前缀表达式&#xff1a;*153 &#xff08;可参考这篇文章&#xff1a;中缀转前缀&#xff09; 第一步&#xff1a;从右至左扫描前缀表达式&#xff08;已存放在字符数组中&#xff09;&a…

声明式的管理方法文件

1.声明式管理方法&#xff08;yaml&#xff09;文件 1.适合对资源的修改操作 2.声明式管理依赖于已有yaml文件&#xff0c;所有的内容都在yaml文件中声明 3.编辑好的yaml文件还是要依靠陈述式的命令发布到k8s集群当中 2.声明式的三种格式 1.deployment的yaml文件 demonset…

oracle-SCN系统改变号

SCN system change number 我们看到的SCN是一串数字&#xff0c;由时间经过函数算出的&#xff0c;其实就是时间。但时间的比较复杂&#xff0c;不如转换成数字比较。 给一个日志加scn号&#xff0c;其实就是给日志加上时间点。 2常见的SCN 对于scn的理解 控制文件中有两个sc…

【REST2SQL】02 GO连接Oracle数据库

Oracle数据库我用的最多&#xff0c;先研究Oracle,Go连接Oracle并实现REST和SQL服务。 1 Oracle数据库的安装 我这里安装使用的是Oracle 11g , 安装过程省略5217字。 2 安装Go-ora依赖 go get github.com/sijms/go-ora/v2 安装成功后在GOPATH目录可见&#xff1a; 3 创建一…

电脑提示找不到msvcp140.dll的修复方法,亲测有效的两种方法

msvcp140.dll是Microsoft Visual C 2015 Redistributable的一个组件&#xff0c;它包含了许多C运行时库文件。这些库文件为运行基于C编写的应用程序提供了必要的支持。当系统中缺少某个或某些库文件时&#xff0c;就可能出现msvcp140.dll丢失的错误。 一、以下是msvcp140.dll文…