算法-位运算基础

文章目录

    • 前置知识
    • 1. 交换两个数
    • 2. 比较两个数的大小
    • 3. leetcode268 寻找缺失的数字
    • 4. leetcode136 只出现一次的数字
    • 5. leetcode260 只出现一次的数字|||
    • 6. leetcode137 只出现一次的数字||
    • 7. 2/3的幂
    • 8. 大于等于该数字的最小2的幂
    • 9. leetcode201 数字范围按位与
    • 10. 位运算中分治法举例

前置知识

本节最重要的一个算法 Brain Kernighan算法
大致内容如下 :
如何提取出来一个数的最右侧的1
n = n & (~n + 1)
因为 (~n + 1) == -n
所以该算法也可以写成
n = n & (-n)

1. 交换两个数

因为我们的异或运算遵循的交换律和结合律, 所以我们可以写出下面的这一段代码

public void swap(int[] arr, int i, int j) {//注意这里的 i != jarr[i] = arr[i] ^ arr[j];arr[j] = arr[i] ^ arr[j];arr[i] = arr[i] ^ arr[j];}

请注意这里面的 i != j 因为如果相等的话, 会直接把这一块区域置为0

2. 比较两个数的大小

尝试不用任何的比较操作就比较出来两个数的大小关系, 我们写出来的代码如下

/*** 不包含比较相关的逻辑运算符来得到两个数当中的最大值*///flip意为反转 --> 此时传入的n保证为 1 / 0 --> 如果是1, 就转化为0 , 如果是0, 就转化为1private int flip(int n) {return n ^ 1;}//获取一下某个数字的符号,如果是非负的数字就返回一个1, 如果是负数就返回0private int sign(int n) {return flip(n >>> 31);}//下面我们给出两种判断的方法 --> 第一种有可能会溢出, 第二种不会溢出//核心的逻辑就是设置 returnA , returnB 来规定什么时候返回a, 什么时候返回b(两个return一定是互斥的才可以)public int getMax1(int a, int b) {//c可能会溢出int c = a - b;int returnA = sign(c);int returnB = flip(returnA);return a * returnA + b * returnB;}

解释一下我们的代码 :
sign方法是为了获取到某一个数的符号, 如果是非负数就返回1, 如果是负数就返回0, flip方法是为了把翻转数字,保证传入的数字一定是0或1, 其实这段代码的本质逻辑就是定义了两个returnA和returnB变量, 这两个变量一定是互斥的(一个1,一个0), 在必要的条件下就返回值
举例:
比如 a == 5, b == 3, c == 2, returnA为获取一下c的符号是非负也就是1, 那么returnB就是相反的0, 所以最后return的结果就是returnA * a == a
思考 : 上述代码是不是有问题呢?
其实, 当我们的c是有可能发生溢出的, 比如a = Integer.MAX_VALUE;
b = Integer.MIN_VALUE, 显然我们的c是溢出的, 所以我们的代码是有问题的, 我们的改动如下(flip和sign方法是不变的)

//下面的这个方法是不会溢出的public int getMax2(int a, int b) {//c依然可能会溢出int c = a - b;//下面判断一下a b c的符号int signA = sign(a);int signB = sign(b);int signC = sign(c);//判断a b 符号是不是相同的int diffAB = signA ^ signB; //不同返回1int sameAB = flip(diffAB); //相同返回1//什么时候进行a的返回 //--> 1. ab不同号且a为非负//--> 2. ab同号(此时不可能会溢出)且signC == 1int returnA = diffAB * signA + sameAB * signC;int returnB = flip(returnA);return a * returnA + b * returnB;}

上述的代码逻辑和之前的那个其实是一致的
就是加入了一些是否越界的判断(到底什么时候returnA)

3. leetcode268 寻找缺失的数字

在这里插入图片描述

前置知识
假设一堆数字异或的结果我们记为异或和 : ans
这一堆数字的部分数字的结果我们记作 : eor1
另一部分记作 : eor2
显然有 eor1 ^ eor2 = ans
两边同时 ^ eor1
可以得到 eor2 = ans ^ eor1
有了上面的结论的铺垫, 写这个题应该是十分的容易, 代码实现如下

class Solution {public int missingNumber(int[] nums) {//说白了这个题就是异或运算的性质int eor = 0;for(int elem : nums){eor ^= elem;}int eorN = 0;for(int i = 0; i <= nums.length; ++i){eorN ^= i;}return eorN ^eor;}
}

4. leetcode136 只出现一次的数字

在这里插入图片描述

这个问题可以抽象为下面的这个问题
给你一个数组, 其中一种数字出现了奇数次, 另外的数字都出现了偶数次
比较简单好想的思路是创建一个Set集合对元素进行去重操作(略)
这里我们用异或运算来写
思考 : 由于异或运算满足交换律, 不管多少个偶数个相同数字异或的结果一定是0
所以只要异或一轮就是那个结果, 代码实现如下

class Solution {public int singleNumber(int[] nums) {int eor = 0;for(int element : nums){eor = eor ^ element;}return eor;}
}

5. leetcode260 只出现一次的数字|||

在这里插入图片描述

该问题与上面的问题类似, 我们把该问题抽象出来就是, 给了一组数字, 其中有两个元素出现了奇数次, 其他的所有元素出现了偶数次, 求出来两个元素
思路分析 :
先把所有的元素异或起来得到一个异或和 eor , 该异或和的结果就是那两个数字(我们简介为m,n)
也就是 m ^ n == eor , 然后通过Brain Kernighan算法, 得到了最右侧的1, 因为我们的异或运算也可以等同于无进位相加, 所以这个1必定来源于m和n的其中一个, 所以我们定义一个eorN,让这个eorN只异或该位为1的数字, 得到的eorN就是m/n的其中一个,问题得解

class Solution {public int[] singleNumber(int[] nums) {int eor = 0;for(int elem : nums){eor ^= elem;}int n = eor & (~eor + 1);int eorN = 0;for(int elem : nums){if((elem & n) == 0){eorN ^= elem;}}return new int[]{eorN, eor ^ eorN};}
}

6. leetcode137 只出现一次的数字||

在这里插入图片描述

把该问题抽象出来, 就是一组数字, 其中一个数字出现次数小于m次, 其他的所有数字都出现了m次, 求出来这个数字是多少
思路分析 :
我们通过分位操作, 同意每一位上出现的1的个数, 遍历这个数组, 如果是hash[i] % m != 0, 就证明该数字这一位是1, 问题得解
代码实现如下

class Solution {public int singleNumber(int[] nums) {//首先进行的是统计每一个数位上的1的个数int[] hash = new int[32];for(int elem : nums){for(int i = 0; i < 32; ++i){hash[i] = hash[i] + ((elem >>> i) & 1);}}//统计1的分位个数完毕, 开始还原数字int ans = 0;for(int i = 0; i < 32; ++i){if(hash[i] % 3 != 0){ans = ans | (1 << i);}}return ans;}
}

7. 2/3的幂

给一个数判断是不是2的幂, 这个没什么可说的, 直接用Brain Kernighan算法

class Solution {/*** 判断一个数字是不是2的幂* @param n* @return*/public boolean isPowerOfTwo(int n){return n > 0 && (n & (~n + 1)) == n;}/*** 判断一个数字是不是3的幂(直接找到int范围内3的最大的幂是多少* @param n* @return*/public boolean isPowerOfThree(int n){return n > 0 && 1162261467 % n == 0;}}

8. 大于等于该数字的最小2的幂

已知n是非负数, 请返回大于等于n的最小的2的幂
思路分析 :
假如数字的二进制序列是 : …0010100110 , 那么此时大于等于该数的最小的2的幂就是最左侧1的一个位置
假如数字的二进制序列是 : …0001000000 , 那么此时大于等于该数的最小的2的幂就是该数本身
假设有一种方案可以把 最左侧的1后面的所有二进制位都刷成1 , 那么+1以后的结果就是答案
为什么要先进行 n-- , 是为了满足n正好是2的幂的情况
下面的几行代码的作用就是将最左侧的1的右面的二进制位全部刷成1
代码实现如下

class Solution{public int nearTwoPower(int n){if(n <= 1){return 1;}n--;n = n | (n >>> 1);n = n | (n >>> 2);n = n | (n >>> 4);n = n | (n >>> 8);n = n | (n >>> 16);return n + 1;}
}

9. leetcode201 数字范围按位与

在这里插入图片描述

暴力算法肯定是不可取的, 所以我们要采取更加好的算法
指定区间按位与(肯定是不能暴力解法)
思考 : 假设我们的left == right, 那么我们最终的与的结果就是left / right
如果 left != right, 那么此时我让right减小一点, 也就是(right - 1) & left
那么从 m ~ right的所有数字与起来的结果是不变的都是m, 因为前缀不变, 后缀全是0
循环下去, 直到 left >= right (中间的过程用的是Brain Kernighan算法)
代码实现如下

class Solution{public int rangeBitswiseAnd(int left,int right){while (left < right) {right = right - (right & (~right + 1));}return right;}
}

10. 位运算中分治法举例

我们给出来两道题, 第一道题就是逆序二进制数位, 第二道题就是汉明距离(统计二进制中的1的个数) , leetcode的题号 190 . 461
这个自己慢慢悟吧, 下面给出来代码实现(让我自己懂的)

class Solution{/*** 翻转二进制的状态* 比如一个数的二进制位是 : 0001101101010010 --reverse--> 010010101011000* 分析 : 正常的解法就是定义一个ans, 看到哪一位上有i你就或上去一个1就行了, 这里我们不在多说, 有点简单*       我们重点说一下位运算分治的思路(从两个一组翻转 --> 四个一组 --> 八个一组.....)*       假如有一个序列  a b c d e f g h*       我们翻转的过程: 1. b a d c f e h g (1v1翻转)*                    2. d c b a h g f e (2v2翻转)*                    3. h g f e d c b a (4v4翻转)*       下面推广到代码上 :*                   1. a b c d e f g h & 0 1 0 1 0 1 0 1  ==> 0 b 0 d 0 f 0 h (1)*                      a b c d e f g h & 1 0 1 0 1 0 1 0 ==>  a 0 c 0 e 0 g 0 (2)*                      (1) << 1 | (2) >>> 1  ==> b a d c f e h g*       下面的过程以此类推* @param n* @return*/public int reverseBits(int n){n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >>> 1);n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >>> 2);n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >>> 4);n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >>> 8);n = ((n & 0x0000ffff) << 16) | ((n & 0xffff0000) >>> 16);return n;}/*** 计算一个数字的二进制位中有几个1* 还是用的位运算分治的方法*   思路分析 : 假如数字的二进制位是  1 0 1 1 0 1 0 1** @param n* @return*/public int cntOnes(int n){n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);return n;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

effective java (1)(考虑使用!)静态工厂方法代替构造方法

只是目前阶段 对本书第一章内容的浅显认知&#xff0c;说实话 这一章 我看了4遍左右&#xff0c;每一遍感觉都不一样 他的创建模式 有时候像设计模式&#xff0c;但作者已经在原文中描述&#xff0c;它并不等价于 设计模式 我们正常 创建一个年级类 是长这样的 我们不写成标准…

C语言 for循环

for循环语句 //初始化 //判断 //调整 for&#xff08;表达式1; 表达式2; 表达式3;&#xff09;循环语句; 例&#xff1a; for循环里break for循环里continue 注&#xff1a;1.不可在for循环体内修改循环变量&#xff0c;防止for循环失去控制 2.建议for语句的循环控制变量的…

open-chat-video-editor:开源短视频生成和编辑工具,以及抖音|TikTok 的移动端短视频项目

open-chat-video-editor&#xff1a;开源短视频生成和编辑工具&#xff0c;以及抖音|TikTok 的移动端短视频项目。 open-chat-video-editor&#xff1a;开源短视频生成和编辑工具 简介 Open Chat Video Editor是开源的短视频生成和编辑工具&#xff0c;整体技术框架如下&…

简单科普-GPT到底是什么?

1.ChatGPT ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;是OpenAI研发的一款聊天机器人程序 &#xff0c;于2022年11月30日发布 。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够基于在预训练阶段所见…

[深度学习] Transformer

Transformer是一种深度学习模型&#xff0c;最早由Vaswani等人在2017年的论文《Attention is All You Need》中提出。它最初用于自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;但其架构的灵活性使其在许多其他领域也表现出色&#xff0c;如计算机视觉、时间序列分析…

HarmonyOS Next开发学习手册——选项卡 (Tabs)

当页面信息较多时&#xff0c;为了让用户能够聚焦于当前显示的内容&#xff0c;需要对页面内容进行分类&#xff0c;提高页面空间利用率。 Tabs 组件可以在一个页面内快速实现视图内容的切换&#xff0c;一方面提升查找信息的效率&#xff0c;另一方面精简用户单次获取到的信息…

Redis Stream Redisson Stream

目录 一、Redis Stream1.1 场景1&#xff1a;多个客户端可以同时接收到消息1.1.1 XADD - 向stream添加Entry&#xff08;发消息 &#xff09;1.1.2 XREAD - 从stream中读取Entry&#xff08;收消息&#xff09;1.1.3 XRANGE - 从stream指定区间读取Entry&#xff08;收消息&…

【王佩丰 Excel 基础教程】第一讲:认识Excel

文章目录 前言一、Excel软件简介1.1、历史上的其他数据处理软件与 Microsoft Excel1.2、Microsoft Excel 能做些什么1.3、Excel 界面介绍 二、Microsoft Excel 的一些重要概念2.1、Microsoft Excel 的几种常见文件类型2.2、工作簿、工作表、单元格. 三、使用小工具&#xff1a;…

SpringDataJPA系列(1)JPA概述

SpringDataJPA系列(1)JPA概述 SpringDataJPA似乎越来越流行了&#xff0c;我厂的mysql数据库和MongoDB数据库持久层都依赖了SpringDataJPA。为了更好的使用它&#xff0c;我们内部还对MongoDB的做了进一步的抽象和封装。为了查漏补缺&#xff0c;温故而知新&#xff0c;整理下…

基于自组织长短期记忆神经网络的时间序列预测(MATLAB)

LSTM是为了解决RNN 的梯度消失问题而诞生的特殊循环神经网络。该网络开发了一种异于普通神经元的节点结构&#xff0c;引入了3 个控制门的概念。该节点称为LSTM 单元。LSTM 神经网络避免了梯度消失的情况&#xff0c;能够记忆更长久的历史信息&#xff0c;更能有效地拟合长期时…

【面试系列】数据科学家 高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

[OtterCTF 2018]Name Game

Name Game 题目描述&#xff1a;我们知道这个帐号登录到了一个名为Lunar-3的频道。账户名是什么&#xff1f;猜想&#xff1a;既然登陆了游戏&#xff0c;我们尝试直接搜索镜像中的字符串 Lunar-3 。 直接搜索 Lunar-3 先把字符串 重定向到 txt文件里面去然后里面查找 Lunar-3…

使用 Spring Boot 3.x 与图形学技术,添加电子印章防伪特征

使用 Spring Boot 3.x 与图形学技术,添加电子印章防伪特征 在电子办公和无纸化办公日益普及的今天,电子印章的使用越来越广泛。然而,如何确保电子印章的安全性和防伪能力成为了一个亟待解决的问题。本文将通过 Spring Boot 3.x 和图形学技术,深入探讨如何为电子印章添加防…

Numpy array和Pytorch tensor的区别

1.Numpy array和Pytorch tensor的区别 笔记来源&#xff1a; 1.Comparison between Pytorch Tensor and Numpy Array 2.numpy.array 4.Tensors for Neural Networks, Clearly Explained!!! 5.What is a Tensor in Machine Learning? 1.1 Numpy Array Numpy array can only h…

IDEA中导入Maven项目

IDEA中导入Maven项目 方式1&#xff1a;使用Maven面板&#xff0c;快速导入项目 打开IDEA&#xff0c;选择右侧Maven面板&#xff0c;点击 号&#xff0c;选中对应项目的pom.xml文件&#xff0c;双击即可 说明&#xff1a;如果没有Maven面板&#xff0c;选择 View > Appe…

C#——SortedList 排序列表详情

SortedList 排序列表 SortedList 类用来表示键/值对的集合&#xff0c;这些键/值对按照键值进行排序&#xff0c;并且可以通过键或索引访问集合中的各个项。 我们可以将排序列表看作是数组和哈希表的组合&#xff0c;其中包含了可以使用键或索引访问各项的列表。如果您使用索…

为什么word生成的PDF内容显示不全?

在现代办公环境中&#xff0c;将文档从一个格式转换为另一个格式是一个常见的任务。然而&#xff0c;有时候我们可能会遇到意想不到的问题&#xff0c;比如使用Word转换成PDF时&#xff0c;生成的PDF文件只显示了整个界面的四分之一内容。这种问题不仅令人困扰&#xff0c;也可…

如何自己录制教学视频?零基础也能上手

随着在线教育的蓬勃发展&#xff0c;录制教学视频成为了教师和教育工作者们不可或缺的一项技能。无论是为了远程教学、课程分享还是知识普及&#xff0c;教学视频的录制都变得愈发重要。可是如何自己录制教学视频呢&#xff1f;本文将介绍两种录制教学视频的方法&#xff0c;这…

pg_rman:备份和恢复管理工具#postgresql培训

pg_rman 是 PostgreSQL 的在线备份和恢复工具。 pg_rman 项目的目标是提供一种与 pg_dump 一样简单的在线备份和 PITR 方法。此外&#xff0c;它还为每个数据库集群维护一个备份目录。用户只需一个命令即可维护包括存档日志在内的旧备份。 #PG培训#PG考试#postgresql考试#pos…

[OtterCTF 2018]Bit 4 Bit

我们已经发现这个恶意软件是一个勒索软件。查找攻击者的比特币地址。** 勒索软件总喜欢把勒索标志丢在显眼的地方&#xff0c;所以搜索桌面的记录 volatility.exe -f .\OtterCTF.vmem --profileWin7SP1x64 filescan | Select-String “Desktop” 0x000000007d660500 2 0 -W-r-…