算法通关村第十一关——位运算实现加减乘除

在计算机中,位运算的效率比加减乘除效率更高。

1.位运算实现加法

力扣371题, 给你两个整数 ab ,不使用 运算符 + -,计算并返回两整数之和。

分析:不让用运算符,就只能使用位运算。先来看一下两位二进制相加的情况:

0 + 0 = 0
0 + 1 = 0
1 + 0 = 0
1 + 1 = 1 (此处发生了进位,结果应该为 10,可以用 1 << 1 来表示)

两数相加时,我们需要考虑的是进位部分的结果和不进位部分的结果。由上面的例子可以知道,对于ab两个数不进位部分的情况是:相同为0,不相同为1,也就是a ⊕ b。对于进位,其结果就是a & b也就是两位只有都是1的时候才会进位,进位发生的时候数的位数就变成两位了,我们只需要将其左移一位即可,也就是(a & b) << 1。综上得出两条结论:

  1. 不进位部分,计算就是a ⊕ b
  2. 对于进位部分,就是(a & b) << 1

代码如下:

function getSum(a, b) {while (b !== 0) {// 进位处运算就是 a & b。如果进位了,就左移一位let sign = (a & b) << 1;// 不进位处按异或进行位运算a = a ^ b;b = sign;}return a;
}

2.位运算实现乘法

力扣面试题08.05,递归乘法。 写一个递归函数,不使用*运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。

加入两个正整数分别是A B

分析:

  1. 首先,检查基本情况:如果乘数 B 等于0,那么乘积一定为0,所以返回0。
  2. 接下来,判断乘数 B 的二进制最低位是否为1(奇数检查),可以使用位运算 B & 1 来判断。如果最低位为1,说明 B 是奇数,进入第3步,否则进入第4步。
  3. 如果 B 是奇数,先将 A 加到结果中,然后通过递归计算 A * (B >> 1),这里的 B >> 1 表示将 B 右移一位,相当于除以2。递归结果再左移一位,相当于乘以2,然后将两者相加,即 A + (A * (B >> 1) * 2)
  4. 如果 B 是偶数,直接通过递归计算 A * (B >> 1),然后结果左移一位,即 A * (B >> 1) * 2

代码如下:

/*** 递归乘法:计算两个数的乘积* @param {number} A* @param {number} B* @return {number}*/
var multiply = function(A, B) {// 如果B为0,任何数乘以0都为0if (B === 0) {return 0;}// 检查B的二进制最低位是否都为1(奇数检查)if ((B & 1) === 1) {// 如果B是奇数,将A加到结果中,然后将A 乘以(B >> 1)的结果加倍return A + (multiply(A, B >> 1) << 1);} else {// 如果B是偶数,将A乘以(B >> 1)的结果加倍return multiply(A, B >> 1) << 1;}
};

3.位运算实现除法

力扣29题,给你两个整数,被除数 dividend 和除数 divisor(!== 0)。将两数相除,要求 不使用 乘法、除法和取余运算。

整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8-2.7335 将被截断至 -2

返回被除数 dividend 除以除数 divisor 得到的

**注意:**假设我们的环境只能存储 32 位 有符号整数,其数值范围是$ [−2^{31}, 2^{31} − 1]$。本题中,如果商 严格大于 2 31 − 1 2^{31} − 1 2311 ,则返回 2 31 − 1 2^{31} − 1 2311;如果商 严格小于 − 2 31 -2^{31} 231 ,则返回 − 2 31 -2^{31} 231

分析:这道题有些复杂,细节比较多。刚开始我们最先想到的就是用循环减法,但是这样被除数一变大效率就太低。

首先对于溢出或者容易出错的边界情况进行讨论:

  • 当被除数为32位有符号整数的最小值 − 2 31 -2^{31} 231时:
    • 如果除数为1,直接返回 − 2 31 -2^{31} 231
    • 如果除数为-1,得到的是 2 31 2^{31} 231,会产生溢出,此时需要返回 2 31 − 1 2^{31}-1 2311
  • 当除数为32位有符号整数的最小值 − 2 31 -2^{31} 231时:
    • 如果被除数同样为 − 2 31 -2^{31} 231,直接返回1;
    • 对于其余的情况,返回0。
  • 如果被除数为0,返回0。

对于一般的情况,被除数和除数符号有可能不同,这样就会有4种情况,不便于编码。为了方便编码我们可以采取对被除数和除数取相反数的方法以统一符号,这样就只需要考虑一种情况。

为了防止正整数出现溢出的情况,把符号都统一为负数,在返回答案时也需要取相反数。

使用二分查找来解决,同样需要注意边界问题。被除数x和除数y都是负数,那么他们的商z就是正数,根据除法及余数的定义,可以将其改成乘法的等价形式: z ∗ y > = x > = ( z + 1 ) ∗ y z * y >= x >= (z + 1) * y zy>=x>=(z+1)y,

由于不让用除法就需要用到快速乘方法,本质上就是加法运算。由于较大的z也会导致加法运算溢出,例如判断A + B < C,由于都为负数,A + B可能会产生溢出,所以必须判断A < C - B是否成立。由于任意两个负数的差一定在 [ − 2 31 + 1 , 2 31 − 1 ] [-2^{31} + 1, 2^{31} - 1] [231+1,2311]范围内,这样就不会产生溢出:

完整代码如下:

function divide(divided, divisor) {const MAX_VALUE = 2**31 - 1;const MIN_VALUE = -(2**31);// 考虑被除数为最小值的情况if (divided === MIN_VALUE) {if (divisor === 1) {return MIN_VALUE;} else if (divisor === -1) {return MAX_VALUE;}}// 考虑除数为最小值的情况if (divisor === MIN_VALUE) {return divided === MIN_VALUE10;}// 考虑被除数为0的情况if (divided === 0) {return 0;}// 一般情况,使用二分查找// 将所有的正数取相反数,这样就只考虑一种情况let reversed = false;	// 标记是否取了相反数if (divided > 0) {divided = -divided;reversed = !reversed;}if (divisor > 0) {divisor = -divisor;reversed = !reversed;}let left = 0, right = MAX_VALUE, ans = 0;while (left <= right) {mid = left + ((right - left) >> 1);const check = quickAdd(divisor, mid, divided);if (check) {ans = mid;if (mid === MAX_VALUE) {break;}left = mid + 1;} else {rihgt = mid - 1;}}return reversed ? -ans : ans;
}/*** 快速乘* @params y* @params z* @params x* * */
// z * y >= x >= (z + 1) * y  (x和y为负数,z是正数)
function quickAdd(y, z, x) {// 需要判断 z * y >= x 是否成立let result = 0, add = y;while (z !== 0) {if ((z & 1) !== 0) {// 需要保证 result + add >= xif (result < x - add) {return false;}add += add;}if (z !== 1) {// 需要保证 add + add >= x,即两数之和大于等于第三个数,防止加法运算溢出if (add < x - add) {return false;}add += add;}// 不能使用除法,就用右移位运算z >>= 1;}return true;
}

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

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

相关文章

【面试经典150题】删除有序数组中的重复项Ⅱ JavaScript

题目来源。 给你一个有序数组 nums &#xff0c;请你** 原地** 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下…

程序自动分析——并查集+离散化

在实现程序自动分析的过程中&#xff0c;常常需要判定一些约束条件是否能被同时满足。考虑一个约束满足问题的简化版本&#xff1a;假设 x1,x2,x3,… 代表程序中出现的变量&#xff0c;给定 n 个形如 xixj 或 xi≠xj 的变量相等/不等的约束条件&#xff0c;请判定是否可以分别为…

Matlab 生成一定信噪比的信号

文章目录 【 1. 信噪比 】【 2. 功率归一化 】2.1 实信号+实噪声2.2 实信号+复噪声【 3. 能量归一化 】3.1 实信号+实噪声3.2 实信号+复噪声【 4. 小结 】【 1. 信噪比 】 信噪比公式 1 : S N R = 10 ∗ l o g 10 P s P n 信噪比公式1:SNR=10*log_{10}\frac{P_s}{P_n} 信噪比…

webrtc的Sdp中的Plan-b和UnifiedPlan

在一些类似于视频会议场景下&#xff0c;媒体会话参与者需要接收或者发送多个流&#xff0c;例如一个源端&#xff0c;同时发送多个左右音轨的音频&#xff0c;或者多个摄像头的视频流&#xff1b;在2013年&#xff0c;提出了2个不同的SDP IETF草案Plan B和Unified Plan&#x…

【uniapp 上传图片示例】

以下是 uniapp 上传图片的详细步骤示例&#xff1a; 定义一个方法&#xff0c;用于选择图片并上传&#xff1a; methods: {chooseImage() {uni.chooseImage({count: 1, // 最多选择的图片数量sizeType: [original, compressed], // 可以指定原图或压缩图sourceType: [album, …

android framework之Applicataion启动流程分析

Application启动流程分析 启动方式一&#xff1a;通过Launcher启动app 启动方式二&#xff1a;在某一个app里启动第二个app的Activity. 以上两种方式均可触发app进程的启动。但无论哪种方式&#xff0c;最终通过通过调用AMS的startActivity()来启动application的。 根据上图…

ABeam×Startup | 德硕管理咨询(深圳)创新研究团队拜访微漾创客空间

近日&#xff0c;德硕管理咨询&#xff08;深圳&#xff09;&#xff08;以下简称&#xff1a;“ABeam-SZ”&#xff09;创新研究团队前往微漾创客空间&#xff08;以下简称&#xff1a;微漾&#xff09;拜访参观&#xff0c;并展开合作交流。会议上&#xff0c;双方相互介绍了…

每日一题 57. 插入区间

读研了&#xff0c;开始用python刷题 今天的题目是力扣 每日一题 57. 插入区间 难度&#xff1a;中等 思路&#xff1a; 处理新区间起点&#xff0c;要么在两个老区间之间&#xff0c;要么被一个老区间包含处理新区间中点&#xff0c;同起点一样 我的代码如下 class Solut…

解锁市场进入成功:GTM 策略和即用型示例

在最初的几年里&#xff0c;创办一家初创公司可能会充满挑战。根据美国小企业管理局的数据&#xff0c;大约三分之二的新成立企业存活了两年&#xff0c;几乎一半的企业存活了五年以上。导致创业失败的因素有市场需求缺失、资金短缺、团队不合适、成本问题等。由此&#xff0c;…

合宙Air724UG LuatOS-Air LVGL API控件--按钮 (Button)

按钮 (Button) 按钮控件&#xff0c;这个就不用多说了&#xff0c;界面的基础控件之一。 示例代码 – 按键回调函数 event_handler function(obj, event) if event lvgl.EVENT_CLICKED then print(“Clicked\n”) elseif event lvgl.EVENT_VALUE_CHANGED then print(“To…

服务器数据库中了locked勒索病毒怎么办,locked勒索病毒恢复工具

最近一段时间网络上的locked勒索病毒非常嚣张&#xff0c;自从6月份以来&#xff0c;很多企业的计算机服务器数据库遭到了locked勒索病毒的攻击&#xff0c;起初locked勒索病毒攻击用友畅捷通T用户&#xff0c;后来七月份开始攻击金蝶云星空客户&#xff0c;导致企业的财务系统…

揭秘视频号创收计划:松松一个月赚1300+

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 这是卢松松一个月视频号的收益&#xff0c;1300元。自从视频号在五月份推出创作者分成计划以来&#xff0c;许许多多的视频号创作者开始获得了一些收益&#xff0c;这绝对是一项挺不错的进展。 目前…

算法通关村第十六关——滑动窗口与堆结合

LeetCode239给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位&#xff0c;返回滑动窗口中的最大值。 输入&#xff1a;nums[1,3,-1,-3,5,3,6,7],k3 输出&#xff1a;[3,3,5,5,…

Pytorch模型转ONNX模型并使用ONNXRuntime运行

Pytorch模型转ONNX模型 import torch import torch.nn as nn from backbone import OXI_Netmodel OXI_Net() # 实例化模型对象 model.load_state_dict(torch.load(./cnn_model_50.pth)) # 加载模型 model.eval() # 推理模式input_names [image] # 输入名称 output_names…

R-Meta分析核心技术教程

详情点击链接&#xff1a;全流程R-Meta分析核心技术教程 一&#xff0c;Meta分析的选题与检索 1、Meta分析的选题与文献检索 1)什么是Meta分析 2)Meta分析的选题策略 3)精确检索策略&#xff0c;如何检索全、检索准 4)文献的管理与清洗&#xff0c;如何制定文献纳入排除标准 …

回归预测 | MATLAB实现TSO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现TSO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现TSO-ELM金枪鱼群优化算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效…

【大数据】Linkis:打通上层应用与底层计算引擎的数据中间件

Linkis&#xff1a;打通上层应用与底层计算引擎的数据中间件 1.引言2.背景3.设计初衷4.技术架构5.业务架构6.处理流程7.如何支撑高并发8.用户级隔离度和调度时效性9.总结 Linkis 是微众银行开源的一款 数据中间件&#xff0c;用于解决前台各种工具、应用&#xff0c;和后台各种…

proxysql使用心得

proxySQL 多层配置系统结构 -------------------------| RUNTIME |-------------------------/|\ || |[1] | [2] || \|/-------------------------| MEMORY |------------------------- _/|\ | …

无锁并发:探秘CAS机制的魔力

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; 无锁并发&#xff1a;探秘CAS机制的魔力 ⏱️ 创作时间&#xff1a; 2…

this.viewer.entities.removeById()循环删除为什么删除不完

在 Cesium 中&#xff0c;viewer.entities.removeById() 方法用于从场景中移除指定 ID 的实体。如果您在循环中使用这个方法来删除多个实体&#xff0c;有可能会出现删除不完全的问题&#xff0c;这是因为在删除实体的同时&#xff0c;实体数组的长度在不断减小&#xff0c;可能…