【算法系列篇】位运算

news2024/12/26 10:34:58

在这里插入图片描述

文章目录

  • 前言
  • 什么是位运算算法
  • 1.判断字符是否唯一
    • 1.1 题目要求
    • 1.2 做题思路
    • 1.3 Java代码实现
  • 2. 丢失的数字
    • 2.1 题目要求
    • 2.2 做题思路
    • 2.3 Java代码实现
  • 3. 两数之和
    • 3.1 题目要求
    • 3.2 做题思路
    • 3.3 Java代码实现
  • 4. 只出现一次的数字
    • 4.1 题目要求
    • 4.2 做题思路
    • 4.3 Java代码实现
  • 5. 消失的两个数字
    • 5.1 题目要求
    • 5.2 做题思路
    • 5.3 Java代码实现
  • 总结

前言

位操作符想必大家都知道吧,&——按位与,|——按位或,^——按位异或,~——按位取法,位操作主要是用来操作二进制数的,就是因为它操作的是二进制,所以它的速度非常的快,那么既然他的速度很快,我们是否可以用位运算来解决一些实际问题呢?当然是可以的,这篇文章我将为大家分享如何使用位运算这种算法来解决一些问题。

什么是位运算算法

位运算算法是一组基于二进制位的操作符和操作方法的算法,用于在计算机中对二进制数字进行快速和高效的操作。位运算算法可以在二进制位级别上进行操作,包括位与(AND)、位或(OR)、位异或(XOR)、位取反(NOT)以及移位操作(左移和右移)等。

  • 按位与(&):只有当两个比特位都为1的时候结果才为1,否则为0
  • 按位或(|):两个比特位中有一个1,结果就为1
  • 按位异或(^):两个比特位相同为0,相异为1
  • 按位取反(~):除符号位之外,其它的比特位取反,为0结果为1,为1结果为0

位运算算法常用于以下情况:

  1. 位操作:可以通过位与、位或、位异或等运算符来对二进制数字的每一位进行操作,实现快速的位级别操作。
  2. 位掩码:可以使用位运算来创建和操作掩码,掩码经常用于标志位、权限控制和位字段的操作。
  3. 整数运算优化:位运算算法可以实现某些整数运算的高效实现,如乘以2的幂次方、除以2的幂次方、判断奇偶性等。
  4. 位图算法:位运算常用于位图算法,其中每个二进制位表示集合中的一个元素,可以进行高效的集合操作,如并集、交集、差集等。
  5. 压缩算法:位运算可以在压缩算法中起到重要的作用,用于压缩和解压缩数据,常见的例子包括哈夫曼编码和算术编码。

位运算算法通常具有高效性、简洁性和可移植性的特点,可以提供快速的底层操作,特别适合某些特定的问题和应用领域。在编写低级别的系统程序、嵌入式系统、网络协议和算法优化等方面,位运算算法发挥着重要的作用。

1.判断字符是否唯一

https://leetcode.cn/problems/is-unique-lcci/

1.1 题目要求

实现一个算法,确定一个字符串 s 的所有字符是否全都不同。

示例 1:

输入: s = "leetcode"
输出: false 

示例 2:

输入: s = "abc"
输出: true

限制:

  • 0 <= len(s) <= 100
  • s[i]仅包含小写字母
  • 如果你不使用额外的数据结构,会很加分。
class Solution {
    public boolean isUnique(String astr) {

    }
}

1.2 做题思路

通常判断唯一性的时候,我们首先想到的是哈希表,但是这里限制我们不适用额外的数据结构,我们虽然可以使用数组来模拟哈希表,但这都不是最优解,这道题最优的解法就是使用位图的思想。为什么会选择使用位图呢?因为题目中说明了:字符串中只包含小写字母,也就是无重复字符的字符串的长度最长为26,而一个整型0有4个字节,32个比特位,并且二进制的0和1则恰好可以标志某一字符有或者没有。

那么如何使用位图的思想来解决这个问题呢?我们可以将每一个字符所代表的ASCII码值来表示它在32个比特位中的位置,用循环来遍历字符串中的每一个字符,如果该字符在32个比特位中的对应位置是0的话,则用 | 运算,将该位置变为1,如果该位置为 1 的话,则说明出现了重复的字符。

1.3 Java代码实现

class Solution {
    public boolean isUnique(String astr) {
    //鸽巢原理,当字符串长度大于26的时候一定会有重复的字符
    if(astr.length() > 26) return fasle; 
        int tmp = 0; //tmp 代表32位比特位的位图
        for(int i = 0; i < astr.length(); i++) {
            char ch = astr.charAt(i);
            if(((tmp >> (ch - 'a')) & 1) == 1) return false;
            else tmp = tmp | (1 << (ch - 'a'));
        }

        return true;
    }
}

在这里插入图片描述

2. 丢失的数字

https://leetcode.cn/problems/missing-number/

2.1 题目要求

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,
因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,
因为它没有出现在 nums 中。

示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]
输出:8
解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,
因为它没有出现在 nums 中。

示例 4:

输入:nums = [0]
输出:1
解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,
因为它没有出现在 nums 中。

提示:

  • n == nums.length
  • 1 <= n <= 104
  • 0 <= nums[i] <= n
  • nums 中的所有数字都 独一无二
class Solution {
    public int missingNumber(int[] nums) {

    }
}

2.2 做题思路

这道题目的意思就是,原本数组中的元素应该是[0,数组长度],但是数组中缺少了一个数字,我们需要找到这个缺失的数字。这个题有很多种解法:

  1. 哈希表。
  2. 高斯求和。将原本数组中的元素的和减去现有数组所有元素的和就得到缺失的那个数字
  3. 排序。将数组进行排序,然后遍历数组找到缺失的那个数字
  4. 位运算

能用位运算解决就尽量用位运算来解决,因为位运算的速度非常快,那么这道题如何使用位运算来解决呢?在这之前,我们需要知道,^ 操作,当两个相同的数字进行异或操作的时候结果为0,那么我们可以将原本数组中元素和现有数组中的元素都进行异或操作,相同的两个数异或结果为0,到最后异或的结果就是我们要找的那个缺失的数字。

2.3 Java代码实现

class Solution {
    public int missingNumber(int[] nums) {
        int ret = 0;
        for(int n : nums) ret ^= n;
        for(int i = 0; i <= nums.length; i++) ret ^= i;

        return ret;
    }
}

在这里插入图片描述

3. 两数之和

https://leetcode.cn/problems/sum-of-two-integers/

3.1 题目要求

给你两个整数 a 和 b ,不使用 运算符 + 和 - ​​​​​​​,计算并返回两整数之和。

示例 1:

输入:a = 1, b = 2
输出:3

示例 2:

输入:a = 2, b = 3
输出:5

提示:

  • -1000 <= a, b <= 1000
class Solution {
    public int getSum(int a, int b) {

    }
}

3.2 做题思路

两数之和,大家一看到这个题目可能就会觉得很简单,直接 return a + b; 不就行了吗?但是仔细看题目,这道题不允许使用运算符 + 和 -,那么如何在不使用运算符的情况下实现两数之和呢?位运算,通过位运算就可以在不适用运算符的情况下实现两数之和的运算。

当我们进行二进制的加法的时候,当两个比特位相加的结果为2的时候,就需要向前进一位,但是我们可以先使用 ^ 操作来进行无进位的加法,当两个比特位相加的结果为2时,不进行进位而得到的结果,然后再使用 & 操作,来得到什么时候该进位,然后将 & 的结果向左移动一位,将上面的两个结果再循环进行上面的操作,直到 & 得到的结果为0的时候,就得到了两数之和的结果。

在这里插入图片描述

3.3 Java代码实现

class Solution {
    public int getSum(int a, int b) {
        while(b != 0) {
            int x = a ^ b;
            int y = a & b;
            a = x;
            b = y << 1;
        }

        return a;
    }
}

在这里插入图片描述

4. 只出现一次的数字

https://leetcode.cn/problems/single-number-ii/

4.1 题目要求

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

示例 1:

输入:nums = [2,2,3,2]
输出:3

示例 2:

输入:nums = [0,1,0,1,0,1,99]
输出:99

提示:

  • 1 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
class Solution {
    public int singleNumber(int[] nums) {

    }
}

4.2 做题思路

通过题目,我们可以知道,除了那个只出现了一次的数字之外,其他的数字都出现了一次,所以呢,我们可以将数组中的每个元素的32个比特位分别相加,将结果 % 3,就会得到那个只出现一次的数字的对应比特位。
在这里插入图片描述

4.3 Java代码实现

class Solution {
    public int singleNumber(int[] nums) {
        int ret = 0;
        for(int i = 0; i < 32; i++) {
            int tmp = 0;
            for(int n : nums) {
                tmp += (n >> i) & 1;
            }
            ret |= (tmp % 3) << i;
        }

        return ret;
    }
}

在这里插入图片描述

5. 消失的两个数字

https://leetcode.cn/problems/missing-two-lcci/

5.1 题目要求

给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?

以任意顺序返回这两个数字均可。

示例 1:

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

示例 2:

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

提示:

  • nums.length <= 30000
class Solution {
    public int[] missingTwo(int[] nums) {

    }
}

5.2 做题思路

这个题目跟上面的消失的一个数字其实是类似的,只不过这里出现了两个消失的数字,我们不可能一次就找到两个消失的数字,但是我们可以分两次找。可以将这道题目转换为数组中只出现了一次的数字,这里大家可以看看我之前写过的一篇文章寻找单身狗,但是呢一个数组中只能找到一个只出现了一次的数字,如果要想找到两个只出现了一次的数字,我们可以将这两个消失的数组分别给分到两个不同的数组中,然后在每一个数组中找那个只出现了一次的数字,最终这两个消失的数字都会被找到。那么,如何将这两个消失的数字分在两个不同的数组中呢?同样是将原本的数组和现有的数组中的所有元素都进行异或操作,相同的元素异或为0,最后剩下的其实就是这两个消失的数字异或的结果,然后我们需要在这个异或的结果中找到比特位为 1 的位置,因为异或,相异为 1 ,相同为0,当找到这个为 1 的比特位之后,就可以将这些元素进行分组了,该比特位为 1 的为一组,为 0 的为另一组。

在这里插入图片描述

5.3 Java代码实现

class Solution {
    public int[] missingTwo(int[] nums) {
        int[] ret = new int[2];
        int tmp = 0;
        for(int n : nums) tmp ^= n;
        for(int i = 1; i <= nums.length + 2; i++) tmp ^= i;
        int flg = 0; //用来记录异或结果比特位为1的位置
        for(int i = 0; i < 32; i++) {
            if(((tmp >> i) & 1) == 1) {
                flg = i;
                break;
            }
        }
        for(int n : nums) {
            if(((n >> flg) & 1) == 1) ret[0] ^= n;
            else ret[1] ^= n;
        }
        for(int i = 1; i <= nums.length + 2; i++) {
            if(((i >> flg) & 1) == 1) ret[0] ^= i;
            else ret[1] ^= i;
        }

        return ret;
    }
}

在这里插入图片描述

总结

通过本篇博客,我们深入了解了位运算算法及其在计算机领域中的重要性和应用。位运算算法是一项强大的工具,它基于二进制位的操作,能够高效地处理二进制数据,提升程序的性能和效率。

在实际应用中,我们可以利用位运算算法来实现各种位级别的操作,如位掩码、位操作、整数运算优化、位图算法和压缩算法等。这些算法和技巧可以在底层系统编程、嵌入式系统、网络协议和算法优化等领域发挥重要作用。

然而,在使用位运算算法时,也需要注意一些优化技巧和注意事项。我们需要注意位运算的优先级、位移操作的性能和溢出问题,以及如何利用位运算进行快速乘法、除法和判断奇偶性等操作。深入理解这些技巧,能够更好地应用位运算算法,提高代码的效率和准确性。

位运算算法是计算机科学中一个广泛应用的领域,通过深入学习和实践,我们可以进一步探索和发现更多有趣的位运算技巧和应用。在日常编程中,合理运用位运算算法,能够帮助我们解决一些复杂的问题,实现更高效和可靠的程序。

希望本篇博客能够为读者提供一个全面而清晰的位运算算法入门指南,让大家对位运算算法有更深入的了解,并能够应用于实际开发中。通过不断学习和探索,我们可以进一步提升自己的编程能力,并在算法领域中取得更多的成就。

感谢您的阅读,希望本篇博客对您有所帮助。如果您有任何问题或反馈,欢迎留言交流。祝愿您在位运算算法的学习和应用中取得成功!

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

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

相关文章

数据库范式以及drop、delete 与 truncate区别

数据库范式了解吗? 我们从一个数据库设计的初始化阶段开始, 但是并没有规范化设计的背景知识 而要求我们设计一个员工管理系统, 可能得到表结构如下: 数据异常 首先这个表有如下问题: 1. 数据冗余: 我们可以看到部门名称相同时, 部门地址也是重复的 因此会重复存储数据 …

【UE5】给模型指定面添加自定义材质

实现步骤 1. 首先我们向UE中导入一个简单的模型&#xff0c;可以看到目前该模型的材质插槽只有一个&#xff0c;当我们修改材质时会使得模型整体的材质全部改变&#xff0c;如果我们只想改变模型的某些面的材质就需要继续做后续操作。 2. 选择建模模式 3. 在模式工具栏中点击…

手机改图片文字软件有哪些?简单分享这几款

手机改图片文字软件有哪些&#xff1f;现在有很多手机APP可以帮助我们实现图片中文字的提取和修改&#xff0c;但是其中一些工具可能会缺乏一些必要的功能&#xff0c;或者不太适合某些特定的用途。在这篇文章中&#xff0c;我们将介绍几款非常实用的手机改图片文字软件。 第一…

复杂性管理与重复性管理

在前面我们说到了所谓的"计算机科学", 重点在于如何控制大型系统的复杂性. 复杂性本身当然也是个很大的话题, 而一种常见的复杂性的来源则是重复性, 即是由不断的重复所带来的复杂性. 重复性带来的复杂性常被人忽视, 大概是因为一开始它是不起眼的, 而当人们意识到它…

软技能的重要性:在面试中展示团队合作与沟通能力

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

2023年下半年西安/广州/深圳软考(中/高级)开班啦!!!

软考是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资格考试。 系统集成项…

​LeetCode解法汇总1448. 统计二叉树中好节点的数目

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给你一棵…

初识Java 3-1 控制流

目录 if-else语句 迭代语句 for循环 for-in语法 return break和continue 标签机制 switch 本笔记参考自&#xff1a; 《On Java 中文版》 Java不允许将数字作为布尔值使用&#xff0c;若需要在一些条件语句中使用一个非布尔值&#xff0c;比如if(a)&#xff0c;那么就需…

美团北极星榜单,服务零售的医美新样本

事实证明&#xff0c;任何时候&#xff0c;人们对美的追求都是刚需&#xff0c;只是有时候被压抑了。 德勤中国的《中国医美行业2023年度洞悉报告》&#xff08;以下简称“报告”&#xff09;显示&#xff0c;中国医美市场规模预计在2023年超过2000亿元&#xff0c;实现20%增速…

残差网络、Dropout正则化、Batch Normalization浅了解

残差网络&#xff1a; 为什么需要残差网络&#xff1a; 残差网络的目的是为了解决深度神经网络在训练过程中遇到的退化问题&#xff0c;即随着网络层数的增加&#xff0c;训练集的误差反而增大&#xff0c;而不是过拟合。残差网络的优点有以下几点&#xff1a; 残差网络可以…

上门服务系统|上门服务软件开发|上门服务改善生活质量的便捷之选

随着现代生活的快节奏和社交距离的需求&#xff0c;我们越来越渴望能够以更便捷、高效的方式获得我们所需的服务。为了满足这一需求&#xff0c;我们公司开发了一款创新的上门服务系统&#xff0c;旨在将便利与质量相结合&#xff0c;为您提供无与伦比的体验。 无论您是忙碌的白…

惠普NS1020激光打印机碳粉警告提示及添加碳粉方法

本文也适用于惠普NS1020、1020c 和 1020w 系列打印机。 通过碳粉量指示灯检查碳粉量。 如果碳粉量是满的或指示器显示 1&#xff0c;可选择添加一个碳粉或者忽略不添加。如果碳粉量指示灯显示 2或 2 和碳粉量警告感叹号图标 &#xff0c;则表示碳粉量不足或严重不足&#xff0…

ORACEL 账户被锁定、无监听

现象1&#xff1a;oracle数据库账号被锁定 OA页面情况&#xff1a;OA系统可以正常登录&#xff0c;但是表单查不出数据 PL SQL 连接情况&#xff1a;有明确的提示&#xff0c;oracle账号被锁。 Tomcat控制台情况&#xff1a;有明确提示账号被锁 解决办法 在命令行中输入就可…

批量身份证图片转Excel,核验真伪,保留头像,只需一款软件

你是否曾经遇到过需要将大量员工的身份证图片转化为Excel表格的情况&#xff1f;这种情况可能会让你感到无从下手。但是&#xff0c;现在有了金鸣表格文字识别电脑客户端&#xff0c;一切都将变得轻松便捷。 首先&#xff0c;你只需要前往金鸣识别官网下载并安装金鸣表格文字识…

企业网络设备监控工具

如今&#xff0c;组织在运营业务方面面临着日益激烈的竞争和日益复杂的问题&#xff0c;在这种情况下&#xff0c;拥有以最高效率运行的网络基础设施不再是奢侈品。相反&#xff0c;对于任何希望在各自领域成为领跑者的组织来说&#xff0c;这是必要的。网络基础设施中每个网络…

python爬虫14:总结

python爬虫14&#xff1a;总结 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产生不好…

查看edge浏览器插件的安装位置

C:\Users\zhang\AppData\Local\Microsoft\Edge\User Data\Default\Extensions 这是我的目录&#xff0c;把中间的的替换成你的电脑用户名就可以了 你也可以先输入目录的部分名称&#xff0c;下拉找对应的目录

docker部署前端项目保姆级教程

本地启动docker&#xff08;有不会启动的吗&#xff1f;下载docker&#xff08;小海豚&#xff09;双击起来就行&#xff09; 准备阿里云账号&#xff08;免费&#xff09; 没有就去注册一个&#xff0c;记住密码后面要用到 官网地址&#xff1a;阿里云登录 - 欢迎登录阿里云…

基于OpenCV+LPR模型端对端智能车牌识别——深度学习和目标检测算法应用(含Python+Andriod全部工程源码)+CCPD数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境OpenCV环境Android环境1. 开发软件和开发包2. JDK设置3. NDK设置 模块实现1. 数据预处理2. 模型训练1&#xff09;训练级联分类器2&#xff09;训练无分割车牌字符识别模型 3. APP构建1&#xff09;导入OpenCV库…

SAP_ABAP_OLE_EXCEL批导案例

SAP ABAP顾问能力模型梳理_企业数字化建设者的博客-CSDN博客SAP Abap顾问能力模型https://blog.csdn.net/java_zhong1990/article/details/132469977 一、OLE_EXCEL批导 1.1 下载按钮 1.2 选择EXCEL上传&#xff0c;解析EXCLE数据&#xff0c; Call屏幕。 1.3 实现效果 1.4…