LeetCode--29.两数相除

解题思路:

        1.获取信息:

                给定两个整数,一个除数,一个被除数,要求返回商(商取整数)

                限制条件:(1)不能使用乘法,除法和取余运算

                                  (2)只能存储32位有符号整数

                额外条件:(1)除数不等于0

                                  (2)INT_MIN<=除数,被除数<=INT_MAX

        2.分析题目:

                (1)不能使用乘法,除法和取余运算

                        我们可以使用加法,减法,那么就可以想到快速乘算法

                        快速乘算法,就是使用加法来模拟乘法的哦,其中会用到右移运算符和quan'zh哦

                        (为了方便你理解我下面的各种方法,我打算一反常态,直接在这个环节讲解一下快速乘法是什么,还会配图哦,实在是很贴心,但我只会说一下基本原理,你可以思考一下该怎么和这道题结合起来)

​​​​​​​

                (2)只能存储32为有符号整数,并且INT_MIN<=除数,被除数<=INT_MAX

                        所以我们要考虑一下溢出的问题了,那么我们想一下一个除法,该怎么丧心病狂地溢出呢?

                        你想一下,我们是求商对吧,在本题的条件下,一个除法的商是不会大于它的被除数的吧,因为都为整数嘛,那么我们可以知道,商一般不会溢出

                        那么造成溢出的情况就只有一些特殊的情况了,如下两种溢出

                        (1)原则上溢出:被除数等于INT_MIN,而除数等于-1,两者相除会大于INT_MAX,所以会溢出

                       (2)运算过程中溢出:因为使用了快速乘的算法,我们在加的过程中可能会造成溢出,(这个溢出也与我所用方法有关,因为我是使用二分查找法来查找一个合适的数来检验是否可以作为商,难免有时候会溢出)

                        这个时候就需要对溢出进行检验,及时止损,我用了以下两步来避免溢出

                        (1)第一步:我们知道INT_MAX<INT_MIN对吧,那么我们就将除数和被除数全部变为负数,用一个bool类型的变量来决定结果商的正负,那么就不容易溢出

                        如果你有疑惑,难道变成正数不行吗?其实也行,但是麻烦,在遇到,如:

                        被除数等于INT_MIN,除数大于1的情况,变成正数,肯定会溢出,而且进行处理也特别麻烦

                        (所以,我们在思考的时候,不要给自己增加太多的麻烦,你要做的是简化问题,而不是让这个问题变得更加麻烦,给自己脑袋增加负担哦)

                        (2)第二步:

                                我们知道在快速乘中会使用加法来模拟乘法,所以可以在加的过程中判断一下溢出

                                (我在这里想不到说什么可以讲得明白,我也不想长篇大论地来浪费你的精力,所以我会在下面的方法中结合代码来帮助你理解我会怎么避免溢出,可以期待一下,你现在也可以自己想一下,再到下面对答案哦)

        3.示例查验:

                示例1和示例2:都没啥太大帮助,也没有提示你什么(我其他题的这个环节是很精彩的,主要是这道题给我衬托得太没用了)

        4.尝试编写代码:

                (这道题你可能看过很多的题解了,你可能是百思不得其解的状态,所以我还是打算换一种方式来帮助你理解,我会用我初次看到这道题一直到我写出其他方法的过程来帮助你层层递进哦,可以期待一下,好了,下面就开始了,你要跟上咯)

                (1)暴力法(这是我第一次写的办法,最后的结果是超时了,被打败了)

                        思路:除法的本质就是减法,乘法的本质就是加法

                                所以我们可以用除数一直去减被除数直到被除数小于0或者用除数一直相加直到等于被除数,最后得到的,进行减法的次数或者进行加法的次数就是商了

下面就是代码的实现,(但是我这个方法并没有通过,只是不想你思维跨度那么大,让你摸不着头脑而已,如果你也是这种方法没过,哈哈,那我们蛮有缘的嘛)

class Solution {
public:int divide(int dividend, int divisor) {if(dividend==0)return 0;//如果被除数为0,直接返回0if(dividend==INT_MIN){//如果被除数为INT_MINif(divisor==1)return INT_MIN;if(divisor==-1)return INT_MAX;}if(divisor==1)return dividend;//如果除数为1,返回被除数if(divisor==-1)return -dividend;//如果除数为1,返回被除数的相反数bool front=false;//分别记录除数和被除数的符号bool tail=false;if(dividend>0){front=true;dividend=-dividend;};//将被除数和除数全部变为负数if(divisor>0){tail=true;divisor=-divisor;}if(dividend>divisor)return 0;//(这里它们都是负数了,所以表示大小的关系不一样咯,别搞错了)如果被除数大于除数,就返回0int res=divisor;//相加的结果int num=1;//相加的次数if(dividend!=INT_MIN){//如果被除数不等于INT_MINwhile(res!=dividend-1&&res!=dividend+1&&res!=dividend){//一直相加步直到满足条件,退出循环res+=divisor;num++;}}else{//如果被除数等于INT_MINwhile(res!=dividend+1&&res!=dividend){//一直相加直到不满足条件,退出循环if(dividend-divisor>res)return front==tail?num:-num;res+=divisor;num++;}}return (front==tail)?num:-num;//返回商}
};

                (2)二分查找法+快速乘(全部迭代法)

                        优化思路:我上面的暴力法超时了,我就在想有没有什么办法可以进行优化

                                        主要的问题是,加法进行的次数太多了,而且进行加法的方式的效率也太低了

                                        所以我就使用了二分查找法和快速乘的法方法来进行书写

                        思路:我们知道,在本题的条件下,商肯定是不会大于被除数的,那么我们就在1到被除数的大小这个范围使用二分法来查找商即可

                                   我们用二分法查找到一个数来作为商,那我们需要对其进行检验吧?

                                   我们就使用快速乘求出商(待检验的那个数)乘除数的结果来对其进行检验,无非就三种情况

                                (1)结果等于被除数,直接返回那个数(要考虑一下正负哦)即可

                                (2)结果小于被除数,说明那个数取小了,就需要在右边的区间取数

                                (3)结果大于被除数,说明那个数取大了,就需要在左边的区间取数

                        接下来说重头戏,快速乘怎么样在这道题里面实现

                        快速乘,我们写一个自定义函数,传入商(二分法选取的那个数)和除数,返回它们的乘积

                        要考虑商的二进制,因为要用到右移运算符>>嘛,那么我们就需要考虑各个位数上的权重,将正确的权重加到结果上去,再让商每次右移一位,直到商为0

                        (我知道,你肯定看不懂我说的啥意思,即使你看懂了我上面快速乘算法的基本原理,所以,你可以结合我下面的代码好好理解一下,我每行都会给出注释)

class Solution {
public:int divide(int dividend, int divisor) {if(dividend==0)return 0;//被除数如果为0,返回0if(dividend==INT_MIN){//如果被除数等于INT_MINif(divisor==-1)return INT_MAX;if(divisor==1)return INT_MIN;}bool sign=false;//一个bool类型的变量用来表示符号if(dividend>0){dividend=-dividend;sign=!sign;};//将除数和被除数全部变为负数if(divisor>0){divisor=-divisor;sign=!sign;};if(dividend>divisor)return 0;//(这里被除数和除数已经全部为负数了,所以比较关系不一样了)如果被除数大于除数,返回0int res=0;//用来储存商int begin=1;//二分查找法范围的下限int end;if(dividend==INT_MIN)end=INT_MAX;//二分查找法范围的上限else {end=-dividend;}while(begin<=end){//循环继续条件int mid=begin+((end>>2)-(begin>>2));//求出中值if(quick(mid,divisor,dividend)){//quick用来判断乘积大小,如果小于res=mid;if(mid==INT_MAX)return sign?-mid:mid;begin=mid+1;}else{//如果大于end=mid-1;}}return sign?-res:res;}
private:bool quick(int mid,int divisor,int dividend){//此时除数和被除数都为负数,所以比较条件,你要好好注意一下int res=0,add=divisor;//add是指权重哦while(mid){if(mid&1){//如果二进制的最后一位为1,那么就可以将这一位加到res中了,因为下一步就是右移一位,舍弃掉这个1if(res<dividend-add)return false;res+=add;}if(mid!=1){//这是在更新权重,配合着上面那个if语句进行正确的加法,比如,末尾一位是二的零次方,倒数第二位是二的一次方,依次类推if(add<dividend-add)return false;add+=add;}mid>>=1;}return true;}
};

                 (3)二分查找法+快速乘(全部迭代版)

                        就是把上面那个方法中用到递归的地方换成了迭代而已,根本思路没变,只是手法变了,我就不写思路咯

                        也不写注释了,考验一下你,哈哈

class Solution {
public:int divide(int dividend, int divisor) {if(dividend==0)return 0;if(dividend==INT_MIN){if(divisor==-1)return INT_MAX;if(divisor==1)return INT_MIN;}bool sign=false;if(dividend>0){dividend=-dividend;sign=!sign;};if(divisor>0){divisor=-divisor;sign=!sign;};if(dividend>divisor)return 0;int res=0;int begin=1;int end;if(dividend==INT_MIN)end=INT_MAX;else {end=-dividend;}res=reverse(begin,end,divisor,dividend,res,sign);return sign?-res:res;}
private:bool quick(int mid,int divisor,int dividend,int res,int add){if(mid<=0)return true;if(mid&1){if(res<dividend-add)return false;res+=add;}if(mid!=1){if(add<dividend-add)return false;add+=add;}mid>>=1;return quick(mid,divisor,dividend,res,add);}int reverse(int begin,int end,int divisor,int dividend,int res,bool sign){if(begin>end)return res;int mid=begin+((end>>1)-(begin>>1));if(quick(mid,divisor,dividend,0,divisor)){res=mid;if(mid==INT_MAX)return mid;begin=mid+1;}else{end=mid-1;}return reverse(begin,end,divisor,dividend,res,sign);}
};

                (4)模拟二分查找法

                        优化思路: 二分查找法已经很优秀了,那还可不可以更加优秀呢?

                                当然可以咯,众所周知,时间复杂度和空间复杂度是此消彼长的关系

                                那么,我们可不可以牺牲空间复杂度来成就时间复杂度呢?

                                于是,这个办法就诞生了

                        思路:我们通过用一个vector来模拟二分查找法

                                我们将商的二进制的各个位数对应的权重都存储在这个vector中,

                                我们根据被除数的二进制的各个权重来决定要存多少个位数进入vector中,

                                在逐个取出vector中的权重减去被除数,来得出商

                                (这个方法,我受到的启发是力扣的那道,数字转罗马数字那道题)

 以下是完整代码,如果你没有看懂我的描述,你可以结合代码中的注释好好理解一下

class Solution {
public:int divide(int dividend, int divisor) {if(dividend==0)return 0;//被除数为0,返回0if(dividend==INT_MIN){//被除数为INT_MINif(divisor==-1)return INT_MAX;if(divisor==1)return INT_MIN;}bool sign=false;//一个符号用来记录正负if(dividend>0){dividend=-dividend;sign=!sign;};//将被除数和除数全变成负数if(divisor>0){divisor=-divisor;sign=!sign;};if(dividend>divisor)return 0;//(此时被除数和除数全部是负数)如果被除数大于除数,返回0int res=0;//商vector<int>table={divisor};//用来存储商的权重while(table.back()>=dividend-table.back())table.push_back(table.back()<<1);//根据被除数来决定商的权重for(int i=table.size()-1;i>=0;i--){if(table[i]>=dividend){res+=(1<<i);//通过商的权重来得出商dividend-=table[i];//被除数减去商的权重}}return sign?-res:res;}
};

以上就是这道题的解析,希望能够帮到你,给你提供便利而没有浪费你的时间和精力

我还是提一嘴,纸上得来终觉浅,绝知此事要躬行哦 

晚安

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

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

相关文章

中山大学GaussianFusion:首个将高斯表示引入端到端自动驾驶多传感器融合的新框架

摘要 近年来由于端到端自动驾驶极大简化了原有传统自动驾驶模块化的流程&#xff0c;吸引了来自工业界和学术界的广泛关注。然而&#xff0c;现有的端到端智驾算法通常采用单一传感器&#xff0c;使其在处理复杂多样和具有挑战性的驾驶场景中受到了限制。而多传感器融合可以很…

《哈希算法》题集

1、模板题集 满足差值的数字对 2、课内题集 字符统计 字符串统计 优质数对 3、课后题集 2006 Equations k倍区间 可结合的元素对 满足差值的数字对 异常频率 神秘数对 费里的语言 连连看 本题集为作者&#xff08;英雄哪里出来&#xff09;在抖音的独家课程《英雄C入门到精…

Cordova移动应用对云端服务器数据库的跨域访问

Cordova移动应用对云端服务器数据库的跨域访问 当基于类似 Cordova这样的跨平台开发框架进行移动应用的跨平台开发时&#xff0c;往往需要访问部署在公网云端服务器上的数据库&#xff0c;这时就涉及到了跨域数据访问的问题。 文章目录 Cordova移动应用对云端服务器数据库的跨…

mysql知识点3--创建和使用数据库

mysql知识点3–创建数据库 创建数据库 在MySQL中创建数据库使用CREATE DATABASE语句。语法如下&#xff1a; CREATE DATABASE database_name;其中database_name为自定义的数据库名称。例如创建名为test_db的数据库&#xff1a; CREATE DATABASE test_db;可以添加字符集和排…

林业资源多元监测技术守护绿水青山

在云南高黎贡山的密林中&#xff0c;无人机群正以毫米级精度扫描古树年轮&#xff1b;福建武夷山保护区&#xff0c;卫星遥感数据实时追踪着珍稀动植物的栖息地变化&#xff1b;海南热带雨林里&#xff0c;AI算法正从亿万条数据中预测下一场山火的风险……这些科幻场景&#xf…

一阶/二阶Nomoto模型(野本模型)为何“看不到”船速对回转角速度/角加速度的影响?

提问 图中的公式反映的是舵角和力矩之间的关系&#xff0c; 其中可以看到力矩&#xff08;可以理解为角加速度&#xff09;以及相应导致的回转角速度和当前的舵速&#xff08;主要由船速贡献&#xff09;有关&#xff0c;那么为什么一阶Nomoto模型&#xff08;一阶野本&#xf…

深入剖析 C++ 默认函数:拷贝构造与赋值运算符重载

目录 1. 简单认识C 类的默认函数 1.1 默认构造函数 1.2 析构函数 1.3 拷贝构造函数 2. 拷贝构造函数的深入理解 拷贝构造的特点: 实际运用 3. 赋值运算符重载的深入理解 3.1.运算符重载 3.2样例 1.比较运算符重载 2.算术运算符重载 3.自增和自减运算符重载 4.输…

板凳-------Mysql cookbook学习 (十--3)

5.16 用短语来进行fulltext查询 mysql> select count(*) from kjv where match(vtext) against(God); ---------- | count(*) | ---------- | 0 | ---------- 1 row in set (0.00 sec)mysql> select count(*) from kjv where match(vtext) against(sin); -------…

python爬虫ip封禁应对办法

目录 一、背景现象 二、准备工作 三、代码实现 一、背景现象 最近在做爬虫项目时&#xff0c;爬取的网站&#xff0c;如果发送请求太频繁的话&#xff0c;对方网站会先是响应缓慢&#xff0c;最后是封禁一段时间。一直是拒绝连接&#xff0c;导致程序无法正常预期的爬取数据…

【AIGC】Qwen3-Embedding:Embedding与Rerank模型新标杆

Qwen3-Embedding&#xff1a;Embedding与Rerank模型新标杆 一、引言二、技术架构与核心创新1. 模型结构与训练策略&#xff08;1&#xff09;多阶段训练流程&#xff08;2&#xff09;高效推理设计&#xff08;3&#xff09;多语言与长上下文支持 2. 与经典模型的性能对比 三、…

算法竞赛阶段二-数据结构(32)数据结构简单介绍

数据结构的基本概念 数据结构是计算机存储、组织数据的方式&#xff0c;旨在高效地访问和修改数据。它是算法设计的基础&#xff0c;直接影响程序的性能。数据结构可分为线性结构和非线性结构两大类。 线性数据结构 线性结构中&#xff0c;数据元素按顺序排列&#xff0c;每…

Windows桌面图标修复

新建文本文件&#xff0c;粘入以下代码&#xff0c;保存为.bat文件&#xff0c;管理员运行这个文件 duecho off taskkill /f /im explorer.exe CD /d %userprofile%\AppData\Local DEL IconCache.db /a start explorer.exe echo 执行完成上面代码作用是删除桌面图标缓存库&…

13.react与next.js的特性和原理

&#x1f7e1; 一句话总结 React 专注于构建组件&#xff0c;而 Next.js 是基于 React 的全栈框架&#xff0c;提供了页面路由、服务端渲染和全栈能力&#xff0c;让你能快速开发现代 Web 应用。 React focuses on building UI components, while Next.js is a full-stack fra…

全栈监控系统架构

全栈监控系统架构 可观测性从数据层面可分为三类&#xff1a; 指标度量(Metrics)&#xff1a;记录系统的总体运行状态。事件日志(Logs)&#xff1a;记录系统运行期间发生的离散事件。链路追踪(Tracing)&#xff1a;记录一个请求接入到结束的处理过程&#xff0c;主要用于排查…

云服务运行安全创新标杆:阿里云飞天洛神云网络子系统“齐天”再次斩获奖项

引言 为认真落实工信部《工业和信息化部办公厅关于印发信息通信网络运行安全管理年实施方案的通知》&#xff0c;2025年5月30日中国信息通信研究院于浙江杭州举办了“云服务运行安全高质量发展交流会”&#xff0c;推动正向引导&#xff0c;巩固云服务安全专项治理成果。会上&a…

刀客doc:WPP走下神坛

一、至暗时刻&#xff1f; 6月11日&#xff0c;快消巨头玛氏公司宣布其价值17 亿美元&#xff0c;在全球70个市场的广告业务交给阳狮集团&#xff0c;这其中包括M&Ms、士力架、宝路等知名品牌。 此前&#xff0c;玛氏公司一直是WPP的大客户。早在今年3月&#xff0c;WPP就…

进行性核上性麻痹饮食攻略:营养安全双护航

进行性核上性麻痹是一种罕见的神经系统退行性疾病&#xff0c;主要影响患者的运动、平衡和吞咽功能。除了医学干预&#xff0c;科学的饮食管理也能在一定程度上减轻症状&#xff0c;提高生活质量。 由于患者常出现吞咽困难&#xff0c;食物质地的选择尤为重要。应避免干硬、大块…

阿里云可观测 2025 年 5 月产品动态

本月可观测热文回顾 文章一览&#xff1a; StoreView SQL&#xff0c;让数据分析不受地域限制 不懂 PromQL&#xff1f;AI 智能体帮你玩转大规模指标数据分析 DeepWiki LoongCollector&#xff1a;AI 重塑开源代码理解 从 o11y 2.0 说起&#xff0c;大数据 Pipeline 的「…

React 基础状态管理方案

1. useState useState 是 React 提供的最基本的 Hook,用于在函数组件中添加状态管理。它返回一个状态变量和一个更新状态的函数。 1.1. 使用场景 适合管理简单的状态。 适合管理组件内部的局部状态。 1.2. 示例代码 import React, { useState } from react;function Cou…

VScode中如何创建项目分支

在 VS Code 中为前端项目创建自己的分支是一个常见的开发实践&#xff0c;以下是详细步骤&#xff1a; 前提条件 已安装 Git已安装 VS Code已有前端项目或克隆了远程仓库 创建分支步骤 1. 打开项目 在 VS Code 中打开你的前端项目文件夹。 2. 初始化 Git 仓库&#xff08…