【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的倍数

相关推荐
倒头就睡的小比特1 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!1 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼1 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光1 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark1 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her11 天前
并查集-听课笔记
笔记·算法·并查集
码流子1 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven1 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark1 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218611 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法