[LeetCode#29]Divide Two Integers

本文提出了一种不使用乘法、除法和取模运算符实现整数除法的方法。通过巧妙地减法操作和位移技巧,有效地解决了整数除法问题,并考虑了各种边界情况。

The problem:

Divide two integers without using multiplication, division and mod operator.

If it is overflow, return MAX_INT.

My analysis:

The idea behind this problem is very veyr elegant, it involves important mainpulataion over the digits of a number, you must master it! And this kind of problem always involves a lot of conner cases, you should be very very careful!!
The key idea:
solution 1: We keep on substracting divisor from dividend, and we record the times of substraction. Once we reach a value less than divisor, we return the count. The time complexity of this solution is O(n). 
solution 2: It also uses the idea of substraction. But it substracts in a more brave way.
num = a_0 * 2^0  +  a_1 * 2^1 + a_2 * 2^2 + a_3 * 2^3 + a_4 * 2^4 + a_5 * 2^5
Idea:
2.1 We left shift divisor to reach the value just less(or equal than) dividend. 
while (divisor <= (dividend >> 1)) { //note we stop value just bigger than (dividend >> 1), cause we would stract it. 
    divisor <<= 1;
    digit++;
}
2.2 Then we follow the below invariant.
Iff dividend larger than divisor, it means we could substract divisor from dividend. And we should add the substracted parts into the return value: 
if (dividend >= divisor ) {
    ret += (1 << digit); 
    dividend -= divisor;
}
Note: the digit here is used to record the current divisor's left shift. it represent (1>>digit) times of original divisor.
Then we could test number less than divisor (with lower times of divisor), by decreasing digit by one and right shift divisor one digit. 
digit--;
divisor >>= 1;
Note: digit is useds to record how many times the current divisor of the original divisor. And divisor is the actual number we opearte on. 
while (digit >= 0) {
    if (dividend >= divisor ) {
        ret += (1 << digit);
        dividend -= divisor;
    }
    digit--;
    divisor >>= 1;
}

Some tricky skills: 
1. the sign of two numbers' product or divide. 
boolean is_neg = (dividend ^ divisor) >>> 31 == 1;
">>>" respresent we right shift the number 31 digits and fill those shifted digits with 0. 

2. inorder to make the uniform comparsion when we shift digits. (and the sign only affects the result's sign, not the abs () part.) We need to use the abs value of dividend and divisor in computation. To get the abs value, we shoul consider following corner cases:
2.1 divisor is 0, we return Integer.MAX_VALUE. 
if (divisor == 0)
    return Integer.MAX_VALUE;
    
2.2 dividend is Integer.MIN_VALUE(the abs() over it would result in overflow). we could substract it with divisor's abs value at first, thus we would not overflow.
if (dividend == Integer.MIN_VALUE) {
    dividend += Math.abs(divisor);
    if (divisor == -1) //note this corner case.
        return Integer.MAX_VALUE;
    ret ++; //rember to record the substraction in the result. 
}

2.3 iff the divisor is Integer.MIN_VALUE. 
2.3.1 iff the dividend is also Integer.MIN_VALUE, we should return 1;
2.3.2 iff the dividend is a Integer larger than Integer.MIN_VALUE, we should return 0. 
int ret = 0;
if (dividend == Integer.MIN_VALUE) {
    dividend += Math.abs(divisor);
    if (divisor == -1)
        return Integer.MAX_VALUE;
    ret ++;
}
if (divisor == Integer.MIN_VALUE) {
    return ret;
}
Note the logic at here is very elegant. 

The solution:

public class Solution {
    public int divide(int dividend, int divisor) {
        if (divisor == 0)
            return Integer.MAX_VALUE;
        boolean is_neg = (dividend ^ divisor) >>> 31 == 1;
        int digit = 0;
        int ret = 0;
        if (dividend == Integer.MIN_VALUE) {
            dividend += Math.abs(divisor);
            if (divisor == -1)
                return Integer.MAX_VALUE;
            ret ++;
        }
        if (divisor == Integer.MIN_VALUE) {
            return ret;
        }
        divisor = Math.abs(divisor);
        dividend = Math.abs(dividend);
        while (divisor <= (dividend >> 1)) {
            divisor <<= 1;
            digit++;
        }
        while (digit >= 0) {
            if (dividend >= divisor ) {
                ret += (1 << digit);
                dividend -= divisor;
            }
            digit--;
            divisor >>= 1;
        }
        return is_neg ? -1 * ret : ret; 
    }
}

 

转载于:https://www.cnblogs.com/airwindow/p/4289573.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值