sql server中两数相除获取小数部分_LeetCode : 29 两数相除

95e54195b3c46771dd121a3df1287072.png

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

返回被除数 dividend 除以除数 divisor 得到的商。

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

示例 1:

输入: dividend = 10, divisor = 3

输出: 3

解释: 10/3 = truncate(3.33333..) = truncate(3) = 3

示例 2:

输入: dividend = 7, divisor = -3

输出: -2

解释: 7/-3 = truncate(-2.33333..) = -2

提示:

被除数和除数均为 32 位有符号整数。

除数不为 0。

假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。

来源:力扣(LeetCode)

链接:力扣

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这是一道算法看起来很简单初等,但是在编程方面有难度的题目。

从整数除法的定义能够很容易地知道,我们可以用多次减法生成除法的效果。于是我们就有了最初的想法:把除法放到正整数范围内进行,使用一个循环不断地以除数为单位削减被除数,直到某一次余下的数小于除数中止,最终我们输出削减的次数作为答案即可。

然而,简单的思路没能写出简单的代码。再写出60行代码,嵌套了5层if else循环仍然报错后,我发现我的情况分类处理出现了问题。事实上,分类情况只需要考虑以下几个要点:

1.输出结果的正负性(注意异或的使用)

boolean isPositive = (dividend > 0)^(divisor < 0);
long result = isPositive? res(dvd, dvr):-res(dvd,dvr);

2.输出结果是否在存储范围内

if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
            return Integer.MAX_VALUE; 
}

3.0作为被除数

if (dividend == 0) return 0;

写在一起,就是:

 if (dividend == 0) return 0;
        else {
            if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
            return Integer.MAX_VALUE; 
            }
            else return (int)result;
        }          

我额外多写了好几种特殊情况的处理,但后来我明白那是因为我的算法运算效率太低,并且不能处理整数很大时的边界情况。如果不改进我们的算法,在出现边界值与1相除时程序会因为运行时间太长中止。故而我们使用一个朴素的想法加快除法的速度:

让每次削减被除数的量都是上一次削减的两倍。

具体地说,我们让被除数第一次削减的量为除数,第二次为除数的二倍,第三次为除数四倍,第四次为八倍。。。直到某一次削减剩余的量小于下一次应当削减的量,此时输出削减次数与剩余量,将削减次数存储,对剩余量进行相同的“加倍削减”操作,求这个剩余量的削减次数。。。如此往复,直至剩余量小于除数为止。此时,输出所有存储的削减次数之和,此乃最终结果的绝对值。

注意,这里的加倍可以使用移位操作来实现。左移或右移操作本质上是对二进制代码表示的数字乘以2或除以2,然而乘法和除法均不允许使用,故而我们考虑使用作用上等价的移位来进行代替。

代码如下:

class Solution {
    public int divide(int dividend, int divisor) {
        long dvd = (Math.abs((long)dividend));
        long dvr = (Math.abs((long)divisor));
        
        
        boolean isPositive = (dividend > 0)^(divisor < 0);
        long result = isPositive? res(dvd, dvr):-res(dvd,dvr);

        if (dividend == 0) return 0;
        else {
            if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
            return Integer.MAX_VALUE; 
            }
            else return (int)result;
        }        
    }

    public long res(long dvd, long dvr){
        long temp = dvd;
        long result = 0;
        while (temp >= dvr) {
            long para = 1;
            while (temp - dvr * para > 0) {
                para = para <<= 1;
            }
            if (temp == dvr) {
                result += para;
                temp = temp - dvr * para;
            }
            else {
                 para >>= 1;
                result += para;
                temp = temp - dvr * para;
            }
        }
        return result;
    }
}

最后,需要注意,我们使用了长整型long进行运算,以避免数据的溢出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值