每日一题「整数除法」

132 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

我是陈皮,一个在互联网 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

本次分享到此结束啦~~

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