每日一题「整数除法」

我是陈皮,一个在互联网 Coding 的 ITer,个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新技术文章。

文章目录

题目

输入2个 int 型整数,将它们进行除法计算并返回商,要求不得使用乘号、除号及求余符号。当发生溢出时,返回最大的整数值。假设除数不为0。例如,输入15和2,输出15/2的结果,即7。

分析

限制了不可以使用除法,乘法,和求余运算,那么可以使用减法来实现除法。

例如15/2,不断地从15里减去2,当减去7个2之后余数是1,余数不能再减去2,所以15/2的商是7。使用一个循环即可实现这个过程。

不过,但当被除数很大但除数很小时,减法操作执行的次数会很多。例如,当被除数为 int 类型的最大值 2^31 - 1,除数为1时,减1操作次数为 2^31 - 1 次。当除数为2时,减2操作次数也要 2^30 次左右。这样会导致算法速度很慢。

所以我们需要优化,如果被除数大于除数时,判断被除数是否大于除数的2倍,如果是,再判断是否4倍,8倍…,直到最多2n倍。然后将被除数减去2n个除数,2n的值累加到总的减次数中,将剩余的被除数继续重复以上操作,直到剩余的被除数小于除数。因为每次将除数翻倍,所以时间复杂度是O(logn)。

因为被除数和除数都有可能是负数,为方便计算,需要先将它们都转为同符号的整数,计算出结果后,再进行对商调整符号。如果将负数都调整为正数,有可能会发生溢出,例如负数-231,但是正数最大值是231-1。所以我们选择将正数转为负数,对两个负数进行除法求商,最后再对商的符号进行调整。

实现

package com.chenpi;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/17
 */
public class ChenPi {

  public static void main(String[] args) {
    ChenPi inst = new ChenPi();
    int dividend = -18;
    int divisor = 3;
    System.out.println(inst.divide(dividend, divisor));
  }

  public int divide(int dividend, int divisor) {

    // 这种情况会发生溢出
    if (dividend == Integer.MIN_VALUE && divisor == -1) {
      return Integer.MAX_VALUE;
    }

    // 记录负号的个数
    int negativeCount = 2;

    // 被除数如果为正数转为负数
    if (dividend > 0) {
      dividend = -dividend;
      negativeCount--;
    }

    // 除数如果为正数转为负数
    if (divisor > 0) {
      divisor = -divisor;
      negativeCount--;
    }

    // 商
    int result = 0;

    // 被除数小于除数时(因为它们都是负数),重复
    while (dividend <= divisor) {
      // 记录最大的|除数*2n|绝对值
      int timesValue = divisor;
      // 减去除数的次数
      int times = 1;
      // 最小值是-2^31,0xc0000000是-2^30,避免timesValue是-2^31时,timesValue + timesValue发生溢出
      while (timesValue >= 0xc0000000 && dividend <= timesValue + timesValue) {
        times += times;
        timesValue += timesValue;
      }
      result += times;
      dividend -= timesValue;
    }

    // 商符号调整
    return negativeCount == 1 ? -result : result;
  }

}

输出结果

-6

本次分享到此结束啦~~

如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈皮的JavaLib

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值