Tuesday, November 18, 2014

Divide Two Integers

Medium difficulty question with all kinds of corner cases, which bump the difficulty to hard.
Leetcode link.

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

A:
I managed to crack it by myself the first time I fought through leetcode, but not this time. I had to go back and check what I had done. :( shame

The idea is simple. Shifting operation is your friend. Test case \( \frac{700}{51} \): \[ 700 = 2^3 \cdot 51 + 292 \\ 292 = 2^2 \cdot 51 + 88 \\ 88 = 2^0 \cdot 51 + 37 \] We stop at 37 because \( 37 < 51 \).
All right that's it. Answer is \( 2^3+2^2+2^0 = 13 \).

Corner cases' time!
  1. Dividend / Divisor == 0?
  2. Dividient or Divisor is negative? or both are negative?
  3. This is about integer, so what do you consider? Overflow! \(Dividend/divisor == INT\_MIN/INT\_MAX\) or \(-INT\_MIN/-INT\_MAX ?\)
First one is easy to handle. Notice when divisor is 0, throwing an exception is what you should do. But OJ says you can simply return 0. All right then.
Second one is tricky to handle. Judge the sign! Then use \( abs \) function to do it! Yeah, you'll see there is one loose end soon...
Third one? I cheated... I used long long type to handle everything. If I don't, the loose end in second question will reveal: The devil \( abs(INT\_MIN) \) !  ideone says \( abs(INT\_MIN) == INT\_MIN \), someone on leetcode forum reports \( abs(-2147483647) = -2147483644 \) or something like that. Anyway, I cheated...

My code is as follow. Not the best code though. Feel free to play it here.
pair<long long, long long> decompose(long long a, long long b) {        // DONT MAKE a < b
    int k = 0;                                  // decompose a/b = 2^k + d, d < 2^k
    while (b < a) {
        b <<= 1;
        k++;
    }
    if (b == a) return make_pair(k, 0);
    return make_pair(--k, a - (b>>1));
}

int divide(int dvd, int dvs) {
    if (dvs == 0) throw overflow_error("Divide by zero exception");
    if (dvd == 0) return 0;

    long long ldvd, ldvs;
    ldvd = abs((long long)dvd); ldvs = abs((long long)dvs);
    if (ldvd < ldvs) return 0;

    long long ret = 0;
    pair<long long, long long> kb;
    do{
        kb = decompose(ldvd, ldvs);
        ret += 1 << kb.first;
        ldvd = kb.second;
    } while (kb.second >= ldvs);
    return ((dvd>>31) == (dvs>>31)) ? ret : (~ret + 1);
}

No comments:

Post a Comment