【LeetCode】29、两数相除

一、整数基础知识

1、整数是一种基本数据类型

  • 一共包括四种不同的整数类型,分别是:byte(1字节=8位),short(2字节),int(4字节),long(8字节)

  • 扩展,其他的基本数据类型, 浮点型(float,double),布尔型(bool),字符型(char),string不是基本数据类型,他是字符数组类型

2、整数数值表示范围

  • int类型表示的数值范围为(-2^31~2^31-1),也就是(-2147483648 - 2147483647)

  • 使用二进制表示,最高位为0则为正数,最高位为1为负数

3、正数运算遵循四则运算

  • 如果超出数值范围会产生溢出,不会报错,但最终结果不正确

二、LeetCode29 两数相除

1、题目信息:

cpp 复制代码
给你两个整数,被除数 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 。

提示:
-231 <= dividend, divisor <= 231 - 1
divisor != 0

2、解题思路:

  • 输入两个整数,分别是被除数dividend和除数divisor,现在要求不适用乘号,除号和取余运算符,来求两个数相除的结果。那可以选择使用加法、减法和位移运算符来实现。

  • 题目提到了使用int整数类型,可能会导致数值溢出,为解决这个问题,可对int类型进行类型转换为long。两个数都转换成正整数,至于他们相处的最终正负号使用一个变量sign来表示。

3、暴力解法:

  • 要求被除数与除数的商,可以先将两个数都转换成正整数,采用减法的方式来处理,使用while循环,判断条件为只要被除数比除数值大,则被除数的值就每次减少除数的大小,并计算while循环减去的次数,直到被除数的值小于除数。此时while循环中减去的次数就接近结果值。

  • 说接近结果值,还有一个是要考虑商的正负数处理。

4、画图理解:

5、代码实现:

cpp 复制代码
int divide(int dividend, int divisor)
{
  long res = 0;
  int sign = 1; // 计算符号

  // 获取他的绝对值,先转成longlong类型,再转换符号
  long dividendL = dividend;
  long divisorL = divisor;
  // 获取绝对值
  if (dividend < 0)
  {
    dividendL = -dividendL;
  }
  if (divisor < 0)
  {
    divisorL = -divisorL;
  }

  // 获取正负数符号
  if ((dividend < 0 && divisor < 0) || (dividend >= 0 && divisor > 0))
  {
    sign = 1;
  }
  else
  {
    sign = -1;
  }

  while (dividendL >= divisorL)
  {
    dividendL -= divisorL;
    res++;
  }
  if (sign < 0)
  {
    res = -res;
  }

  if (res > INT32_MAX)
  {
    return INT32_MAX;
  }
  if (res < INT32_MIN)
  {
    return INT32_MIN;
  }
  return res;
}

三、折半解法:

1、解题思路:

  • 上面的暴力解法使用一层while循环,每次被除数减少除数的大小,他的时间复杂度为O(n)

  • 可以通过两层while循环,每次减少数据是除数的倍数,而且这个除数的倍数的结果值,要是小于被除数一半的最大值,而要计算确定除数的倍数值,可使用内层while循环来计算

  • 因为不能使用乘法,改为使用整数的移位操作,对除数不断左移<<,在内层while循环中对除数左移一位,他的倍数是2的n次方,直到倍数值大于被除数的一半为止。

  • 这样在外层while循环中,就可以一次性减去内层while循环计算得到的除数的倍数值。直到被除数小于除数值,这个倍数值不断累加就是最终结果值。

2、画图理解:

3、代码实现:

cpp 复制代码
int divide(int dividend, int divisor)
{
  long res = 0;
  int sign = 1; // 计算符号

  // 获取他的绝对值,先转成longlong类型,再转换符号
  long dividendL = dividend;
  long divisorL = divisor;
  // 获取绝对值
  if (dividend < 0)
  {
    dividendL = -dividendL;
  }
  if (divisor < 0)
  {
    divisorL = -divisorL;
  }

  // 获取正负数符号
  if ((dividend < 0 && divisor < 0) || (dividend >= 0 && divisor > 0))
  {
    sign = 1;
  }
  else
  {
    sign = -1;
  }

  // 使用阶乘方式来处理
  long temp = 0;
  long multi = 0; // 重复的阶乘个数
  while (dividendL >= divisorL)
  {
    multi = 1;
    temp = divisorL;
    while (dividendL > (temp << 1))
    {
      multi = multi << 1; // 往左移动
      temp = temp << 1;
    }
    dividendL -= temp;
    res += multi;
  }
  if (sign < 0)
  {
    res = -res;
  }

  if (res > INT32_MAX)
  {
    return INT32_MAX;
  }
  if (res < INT32_MIN)
  {
    return INT32_MIN;
  }
  return res;
}

四、总结:

  • 整数包括始终数据类型,他有正负号与数值表示范围

  • 整数遵循四则运算法则,超过数值范围会导致数值溢出

  • 暴力解法采用被除数不断减去除数的次数,直到被除数小于除数

  • 折半解法采用两层while循环,每次减少被除数的一半,采用位移方式减出除数的2的倍数

相关推荐
船厂电气自动化ai大模型1 小时前
AI大模型与数学/第63课:矩阵定义、矩阵加法、标量乘法(逐级精讲)
数据结构·人工智能·深度学习·线性代数·算法
余额瞒着我当琳1 小时前
算法修炼 chapter 2 双指针进阶、盛最多水的容器、有效三角形的个数、两数之和、三数之和、四数之和
算法
你压到我腿毛了6661 小时前
C语言冒泡算法(Bubble sort)
c语言·数据结构·算法
靠沿2 小时前
贪心算法专题(三)
算法·贪心算法
super大力张2 小时前
MOE基于结构的药物设计(七):Ligand R-Vectors——如何判断配体可以从哪里继续生长?
数据库·算法·cadd·moe·svl·基于结构的药物设计
Tongsr3 小时前
别只混淆代码:用 Kaleido 加固整个 Android Release AAB
前端·算法·github
高亦真3 小时前
今天是学习嵌入式的第34天
linux·学习·算法
飞Link4 小时前
动作方法中的分割与过度分割方法全解析(含代码实战与踩坑案例)
人工智能·python·算法·计算机视觉
张宇Joaquin5 小时前
鲲鹏统一并行加速库KUPL--异步数据拷贝
线性代数·算法·矩阵·numpy