专题四_位运算( >> , << , , | , ^ )_算法详细总结

news2024/11/23 13:20:46

目录

位运算

常见位运算总结

1.基础位运算

2.给一个数 n ,确定它的二进制表示中的第 x 位是 0 还是 1

3.运算符的优先级

4.将一个数 n 的二进制表示的第 x 位修改成 1 

5.将一个数n的二进制表示的第x位修改成0

6.位图的思想

7.提取一个数(n)二进制表示中最右侧的 1 (lowbit)

8.干掉一个数(n)二进制表示中最右侧的 1

9.异或(^) 运算的规律

1. 判断字符是否唯⼀(easy)

解析:

1.暴力

2.位运算

总结:

2. 丢失的数字(easy)

解析:

1.暴力

2.位运算

总结:

3. 两整数之和(medium)

解析:

1.暴力:

2.位运算

总结:

4. 只出现⼀次的数字 II(medium)

解析:

1.暴力:

2.位运算:

总结:

5. 消失的两个数字(hard)

解析:

1.暴力:

2.位运算

总结:


位运算

常见位运算总结

1.基础位运算

  << : 数 n 的二进制左移x位                         按位与  &:有 0 就 0  (看&有没有很圆,长得很像0)

  >> : 数 n 的二进制右移x位                         按位或  | : 有 1 就 1  (看|  是不是长得很像1)

  ~  (按位取反,所有位0变1,1变0)          异或运算 ^ : 相同为0 ,相异为 1 / 无尽位相加 

eg:

2.给一个数 n ,确定它的二进制表示中的第 x 位是 0 还是 1

3.运算符的优先级

能加括号就加括号u,绝对不会错

4.将一个数 n 的二进制表示的第 x 位修改成 1 

5.将一个数n的二进制表示的第x位修改成0

那么就跟上一个思路一样,只要第x位,遇0,变0,即可。(&按位与)其他位全都&上一个1即可。

6.位图的思想

位图的思想其实就是哈希表

7.提取一个数(n)二进制表示中最右侧的 1 (lowbit)

n & (-n)  本质就是,得到最右侧的1,那么要考虑其他位都是于n 的每一位相反,但就是要保证最右侧的1,不变,然后&即可。

那么 (-n)就是先~(按位取反)再+1,就会让按位取反的1全都进位,变成0,知道遇到取反后的第一个0,变成1,就又变回了原来的1,然后再&即可。

8.干掉一个数(n)二进制表示中最右侧的 1

n & (n-1)  ,条件就是 n -1 就能一直向前借位,知道第一个不是0的1变成0.

再& ,就只会改变左边到借位这些位,全部都遇0,变0,到达删掉最右侧的1的效果 

9.异或(^) 运算的规律

1.a ^ 0 = a

2.a ^ a = 0 (消消乐)

3.a ^ b ^ c = a ^ (b ^ c)

^异或,再其数二进制的每一位上,相同为0,相异为1

那么就直接上例题:

1. 判断字符是否唯⼀(easy)

题目就是判断是不是字符串的字符是不是又重复的,但是不能借助任何数据结构,那么就可以考虑利用位运算,把字符当作比特位一样放在32位的数组里,如果有重复的,那么就可以利用比特位的0或1来判断。

解析:

1.暴力

不用多说,就是创建一个数组,来判断是否有字符的个数大于等于2,就返回false

2.位运算

利用一个int型32比特位来计算是否存在重复的字符,可以将字符s[i]-'a' 来存入这个32位里

class Solution {
public:
    bool isUnique(string astr) {
        int n=astr.size();if(n>26) return false;
        int bitMap=0;
        for(auto e : astr)
        {
            int i=e-'a';
            //判断该字符是否存在过
            if((bitMap>>i)&1==1) return false;
            //如果不是,我就要把第i位改成1;
            bitMap |= (1<<i);
        }
        return true;
    }
};

总结:

用bitMap来创建一个相当于int型的数组,i来存储每一位字符该移动的位数,那么就将bitMap>>i移动i位后,在跟1进行按位与,如果第一位都是1,那么就会得到1,说明之前就重复存在过,返回false

只要没有返回false 说明都是第一次出现,那么就将他bitMap这一比特位进行改变为1 ,先将1<<左移i位后进行或等于。遇1就改变。

2. 丢失的数字(easy)

这题题目意思比较简单,就是数组范围是[0,n] 那么他们就缺少一个数字x,对于ret进行^异或计算,^异或有消消乐的能力,也有无进位相加,那么进行消消乐,最后有一个数没有被消掉,就可以直接返回。

解析:

1.暴力

不用多少,排序后对数组的每一个元素跟[0,n]进行比较,如果有有一个不相等,那么就返回这个i

2.位运算

利用^异或运算,将没有消掉的数字进行返回就ok

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int ret=0;
        for(auto e : nums) ret^=e;
        for(int i=0;i<=nums.size();i++) ret^=i;
        return ret;
    }
};

总结:

^异或运算, 具有消消乐和无进位相加,那么这题就利用了消消乐的性质,翻译过来其实就是找到只出现了一次的数字这个意思,将出现了两次的数字给消掉了

3. 两整数之和(medium)

不使用加减得到两数之和,那么就肯定考虑的是位运算,利用上一题提到的^,无进位相加,具有相加性质,那么就可以进行运算

解析:

1.暴力:

其实像这种都是简单的面试题,如果未来机式,管他3*7=21,都是直接return a+b;

2.位运算

利用^ 异或运算,进行无进位相加,那么相加的都是无进位的,然后将这个值赋值给a,在单独求进位,这个时候你会发现(a&b) 就全是进位,但是都是本该进位的值在原来的位,所以全都要进一位,就全都要进行<<1左移1位,在赋值给b,在重复进行(a^b),直到b无进位为止

class Solution {
public:
    int getSum(int a, int b) {
        while(b)
        {
            int x=a^b;
            int jinwei=(a&b)<<1;
            a=x;
            b=jinwei;//知道进位为0
        }
        return a;
    }
};

总结:

本题利用^异或运算进行无进位相加,但是仍具有相加性质,只要在单独加上进位即可(只需要发现(a&b)全都是进位)

4. 只出现⼀次的数字 II(medium)

题目意思挺简单的,就是找数组中只出现了1次的数字,其他数字都出现了3次,那么就不能像上一题一样用^异或运算,消掉两个重复出现的数字,那么就会让数组全变成一个数字,那么就考虑其他位运算解决,本题有点难理解,还是要用心体会。

解析:

1.暴力:

用哈希表,每当把整个数组相同的数字都存到一起,最后返回只出现了一次的数字,有点麻烦了,时间复杂度高,空间复杂度也高

2.位运算:

我第一次写的时候听了好几遍视频,真的挺不好理解的。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret=0;
        int n=nums.size();
        for(int i=0;i<32;i++)
        {
            int sum=0;
            for(auto e : nums) if((e>>i)&1) sum++; //计算nums中所有数的第i位的和是多少
            if(sum%3) ret |= (1<<i);
        }
        return ret;
    }
};

总结:

首先就是再数组中找到只出现一次的数字,其他的数字都是出现三次,由于题目不让额外开辟新空间,那么就是说明只能利用位运算进行计算
那么就要思考从哪下手,比如记录一个整个数组的所有位,(每个数都含有32位,占4个字节),那么我们使用位运算,将整个数组的同一位进行相加,eg:第1位 有3n个1+0 -> 3n 或者  3n个0 + 0 -> 0  等4种情况,因为都是出现3次,那么就把记录这个位出现的次数%3 =0 或则1 ,这就证明ret 这个只出现一次的这个数字,这一位就是这个0 或者1,那么就改变ret这32位里面的这一位,知道遍历完整个数组的所有32位即可

5. 消失的两个数字(hard)

虽然这题是困难题,但是只要弄得前面的题目真很easy

解析:

1.暴力:

那就是用数组,任何一个个比较,但是违反了题意

2.位运算

就是前面几个题目的结合,理解位运算的本质,然后进行运用
方法一:sort时间复杂度不达标O(NlogN)>O(N),还可能退化到O(N^2)
O(N) 时间内只用 O(1) 的空间   就是位运算
在这种条件下,只有用位运算是最快,最节省空间的,并且很好想,就拿^ 异或运算来说,这个就相当于消消乐,因为nums数组里面全都是从1开始的数字,全部都^ 异或后,在对i从1开始到n+2个数字进行^
消除掉已经存在的数字,那么sum中记录的就是最后剩余的两个元素,即不纯在的两个数字,那么我们只需要找到一个已经消失的数字,那么再次与sum进行^ 就可以得到两个都不存在的数字
但是后面的测试用例可能不是完全有序,我就开始进行sort,这样就可以判断当nums[0]!=1的时候就可以判断出极端情况,直接得出有一个1不存在,那么就可以得到第二个不存在的数字,但是这样sort就会发现排序就花了O(NlogN) 况且当数组接近有序的时候,快排就退化到O(N^2) 所以还要进行优化
方法二:
优化:为了不排序,让时间复杂度跳到O(logN) 那么就是当tmp记录到只剩下消失的两个数字a,b那么就明白,当tmp32位里面有一位等于1的时候,就说明,在这一位上要么a==1,b==0 要么a==0,b==1 ,就是a与b在这一个比特位上绝对不同,那么就可以在1到n+2,这么多数里面进行^异或,只要在这一个比特位上数字为1的就把他^异或到a里,如果为0,就^异或到b里,然后在^异或数组nums里面的所有元素,那么a 和 b 就会被单独独立出来
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int tmp=0;
        for(auto e : nums) tmp^=e;
        for(int i=1;i<=nums.size()+2;i++) tmp^=i;

        //那么现在只剩下a,b,找出比特位不同的那一位
        int diff=0;
        while(1)
        {
            if((tmp>>diff)&1) break;
            else diff++;
        } 

        //根据diff位进行计算未出现的数字
        int a=0,b=0;
        for(int i=1;i<=nums.size()+2;i++)
        {
            if((i>>diff)&1) a^=i;
            else b^=i;
        }
        for(auto e : nums)
        {
            if((e>>diff)&1) a^=e;
            else b^=e;
        }
        return {a,b};
    }
};

总结:

就是从数组里面找出两个消失的数字,那么就考虑^异或运算,但是最后ret里面存的就是最后消失的两个数字,所以要将两个数分离。

1.就是找到一个已经消失的数,然后再进行^异或,就可以得到,但是数组要进行排序才行

2.不进行排序,那么ret里面有两个不同的数,那么并且已经进行^ 异或运算,相同为0,相异为1,当找到ret比特位有为1的时候就证明a与b已经有分离的办法,将数组里面所有再该位比特位为1的存入a,为0的存入b,然后再将每个数字进行^异或 就能完美的将a 与 b进行分离。

总结一下吧~位运算刚开始听的时候确实很吃力,也很难,但是当上面结论用多了,确实也很简单,正所谓熟能生巧,我的进步很大,希望对你也是~

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

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

相关文章

解决使用阿里云DataV Geo在线地图路径访问403问题

文章目录 1. DataV Geo在线地图路径访问403问题2. 解决方法3. 重启生效 1. DataV Geo在线地图路径访问403问题 最近在写一个省市下钻的demo&#xff0c;用到的是 阿里云DataV Geo在线地图 去动态获取GeoJSON 省市的数据&#xff0c;如下代码 axios.get("https://geo.dat…

Ubuntu24.04 安装opencv4.10

Ubuntu24.04 安装opencv4.10 一、下载OpenCV二、更新系统&#xff0c;安装必要的包1、“E: unable to locate libjasper-dev"的解决方法2、没有公钥&#xff0c;无法验证下列签名 :NO_PUBKEY 的解决方法 三、配置&#xff0c;使用cmake工具1、新建build目录2、在build中&a…

计算机毕业设计 玩具租赁系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

智能 Uber 发票 PDF 合并工具

在现代商务出行中&#xff0c;尤其是在跨国出差中&#xff0c;处理和整合大量 Uber 发票已成为一项不小的挑战。手动整理和合并这些发票不仅耗时&#xff0c;还容易出错。作为开发者&#xff0c;为什么不开发一个自动化工具&#xff0c;将这些任务交给代码来完成呢&#xff1f;…

【AI学习笔记】初学机器学习西瓜书概要记录(一)机器学习基础知识篇

初学机器学习西瓜书的概要记录&#xff08;一&#xff09;机器学习基础知识篇(已完结) 初学机器学习西瓜书的概要记录&#xff08;二&#xff09;常用的机器学习方法篇(待更) 初学机器学习西瓜书的概要记录&#xff08;三&#xff09;进阶知识篇(待更) 文字公式撰写不易&#x…

基于代理的分布式身份管理方案

目的是使用分布式的联合计算分发去替换掉区块链中原有的类第三方可信中心的证书机制&#xff0c;更加去中心化。 GS-TBK Group Signatures with Time-bound Keys. CS-TBK 算法 Complete subtree With Time-bound Keys&#xff0c;该算法是用来辅助检测用户的签名是否有效&…

新手学习Python第十天-新手笔记(速学)

一、特殊方法和特殊属性 1.1 特殊属性 __dict__:获得类对象或实例对象所绑定的所有属性和方法的字典 1.2 特殊方法&#xff1a; 1.2.1 .__len__:通过重写__len__()方法&#xff0c;让内置函数len()的参数可以是自定义类型 长度 1.2.2 __add__():通过重写__add__()方法&…

ICMP

目录 1. 帧格式2. ICMPv4消息类型(Type = 0,Code = 0)回送应答 /(Type = 8,Code = 0)回送请求(Type = 3)目标不可达(Type = 5,Code = 1)重定向(Type = 11)ICMP超时(Type = 12)参数3. ICMPv6消息类型回见TCP/IP 对ICMP协议作介绍 ICMP(Internet Control Messag…

HTTP中的Cookie与Session

一、背景 HTTP协议是无状态无连接的。 无状态&#xff1a;服务器不会保存客户端历史请求记录&#xff0c;每一次请求都是全新的。 无连接&#xff1a;服务器应答后关闭连接&#xff0c;每次请求都是独立的。 无状态就导致服务器不认识每一个请求的客户端是否登陆过。 这时…

TCP并发服务器的实现

一请求一线程 问题 当客户端数量较多时&#xff0c;使用单独线程为每个客户端处理请求可能导致系统资源的消耗过大和性能瓶颈。 资源消耗&#xff1a; 线程创建和管理开销&#xff1a;每个线程都有其创建和销毁的开销&#xff0c;特别是在高并发环境中&#xff0c;这种开销…

计算机三级网络技术总结(一)

RPR环中每一个节点都执行SRP公平算法IEEE 802.11a和g将传输速率提高到54Mbps一个BGP发言人与其他自治系统中的BGP发言人要交换路由信息就要先建立TCP连接在一个区域内的路由器数一般不超过200个进入接口配置模式&#xff1a;Router(config)#interface <接口名> 封装ppp协…

CentOS上使用Mosquitto实现Mqtt主题消息发布和订阅mqtt主题消息连同时间戳记录到文件

场景 CentOS上使用rpm离线安装Mosquitto(Linux上Mqtt协议调试工具)附资源下载&#xff1a; CentOS上使用rpm离线安装Mosquitto(Linux上Mqtt协议调试工具)附资源下载-CSDN博客 上面介绍了mosquitto的离线安装。 如果业务场景中需要订阅某mqtt主题的消息并将收到消息的时间以…

婚礼弹幕上墙阳光正好,爱意正浓,打造一场出圈的唯美婚礼!

原文地址 婚礼现场的弹幕功能可以给整个场景增添温暖和喜庆的氛围。通过手机发送祝福&#xff0c;让亲友可以即时将祝福传达给新人&#xff0c;同时这些祝福以弹幕的形式在大屏幕上滚动展示&#xff0c;增加了现场互动的乐趣。墙上新闻搭配的功能则更加抢眼&#xff0c;不仅可…

idea插件推荐之Cool Request

Cool Request是一款基于IDEA的HTTP调试工具&#xff0c;可以看成是轻量版的postman&#xff0c;它会自动扫描项目代码中所有API路径&#xff0c;按项目分组管理。一个类被定义为Controller且其中的方法被RequestMapping或者XXXMapping注解标注以后就会被扫描到。 对应方法左侧会…

【C++二叉树】102.二叉树的层序遍历

107. 二叉树的层序遍历 II - 力扣&#xff08;LeetCode&#xff09; 思路分析&#xff1a; 层序遍历&#xff0c;但是要注意输出的结果是一个二维数组&#xff0c;不是一层一个值一个值的输出&#xff0c;而是要一层一层的输出。可以通过一个循环控制每一层的数据个数&#xff…

FastAdmin CMS 操作手册

FastAdmin CMS 操作手册 概述&#xff1a; 安装&#xff1a; 配置&#xff1a; 模板&#xff1a; 模板目录&#xff1a; 标签&#xff1a; 全局&#xff1a; 文章&#xff1a; 专题&#xff1a; 栏目&#xff1a; 公共参数&#xff1a; 单页&#xff1a; 特殊标签&#xff1a;…

python正则表达式如何不区分大小写

使用python的re模块做模式匹配时&#xff0c;有时需要忽略大小写&#xff0c;只需要在re.search()函数中添加参数re.IGNORECASE即可。 mystring some string pattern some pattern match re.search(pattern, mystring, re.IGNORECASE)

95、k8s之rancher可视化

一、ranker 图形化界面 图形化界面进行k8s集群的管理 rancher自带监控----普罗米修斯 [rootmaster01 opt]# docker load -i rancher.tar ##所有节点 [rootmaster01 opt]# docker pull rancher/rancher:v2.5.7 ##主节点[rootmaster01 opt]# vim /etc/docker/daemon.jso…

1.数据结构-双链表

一.双链表与单链表的对比&#xff1a; 二.双链表的初始化(带头结点)&#xff1a; 1.图解&#xff1a; 2.代码演示&#xff1a; #include<stdio.h> #include<stdlib.h> ​ //定义双链表结构体 typedef struct DNode {int data;struct DNode *prior;//前驱指针即指…

【Windows】使用 WMI 获取系统版本信息

目录 获取系统版本信息代码 获取系统版本信息 通过 RtlGetNtVersionNumbers 获取系统版本的方法可能不适用于所有情况&#xff0c;而且将要过时&#xff08;被废弃&#xff09;。下面介绍一种通过 WMI 查询并根据版本号进行划分的系统版本解析工具&#xff0c;其他方法还有通过…