Divide Two Integers -- with detailed code and ideas

Posted by quecoder on Sat, 11 Dec 2021 15:47:35 +0100

0 results

1 topic

2 ideas

First, interpret the topic and deal with special cases (the value range of int is (- 2 ^ 31 (- 2147483648) ~ 2 ^ 31-1)),

  • 1, when the divisor is equal to int_ When min, prevent the benefit when the divisor is 1;
  • 2. When the divisor is INT_MIN, the divisor is not equal to int_ It returns 0 when min, otherwise it returns 1.

Next, solve the division calculation:

2.1 train of thought 1

The divisor is approximated by multiplication, such as the formula of x/y=z. when calculating z, x > = y * z can be used to approximate x, and z can be accumulated by the power of 2, so as to find the maximum z satisfying the inequality.

For example:

59 / 3 = z
⇒ 59 = 3*z
⇒ x*z <= 59
⇒ 3 * (2^4 + 2^1 + 2^0 )
⇒ 3* ( 16 + 2 + 1)
⇒ 57
  
 and z =  (2^4 + 2^1 + 2^0 ) = 10011 (19)

According to the idea of writing the program below, get it first z All possible cases of value,
z = {3*2^0,  3*2^1,  3*2^2,  3*2^3,  3*2^4} ,Because 3 * (2^5) > 59 So the future is not included.

calculation z Value( ans = 0): 
1, 59 - 3*2^4 = 11, Result set ans = ans + 1<<4 = 16
2, 11 - 3*2^1 = 5, Result set ans = ans + 1<< 1 = 16 + 2 = 18
3, 5 - 3*2^0 = 2, Result set ans = ans + 1<< 0 = 16 + 2  + 1= 19(That is, binary 10011)
4,2 < 3 ,The loop terminates and returns the result ans. 


For writing code, finding z solves the problem.

  • 1. Use the vector to store the multiple of 3 (increasing by the power of 1, 2, 4, 8... Etc., because any non-zero number can be divided into the sum of the power of 2, which greatly increases the operation speed) less than or equal to the value of x[ ⚠️: The sequence number in the vector is equal to the sub idempotent of 2];
  • 2. Subtract the multiple of the largest 3 in the vector from the divisor to obtain the new divisor, and then judge whether the multiple of the remaining 3 in the vector is less than or equal to the new divisor. If the conditions are met, add 1 to the result set, shift the sequence number value of the multiple in the vector left [equivalent to adding the multiple of 3], and repeat two until the conditions are not met.

⚠️: In order to avoid writing codes in two cases to deal with negative numbers and positive numbers (negative numbers have one more bit than positive numbers), both numbers are converted into negative numbers to deal with them. The above cases describe positive numbers. When they are negative numbers, change the inequality symbol.

2.2 train of thought 2

Here, we assume that both numbers are negative numbers. According to x/y = z, we get y * z < = x < = y * (z + 1). Therefore, we can use the dichotomy to find the maximum z index and make the equation hold.

use Fast multiplication To simulate multiplication, and then use the dichotomy to call fast multiplication, and the result is constantly approaching the z value.

Quick multiply template:

    int multiply(int A, int B) {
        int ans = 0;
        for(; B != 0; B >>= 1){
            if(B & 1){
                ans += A;
            }
            A <<= 1;
        }
        return ans;
    }

Rewrite the fast multiplication template for dichotomy to determine whether x * y > = y is true:

        auto quickAdd = [](int y, int z, int x) {
            //It is necessary to judge whether Z * y > = x is true
            //For example, when calculating 3 * 7, y = [-3, -6, -12] res = [-3, -9, -12, -21]
            int res = 0;
            for(; z != 0; z >>= 1){
                if(z & 1){//Here we deal with the case where the multiplier is odd
                    //Ensure that res > = x,
                    // Here, the res value is calculated in advance, so the new res value is equal to res + y
                    if(res < x - y){ //To prevent overflow, the res value is calculated in advance and the inequality is transformed
                        return false;
                    }
                    res += y;
                }
                //The following deals with the case where the multiplier is even
                //Ensure that y + Y > = x, and the y value here is the subsequent addend
                if(y < x - y && z != 1){//Anti overflow, calculate the y value in advance and transform the inequality
                    return false;
                }
                y <<= 1;
            }
            return true;
        };

To prevent overflow, modify some of the above Codes:

                //The following deals with the case where the multiplier is even
                //Ensure that y + Y > = x, and the y value here is the subsequent addend
                if(y < x - y && z != 1){//Anti overflow, calculate the y value in advance and transform the inequality
                    return false;
                }
                y <<= 1;

Replace with:

                //The following deals with the case where the multiplier is even
                //Ensure that y + Y > = x, and the y value here is the subsequent addend
                if(z != 1){//Anti overflow, calculate the y value in advance and transform the inequality
                    if(y < x - y) return false;
                    y += y;
                }

Then use the dichotomy to approximate the z value. Because z must be positive, let the left and right bounds of z value be 1 and INT_MAX,

        int left = 1, right = INT_MAX, ans = 0;
        while(left <= right){
            //The following formula is equivalent to mid = (left + right)/2,
            //However, it is rewritten to prevent overflow
            int mid = left + ((right - left)>>1);
            bool check = quickAdd(divisor, mid, dividend);
            if(check){
                ans = mid;
                //Prevent overflow
                if (mid == INT_MAX) {
                    break;
                }
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }

3 code

3.1 train of thought 1

class Solution {
public:
    int divide(int dividend, int divisor) {
        // Consider the case where the divisor is the minimum
        if(dividend == INT_MIN){ //-2^31(-2147483648)~2^31-1
            if(divisor == -1) return INT_MAX;
            if(divisor == 1) return INT_MIN;
        }

        // Consider the case where the divisor is the minimum
        if(divisor == INT_MIN){
            return dividend == INT_MIN ? 1 : 0;
        }

        //Unify the divisor and divisor into negative numbers (because negative numbers are 1 greater than the absolute value of positive numbers)
        int sign = ((divisor >> 31) ^ (dividend >> 31))  == 0 ? 1 : -1;
        dividend = (dividend < 0) ? dividend : -dividend;
        divisor = (divisor < 0) ? divisor : -divisor;

        vector<int> candidates{divisor};

        while(candidates.back() >= dividend - candidates.back()){//Prevent overflow
            candidates.emplace_back(candidates.back() + candidates.back());
        }

        int ans = 0;
        for(int i = candidates.size() -1;i >= 0; --i){
            if(candidates[i] >= dividend){
                ans += (1 << i);
                dividend -= candidates[i];
            }
        }

        return sign == 1? ans: -ans;
    }
};

3.2 train of thought II

class Solution {
public:
    int divide(int dividend, int divisor) {
        // Consider the case where the divisor is the minimum
        if(dividend == INT_MIN){ //-2^31(-2147483648)~2^31-1
            if(divisor == -1) return INT_MAX;
            if(divisor == 1) return INT_MIN;
        }

        // Consider the case where the divisor is the minimum
        if(divisor == INT_MIN){
            return dividend == INT_MIN ? 1 : 0;
        }

        //Unify the divisor and divisor into negative numbers (because negative numbers are 1 greater than the absolute value of positive numbers)
        bool sign = ((divisor >> 31) ^ (dividend >> 31)) == 0;
        dividend = (dividend < 0) ? dividend : -dividend;
        divisor = (divisor < 0) ? divisor : -divisor;

        // Fast multiplication
        auto quickAdd = [](int y, int z, int x) {
            //It is necessary to judge whether Z * y > = x is true
            //For example, when calculating 3 * 7, y = [-3, -6, -12] res = [-3, -9, -12, -21]
            int res = 0;
            for(; z != 0; z >>= 1){
                if(z & 1){//Here we deal with the case where the multiplier is odd
                    //Ensure that res > = x,
                    // Here, the res value is calculated in advance, so the new res value is equal to res + y
                    if(res < x - y){ //To prevent overflow, the res value is calculated in advance and the inequality is transformed
                        return false;
                    }
                    res += y;
                }
                //The following deals with the case where the multiplier is even
                //Ensure that y + Y > = x, and the y value here is the subsequent addend
                if(z != 1){//Anti overflow, calculate the y value in advance and transform the inequality
                    if(y < x - y) return false;
                    y += y;
                }
               
            }
            return true;
        };

        int left = 1, right = INT_MAX, ans = 0;
        while(left <= right){
            //The following formula is equivalent to mid = (left + right)/2,
            //However, it is rewritten to prevent overflow
            int mid = left + ((right - left)>>1);
            bool check = quickAdd(divisor, mid, dividend);
            if(check){
                ans = mid;
                //Prevent overflow
                if (mid == INT_MAX) {
                    break;
                }
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return sign ? ans : -ans;
    }
};

Topics: Algorithm leetcode