当前位置: 首页 > news >正文

Leetcode29:两数相除

一、题目描述

给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。
整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8 ,-2.7335 将被截断至 -2 。
返回被除数 dividend 除以除数 divisor 得到的 商 。

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

示例 1:
输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = 3.33333.. ,向零截断后得到 3 示例 2:
输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 

二、题解

1.加法
    0 1 1 1+ 1 1 1 0-------------1 0 1 0 11+0=11+1=2 转为二进制 10 填0,往前进一位1+1+1(前面进的位)=3 转为二进制 11 填1,往前进一位0+1+1=2 转为二进制 10 填0,往前进一位

加法结果:
使用^运算(^ : 两个位相同为0,相异为1)的到的结果就是无进位相加的结果
进位信息:
如果两个都为1,那么就会有进位信息,用&运算,得到的就是1,再往左移动一位,结果就是进位信息
最终的结果就是让^运算的结果加上进位信息
得到的 ^运算结果 和 &运算结果左移 相加就是和,依次执行,直到进位信息没有了,就通过位运算实现了加法

    /*** 加法*     0 1 1 1*   + 1 1 1 0*   -------------*   1 0 1 0 1**  1+0=1*  1+1=2 转为二进制 10 填0,往前进一位*  1+1+1(前面进的位)=3 转为二进制 11 填1,往前进一位*  0+1+1=2 转为二进制 10 填0,往前进一位*/public int add(int a ,int b){//相同为0,不同为1,当两个要相加的时候,相同进位为0,不同1+0=0,缺少进位信息int result = a ^ b;// 相同为1,不同为0;相同进位,左移一位刚好为进位信息int carry = (a & b) << 1;if(carry!=0){return add(result,carry);}return result;}
2.减法
   1 0 1 0 0 1- 0 1 1 0 1 0----------------0 0 1 1 1 11-0=1
0-1 不够减,往前借1(借到的是2), 2-1=1
0-0 因为被借走了一位,所以0变成-1:-1-0,不够减,往前借1,2-1-0=1
1-1 因为被借走了一位,所以1变成0:0-1,不够减,往前借1,2-1=1
0-1 因为被借走了一位,所以0变成-1,-1-1,不够减,往前借1,2-1-1=0
1-0 因为被借走了一位,所以1变成0,0-0=0
    /*** 减法* a-b => a+(-b)* -b => ~b+1* @param a* @param b* @return*/public static int minus(int a, int b) {return add(a,add(~b,1));}
3.乘法
        1 0 0 1* 1 1 0 1---------------------1 0 0 10 0 0 01 0 0 11 0 0 1-----------------------1 1 1 0 1 0 1

乘法

  • 当乘的位数是1的时候,还是原来的数字
  • 当乘的位数是0的时候,全部是0
  • 把全部的结果相加

思路:判断乘数b的位数是不是1,通过让他和1进行&运算,如果是1,说明当前位是1。(当乘数是0的时候不用考虑,因为乘出来要加的还是0)
&完的结果如果是1,把被乘数a作为要相加的和,左移一位(下一次如果是1的和)。
b右移一位,让他来到下一位去乘。

    /*** 乘法*          1 0 0 1*        * 1 1 0 1*    ---------------------*          1 0 0 1*        0 0 0 0*      1 0 0 1*    1 0 0 1*   -----------------------*    1 1 1 0 1 0 1*/public static int multiply(int a, int b) {int lastSum = 0;while (b != 0) {//b和1进行&运算,判断除要乘的这位是不是1if ((b & 1) == 1) {lastSum = add(lastSum, a);}// 111b = (b >>> 1);a = (a << 1);}return lastSum;}
4.除法
             0 0 0 1 1 0   商-------------
除数b 1 1 0 ) 1 0 0 1 1 0           被除数a1 1 0                // 相当于b向左移动到不会超过a的位置b<=a 此位移动的次数i的位置上为1  a右移a>=b-----------            // b<<i  <= a0 0 1 1 1              // a = a-(b<<i)1 1 0              // b向左移动到不会超过a的位置 此位商为1------------0 0 1 0  余数      //
  public static int divide(int a, int b) {if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {return 1;}if (a != Integer.MIN_VALUE && b == Integer.MIN_VALUE) {return 0;}if (a == Integer.MIN_VALUE) {if (b == -1) {return Integer.MAX_VALUE;}/*** 系统最小值没办法取绝对值,使用分配律解决** 要计算Integer.MIN_VALUE ÷ b:* 先计算(Integer.MIN_VALUE+1)÷ b = c* c*b = a* [(Integer.MIN_VALUE+1)- a] / b = d* 商=c+d*/int i = divideNormal(add(a, 1), b);int multiplyRes = multiply(i, b);int minusRes = minus(a, multiplyRes);int subRes = divideNormal(minusRes, b);return add(i, subRes);}return divideNormal(a, b);}/*** 正常除法(不包含系统最小)* @param a* @param b* @return*/private static int divideNormal(int a, int b) {boolean negativeA = isNegative(a);boolean negativeB = isNegative(b);a = negativeA ? oppositeNum(a) : a;b = negativeB ? oppositeNum(b) : b;int result = 0;// int整型一共32位,一位一位的移动去尝试for (int i = 30; i >= 0; i = minus(i, 1)) {if ((a >> i) >= b) {//说明第i位是1,使用|运算,让数字和1<<i去进行|运算,可以让i对应的那一位变成1。result = result | (1 << i); a = minus(a, b << i); //a = a-(b<<i);}}return negativeA != negativeB ? oppositeNum(result) : result;}/*** 判断一个数是否是负数* @param a* @return*/public static boolean isNegative(int a) {return a < 0;}/*** 取相反数* @param a* @return*/public static int oppositeNum(int a){return ~a+1;}
完整题解:
class Solution {public int divide(int dividend, int divisor) {  if (dividend == Integer.MIN_VALUE && divisor == Integer.MIN_VALUE) {return 1;}if (dividend != Integer.MIN_VALUE && divisor == Integer.MIN_VALUE) {return 0;}if (dividend == Integer.MIN_VALUE) {if (divisor == -1) {return Integer.MAX_VALUE;}int i = divideNormal(add(dividend, 1), divisor);int multiplyRes = multiply(i, divisor);int minusRes = minus(dividend, multiplyRes);int subRes = divideNormal(minusRes, divisor);return add(i, subRes);}return divideNormal(dividend, divisor);}public int divideNormal(int dividend, int divisor) {boolean isNegativeA = isNegative(dividend);boolean isNegativeB = isNegative(divisor);dividend = isNegativeA? oppositeNum(dividend):dividend;divisor = isNegativeB? oppositeNum(divisor):divisor;int result = 0;for(int i=30;i>=0;i = minus(i,1)){if(dividend>>i >= divisor){result |= 1<<i;//dividend = dividend - divisor<<i;dividend = minus(dividend,divisor<<i);}}return isNegativeA!=isNegativeB ? oppositeNum(result) : result;}public boolean isNegative(int a){return a<0;}public int add(int a ,int b){//相同为0,不同为1,当两个要相加的时候,相同进位为0,不同1+0=0,缺少进位信息int result = a ^ b;// 相同为1,不同为0;相同进位,左移一位刚好为进位信息int carry = (a & b) << 1;if(carry!=0){return add(result,carry);}return result;}public int minus(int a,int b){return add(a,oppositeNum(b));}public int multiply(int a,int b){int result = 0;while(b!=0){int res = b&1;if(res == 1){result = add(a,result);}a = a<<1;b = b>>>1;}return result;}public int oppositeNum(int a){return add(~a,1);}
}

相关文章:

  • 【python之美】减少人工成本之批量拿取文件名保存_4
  • Rust的Match语句:强大的控制流运算符
  • Gin 中使用 base64Captcha 生成图形验证码
  • flask+python高校学生综合测评管理系统 phl8b
  • 1.JavaScript中的数据类型
  • 小白学习Halcon100例:如何利用动态阈值分割图像进行PCB印刷缺陷检测?
  • DolphinScheduler安装与配置
  • 《零基础实践深度学习》波士顿房价预测任务1.3.3.4训练过程
  • 寒假学习记录13:JS对象
  • 探索XGBoost:自动化机器学习(AutoML)
  • 投资银行在网络安全生态中的作用
  • Python 线性回归可视化 并将回归函数放置到图像上
  • Prompt Tuning:深度解读一种新的微调范式
  • YOLOv5改进 | 融合改进篇 | 华为VanillaNet + BiFPN突破涨点极限
  • TeamCity创建git项目Timed out 超时的一个解决办法
  • C# 免费离线人脸识别 2.0 Demo
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • HashMap剖析之内部结构
  • JavaScript 奇技淫巧
  • java取消线程实例
  • jQuery(一)
  • node.js
  • Object.assign方法不能实现深复制
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • vue.js框架原理浅析
  • vue脚手架vue-cli
  • windows下mongoDB的环境配置
  • 前端js -- this指向总结。
  • 使用SAX解析XML
  • 学习笔记TF060:图像语音结合,看图说话
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • Android开发者必备:推荐一款助力开发的开源APP
  • 阿里云移动端播放器高级功能介绍
  • 选择阿里云数据库HBase版十大理由
  • # Apache SeaTunnel 究竟是什么?
  • #git 撤消对文件的更改
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (6)STL算法之转换
  • (pojstep1.3.1)1017(构造法模拟)
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (四)模仿学习-完成后台管理页面查询
  • .md即markdown文件的基本常用编写语法
  • .mysql secret在哪_MySQL如何使用索引
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .net MySql
  • .net wcf memory gates checking failed
  • .net 验证控件和javaScript的冲突问题
  • .net专家(高海东的专栏)
  • @Autowired和@Resource装配
  • @Query中countQuery的介绍
  • @RequestParam详解
  • @德人合科技——天锐绿盾 | 图纸加密软件有哪些功能呢?
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945
  • [Angularjs]asp.net mvc+angularjs+web api单页应用