Leetcode29:两数相除

2024-02-15 11:36
文章标签 相除 leetcode29

本文主要是介绍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);}
}

这篇关于Leetcode29:两数相除的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/711273

相关文章

一个google的面试题 计算两个整数相除

Divide number and return result in form of a string. e.g 100/3 result should be 33.(3) Here 3 is in brackets because it gets repeated continuously and 5/10 should be 0.5. 这题难在怎么去判断循环和记录循环出现的位置 上代码:

两个long型数据相除结果错误问题解决

long A=1; long B=2; 因为两个long型数据相除默认取整数,所以就有 A/B=0; 这样的结果是不准确的,我们可以通过将被除数乘以1.0,这时的结果就会带小数了 A*1.0/B=0.5 当我们用两个long型计算文件的下载百分比的时候,可以将被除数先乘以100,这样得到的就直接是百分数了。 A*100/B

verilog中两个常数相除

在Verilog中,两个常数(即编译时已知的值)相除,其结果的处理方式取决于几个因素,包括这些常数的类型(整数还是实数)、Verilog的版本(Verilog-2001之前的版本与SystemVerilog有所不同,尽管后者在很大程度上与Verilog兼容并扩展了其功能),以及你期望的结果类型。 整数除整数 如果两个操作数都是整数,那么结果也将是整数,并且结果会向下取整(即,丢弃小数部分)。这

java求两个整数相除得到的小数

在 Java 中,进行整数相除操作时,如果操作数都是整数,结果也会是整数,并且小数部分会被丢弃。如果你希望得到一个包含小数部分的结果,你需要将其中至少一个操作数转换为浮点类型(如 double 或 float)。 类型转换 public class DivisionExample {public static void main(String[] args) {int numerator =

数论基础 辗转相除 扩展欧几里德

辗转相除: 辗转相除,又称为欧几里德算法,用于求解俩个数值的最大公约数,原理如下: gcd(a,b) = gcd(b,a%b) = gcd(a%b,(a%b)%b) ... = gcd(c,0) = c; 一般经过俩次的递归之后,第一个参数就小于原来的一半,所以不用但是栈溢出的情况。 int gcd(int a,int b){if(b==0)return a;return

【Leetcode 29】 两数相除

题目描述 方法一: 题干中说明不能用乘法和除法, 那么我们可以用减法, 被除数最多可以减多少个除数还能保证是非负的即可.换句话说商为被除数减去除数的总次数 class Solution:def divide(self, dividend, divisor):sig = True if dividend*divisor > 0 else False # 判断二者相除是正or负dividend

1016 两浮点数相除

#include<iostream>#include<iomanip>using namespace std;int main(){double a,b,c;cin>>a>>b;c=a/b;cout<<setiosflags(ios::fixed)<<setprecision(2)<<c<<endl;return 0;}

浅谈一下大数相除有关思路(图解)与用java代码具体解决方案

浅谈一下大数相除有关思路(图解)与用java代码具体解决方案         PS:接上篇大数相乘博客。两数的正负情况在这就不谈了,只要加一个标记就可以了。此文阅读前提:需在解决了大数相加减和大数相乘的基础上进行。     在完成了大数相乘的程序后,很自然地想到了在不使用java API的情况下,如何实现两个数相除,两数可以是大数和小数的任意组合,如大数/大数,大数/小数。   思路图解1

将两数相除

将两数相除,要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8 ,-2.7335 将被截断至 -2 。 首先对被除数和除数为特殊值时出现越界问题进行判断。 当被除数为 32 位有符号整数的最小值 −2^31时:         如果除数为 1,那么我们可以直接返回答案 −2^31         如果除

LintCode_两个整数相除

问题描述: 将两个整数相除,要求不使用乘法、除法和 mod 运算符。如果溢出,返回 2147483647 。 样例:给定被除数 = 100 ,除数 = 9,返回 11。 算法思想: 方法一:(这是开始自己想出来的,算法思想简单,缺点是,循环次数多,运行速度慢) 如果不能采用乘除运算方法,那么可以采用加减方式,当然还要(1)、注意分类:正正,正负,负正,负负;(2)、溢出问题;