像考研一样学个宇宙之刷题篇:剑指offerⅡ:整数系列——整数除法0706 TODO

news2024/10/7 4:35:51

001. 整数除法:

给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 ‘*’、除号 ‘/’ 以及求余符号 ‘%’ 。

在这里插入图片描述

一些知识点和思路

第一题,easy题,狠狠来了个下马威。

  • 首先是 “被除数/除数”
  • 关于溢出的情况,可以对除数与被除数分别按照他们的临界值进行考虑
    在这里插入图片描述
  • 快速乘原理基于二进制的特性
    在这里插入图片描述

关于快速乘中位操作的一些知识点

快速乘的代码

auto quickAdd = [](int y, int z, int x) {
            // x 和 y 是负数,z 是正数
            // 需要判断 z * y >= x 是否成立
            int result = 0, add = y;
            while (z) 
			{
                if (z & 1) 
				{
                    // 需要保证 result + add >= x
                    if (result < x - add) {
                        return false;
                    }
                    result += add;
                }
                if (z != 1) 
				{
                    // 需要保证 add + add >= x
                    if (add < x - add) {
                        return false;
                    }
                    add += add;
                }
                // 不能使用除法
                z >>= 1;
            }
            return true;
        };

变量result和add

在这段代码中,result和add变量的含义如下:

result:表示乘法的结果,即最终计算得到的乘积。
add:表示乘法中的一个因子,用于将其加入到最终的结果中。

在快速乘法算法中,通过不断将add乘以2,并根据z的二进制表示中的每一位判断是否需要将add加入到result中。
当z的某一位为1时,表示需要将add加入到result中;当z的某一位为0时,不需要加入。

在循环中,根据z的最低位判断是否需要将add加入到result中。
如果需要加入,则先判断result + add是否小于x,如果是,则返回false,表示乘法运算失败。
然后将add加入到result中,即result += add。

接下来,判断z是否等于1,如果不等于1,则需要将add乘以2。
在乘法之前,先判断add + add是否小于x,如果是,则返回false,表示乘法运算失败。
然后将add更新为add + add。

最后,将z右移1位,相当于将二进制表示中的最低位去掉,继续下一轮循环。

通过这样的循环和判断,可以实现快速乘法运算,并且避免了溢出的问题。

一个整数&1表示什么:表示最低一位,一般表示奇偶性

在这里插入图片描述

一个整数右移1位代表什么:相当于除以2,右移位数相当于除以2的指定次数

在这里插入图片描述

同理左移相当于乘以2的指定次数

在这里插入图片描述

为什么要判断z的最低位是否为1和是否等于1

判断z的最低位是否为1和是否等于1的目的是为了确定乘法运算的次数和乘法的基数。

在快速乘法算法中,我们将z表示为二进制形式,
从最低位开始,每一位代表了乘法中的一个因子。
如果某一位为1,表示需要将对应的因子加入到最终的结果中;
如果某一位为0,表示不需要将对应的因子加入到结果中。
因此,判断z的最低位是否为1,可以确定是否需要将add加入到result中。
如果最低位为1,则需要加入;如果最低位为0,则不需要加入。

而判断z是否等于1,可以确定是否还有其他位需要进行乘法运算。
如果z等于1,说明已经处理完了所有的位,不需要再进行乘法运算;
如果z不等于1,说明还有其他位需要处理,需要将add乘以2。

这样,通过判断z的最低位和是否等于1,可以在循环中正确地进行乘法运算,避免了不必要的计算和溢出的问题。

一些快速乘的具体示例

当我们具体代入数值来理解快速乘法的工作原理时,可以考虑以下示例:

假设我们要计算 z * y 是否大于等于 x,其中 z = 5,y = -3,x = -14。

我们可以使用快速乘法来判断 z * y 是否大于等于 x,具体的代码如下:

#include <iostream>

bool quickMultiply(int z, int y, int x) {
    int result = 0, add = y;
    while (z) {
        if (z & 1) {
            if (result < x - add) {
                return false;
            }
            result += add;
        }
        if (z != 1) {
            if (add < x - add) {
                return false;
            }
            add += add;
        }
        z >>= 1;
    }
    return true;
}

int main() {
    int z = 5, y = -3, x = -14;
    bool result = quickMultiply(z, y, x);
    std::cout << "Is " << z << " * " << y << " >= " << x << "? " << std::boolalpha << result << std::endl;
    return 0;
}

在这个示例中,我们使用 quickMultiply 函数来判断 z * y 是否大于等于 x。根据快速乘法的原理,我们会在循环中根据 z 的二进制表示的每一位来判断是否需要将 add 加入到 result 中。

具体的计算过程如下:

初始时,result = 0,add = -3。
第一轮循环,z = 5,z & 1 = 1,表示需要将 add 加入到 result 中。
    result + add = 0 + (-3) = -3。
    result < x - add 不成立,继续执行。
    result += add,此时 result = -3。
第二轮循环,z = 2,z & 1 = 0,表示不需要将 add 加入到 result 中。
    add + add = -3 + (-3) = -6。
    add < x - add 不成立,继续执行。
    add += add,此时 add = -6。
第三轮循环,z = 1,z & 1 = 1,表示需要将 add 加入到 result 中。
    result + add = -3 + (-6) = -9。
    result < x - add 不成立,继续执行。
    result += add,此时 result = -9。
第四轮循环,z = 0,循环结束。

最终,result = -9。由于 -9 不大于等于 -14,所以 z * y 不大于等于 x。

因此,程序输出结果为:Is 5 * -3 >= -14? false。

通过这个具体的例子,我们可以更直观地理解快速乘法函数的作用,即判断两个数的乘积是否大于等于给定的数。

官方答案

class Solution {
public:
    int divide(int a, int b) {
        // 考虑被除数为最小值的情况
        if (a == INT_MIN) {
            if (b == 1) {
                return INT_MIN;
            }
            if (b == -1) {
                return INT_MAX;
            }
        }
        // 考虑除数为最小值的情况
        if (b == INT_MIN) {
            return a == INT_MIN ? 1 : 0;
        }
        // 考虑被除数为 0 的情况
        if (a == 0) {
            return 0;
        }
        
        // 一般情况,使用二分查找
        // 将所有的正数取相反数,这样就只需要考虑一种情况
        bool rev = false;
        if (a > 0) {
            a = -a;
            rev = !rev;
        }
        if (b > 0) {
            b = -b;
            rev = !rev;
        }

        // 快速乘
        auto quickAdd = [](int y, int z, int x) {
            // x 和 y 是负数,z 是正数
            // 需要判断 z * y >= x 是否成立
            int result = 0, add = y;
            while (z) 
			{
                if (z & 1) 
				{
                    // 需要保证 result + add >= x
                    if (result < x - add) {
                        return false;
                    }
                    result += add;
                }
                if (z != 1) 
				{
                    // 需要保证 add + add >= x
                    if (add < x - add) {
                        return false;
                    }
                    add += add;
                }
                // 不能使用除法
                z >>= 1;
            }
            return true;
        };
        
        int left = 1, right = INT_MAX, ans = 0;
        while (left <= right) 
		{
            // 注意溢出,并且不能使用除法
            int mid = left + ((right - left) >> 1);
            bool check = quickAdd(b, mid, a);
            if (check) 
			{
                ans = mid;
                // 注意溢出
                if (mid == INT_MAX) {
                    break;
                }
                left = mid + 1;
            }
            else {
                right = mid - 1;
            }
        }

        return rev ? -ans : ans;
    }
};

当前的一些疑问:

快乘法是用来判断当前y*z是否大于等于x的,那如果当前的值不是即false,不是表示当前值小,正确的应该在右边,则应该是left = mid + 1;当返回true的时候表示大了,应该right = mid - 1;吗,不理解,整体都不是太理解,但是知道了一些位运算的操作,不要让第一题耽搁太久,留着等有更多基础再重做

更新 终于理解了

class Solution {
public:
    int divide(int dividend, int divisor) {
        //会溢出的情况
        if(dividend == INT_MIN && divisor == -1)
        {
            return INT_MAX;
        }
        // 特殊情况,无需计算,直接返回
        if (dividend == 0 || divisor == 1) {
            return dividend;
        } else if (divisor == -1) {
            return -dividend;
        }

        // 由于(-2^31) 转换为正数会溢出,但是任意正数转换为负数都不会溢出
        // 故,记录负数的个数,并将正数转换为负数方便统一计算
        int negative = 0;
        if(dividend > 0)
        {
            dividend = -dividend;
            negative++;
        }
        if(divisor > 0)
        {
            divisor = -divisor;
            negative++;
        }

        //开始用位运算找被除数中有几个除数 首先找到一个最大的shiftshift 比如 61 /3 那首先61-3*2^4=61-48。但3*2^5 = 96 所以maxshift = 4 
        //然后剩下的61-48=13。13里再去找有几个2 
        int res = findAllShift(dividend, divisor);
        return negative == 1?-res:res;
    }

    int findAllShift(int dividend, int divisor)
    {
        int res = 0;
        //找到最大的shift
        int shift = 0;
        //注意这里的除数和被除数都是负数 要不我给换回来吧 求shift不是都一样的嘛 -64 -3
        int temp = divisor;
        while(temp > dividend)
        {
            temp <<= 1;//这相当于 -3 * 2^1
            shift++;
        }
        //得到shift 开始从shift往下找
        while(dividend <= divisor)
        {
            //dividend一直会右移变小
            while(dividend > (divisor << shift))
            {
                shift--;
            }
            dividend -= divisor<<shift;
            res += (1 << shift);
        }
        return res;
    }

};

在这里插入图片描述

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

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

相关文章

| 交互式建模与学习:重建人类运动功能

在报告《交互式建模与学习&#xff1a;重建人类运动功能》中&#xff0c;清华大学副教授眭亚楠介绍了AI在重建人类运动功能时&#xff0c;从无模型学习&#xff08;model-free learning&#xff09;到基于模型学习&#xff08;model-based learning&#xff09;的转变&#xff…

剑指 Offer II . 删除链表的倒数第 n 个结点

给定一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#x…

【MySQL入门实战5】-Linux PRM 包安装MySQL

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61…

【QT】QCustomPlot开发笔记

QCustomPlot开发 01、QCustomPlot简介1.1 帮助文档1.2 下载&使用 02、QCustomPlot项目使用笔记2.1 创建QCustomPlot 03、源代码 01、QCustomPlot简介 QCustomPlot 是一个用于科学绘图的 QT 第三方库&#xff0c;可以用于常见的二维图像绘制&#xff0c;比如函数曲线、参数…

管理类联考——择校——学费

截止2023年06月&#xff0c;关于广东的管理类联考的xuefei。 借鉴&#xff1a;https://zhuanlan.zhihu.com/p/421296334。罗列985相关院校 广州以本土MBA为主&#xff0c;共有9家院校&#xff1b; 深圳以外地MBA为主&#xff0c;有超过20家院校。 一梯队&#xff1a;北大光华…

日志---spdlog

spdlog中各对象都分为多线程与单线程版本&#xff1a; *_st&#xff1a;单线程版本&#xff0c;不用加锁&#xff0c;效率更高。*_mt&#xff1a;多线程版本&#xff0c;用于多线程程序是线程安全的。 spdlog是基于C11实现的一款纯头文件的日志管理库 git地址&#xff1a;htt…

WSI-finetuning

一、贡献 (1)通过引入一个IB模块来提出WSI-MIL的简单代理任务&#xff0c;该模块将包中超过10k个冗余实例提炼成不到1k个最受支持的实例。因此&#xff0c;在千兆像素图像上进行基于梯度的训练的并行计算成本减轻了十倍以上。通过对简化袋的学习和分类&#xff0c;发现由于病理…

【自学笔记】在SQL Server中创建用户角色及授权(使用SQL语句)更新2023.07.06

--<在SQL Server中创建用户角色及授权(使用SQL语句)>更新2023.07.06 --1. 首先在 SQL Server 服务器级别&#xff0c;创建登陆帐户&#xff08;create login&#xff09; --2. 创建数据库用户&#xff08;create user&#xff09;&#xff1a; --3. 通过加入数据库角色&a…

不忘初心,筑梦未来 | 【2023 ACDU 中国行·深圳站】数据库主题交流活动成功举办!

6月30日下午&#xff0c;【ACDU 中国行深圳站】在深圳回酒店圆满落下帷幕。本次活动由中国数据库联盟&#xff08;ACDU&#xff09;联合墨天轮社区主办&#xff0c;围绕「数据库前沿技术揭秘及应用」这一主题&#xff0c;七位数据库行业的领军人物从数据库新特性解读、创新与应…

Docker集群部署-redis集群

学习要求 利用Docker实现redis 集群的部署&#xff0c;实现3主3从集群配置&#xff0c;并在此基础上实现主从扩容、缩容。 学习准备 要求实验主机能够连接外网&#xff0c;已经正确安装Docker&#xff0c;并关闭防火墙和selinux。 学习步骤 创建6个docker容器实例&#xf…

OpenFeign 源码分析

&#xff08;学习别人的思想&#xff0c;可以找 bug&#xff0c;优化你的代码&#xff0c;提高代码的健壮性&#xff09;看源码之前要先大致猜想一下 他是怎么实现的&#xff1f;&#xff08;先使用在分析&#xff09; 5.1 OpenFeign 的原理是什么&#xff1f; 根据前文的案例…

3DCAT实时云渲染助力VR虚拟现实迈向成熟

近年来&#xff0c;虚拟现实&#xff08;Virtual Reality, VR&#xff09;技术在市场上的应用越来越广泛&#xff0c;虚拟现实已成为一个热门的科技话题。相关数据显示&#xff0c;2019年至2021年&#xff0c;我国虚拟现实市场规模不断扩大&#xff0c;从2019年的282.8亿元增长…

uniapp开发的APP升级、整包更新和热更新组件

插件地址&#xff1a;app升级、整包更新和热更新组件 仔细阅读说明文档&#xff0c;后台接口返回的数据格式要严格按照文档要求的格式返回&#xff0c;前端示例代码 或者根据实际业务修改 如果需要自动检测新版本&#xff0c;建议写在App.vue的onShow中&#xff0c; <scrip…

化繁为简——论五大市场风格

A股市场至今已有逾5000家上市公司&#xff0c;行业分析有助于化简选股过程&#xff0c;然而如果想要对于各个行业都获得高于平均水平的了解&#xff0c;行业分类体系又显得繁杂。以中信行业分类体系为例&#xff0c;其一级行业包括30个行业类别&#xff0c;二级行业包括109个行…

高效工作——PPT动画制作【图文板(1)】

今天&#xff0c;我来教大家如何制作PPT或PPTX动画。希望这对你能有所帮助。{提示&#xff1a;改变原文&#xff1a;查看本人的“高效工作——PPT动画制作【文字板&#xff08;1&#xff09;】”} 首先&#xff0c;打开WPS office&#xff0c;点击创建PPT&#xff0c;点击创建空…

安全头响应头(二)​X-Frame-Options​

一 X-Frame-Options 1) CSP 安全头与前端编程息息相关,后续通过对CSP头的理解加深对前端知识的理解 ① 点击劫持 说明&#xff1a;X-FRAME-OPTIONS是微软提出的一个http头,专门用来防御利用iframe嵌套的点击劫持攻击 相关参考 ② 简介 背景&#xff1a; 出于安全考虑…

5.8.8 TCP流量控制

5.8.8 TCP流量控制 计算机网络的流量控制实际上是调节发送方的速率使得接收方能够及时处理的一个过程。 在TCP中采用的是大小可变的滑动窗口的方式进行流量控制&#xff0c;窗口大小的单位是字节。 如图 根据接收方的接收能力&#xff0c;通过接收窗口rwnd可以实现一个端到端…

PMO对企业的价值:有效赋能+战略落地︱富途网络PMO总监苗秀娟

富途网络科技&#xff08;深圳&#xff09;有限公司PMO总监苗秀娟女士受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾&#xff0c;演讲议题&#xff1a;PMO对企业的价值&#xff1a;有效赋能战略落地。大会将于8月12-13日在北京举办&#xff0c;敬请关注&#xff01; 议…

【LeetCode】332. 重新安排行程

332. 重新安排行程&#xff08;困难&#xff09; 思路 由于题目保证了存在一条合法的旅行路线&#xff0c;并要求按照字典序返回完整的路线。该方法通过深度优先搜索和栈的结合&#xff0c;可以保证每次选择字典序最小的终点进行访问&#xff0c;从而得到按照字典序排列的完整旅…

【Pandas】dataframe互转

目录 一、list 1.1 dataframe转list 1.2 list转dataframe 1.2.1 先用list构造字典&#xff0c;再转dataframe 1.2.2 对于符合列表&#xff0c;可以直接转成dataframe 二、dict 三、spark dataframe 一、list 【Pandas学习】list列表和Dataframe互相转换_list转datafram…