Rikou Diary Sword Finger Offer II 001

1. Topic

LeetCode Swordsman Offer II 001. Integer Division

1.1 Question meaning

Simulates division without multiplication and division signs

1.2 Analysis

First of all, analog division can use subtraction, and the result can be obtained by continuously subtracting divisors. In the worst case, such time complexity is (2^31) (ie INT_MIN / 1), and it will definitely not pass (probably around 1e6 to pass oj).
If you know the fast power, you can think of a similar fast power method to find b, 2b, 4b, 8b... and then you can find the divisor multiples that can be subtracted each time by means of dichotomy.

-2^31 <= a, b <= 2^31 - 1
b != 0

Then talk about the details, because it may involve a and b with different signs, so consider changing a and b into the same sign (otherwise there will be problems with the sign after the multiple of the divisor is subtracted each time, you can simply give an example yourself)
At the beginning, I changed both numbers into positive signs, but there was a problem? Why, because the int complement range has one more negative number than the positive number, taking the negative will overflow. At the beginning, I used long to save, but it didn't meet the requirements of the topic. Then think that only the case of different signs needs special treatment. If both numbers are converted into negative numbers, the result is still the same (because ( − a ) / ( − b ) = a / b (-a)/(-b)=a/b(a)/(b)=a / b , and there will be no overflow.

In addition, in the case of overflow in the title, only INT_MIN/(-1) will overflow, and special judgment is required.

The details for the bisection are written in the code comments.

1.3 My solution

class Solution {
    
    
public:
    int divide(int a, int b) {
    
    
        // 结果是否需要加负号
        int negFlag = 0;
        if(a==INT_MIN && b==-1)
            // 特判溢出的情况
            return INT_MAX;
        if(a>0){
    
    
            // 将被除数变成负数
            a = -a;
            // 使用异或记录下符号变化的次数
            // 奇数次则说明结果需要添加负号
            negFlag ^= 1;
        }
        if(b>0){
    
    
            // 被除数变成负数
            b = -b;
            negFlag ^= 1;
        }
        // dichotomy
        // b 2b 4b 8b 16b 32b
        // 利用二分法(类似快速幂)
        // 一个记录下除数的倍数 b 2b 4b 8b .....
        // 一个记录下对应的系数 1 2 4 8 ......
        // 为什么要记系数?
        // 因为不能使用乘法,根据下标难以快速得到系数
        vector<long> mult; // store b 2b  ......
        vector<long> base; // store 1 2 4 8 ......
        mult.emplace_back(b);
        base.emplace_back(1);
        // generate mult and base
        // 生成除数的倍数
        // 直到除数的倍数超过被除数a
        while(mult.back()>=a){
    
    
            mult.emplace_back(mult.back() + mult.back() );
            base.emplace_back(base.back() + base.back() );
        }
        // compute ans
        long res = 0;
        int n = mult.size();
        // 要注意这里头mult中的 b 2b 4b ....是降序排列
        // 因为b是负数
        while(a <= mult[0]){
    
    
            // dichotomy
            // find ind: mult[ind] < a && mult[ind-1] >= a 
            // 找到第一个比剩余的a小的数
            int l=0, r=n-1, mid = (l+r)/2;
            while(l<r){
    
    
                // 细节:怎么判断是否这两个边界会造成死循环
                // 死循环的根本是最后 l r相近的时候,mid不会继续改变
                // 举例 比如 l=0, r=1, mid= 0,然后再分支中l=mid,这类情况
                // 关键在于不能缩小范围的那个分支里头,比如下面是r=mid
                // 可以举具体例子代入,康康是否会出现死循环,
                // 在下面代码情况中是不会的l=0, r=1, mid= 0,只有可能r=0,或者l=1都能缩小范围到退出循环
                if(mult[mid] < a){
    
    
                    r = mid;
                }
                else{
    
    
                    l = mid + 1;
                }
                mid = (l+r) / 2;
            }
            res += base[mid-1];
            a -= mult[mid-1];
        }
        // 注意符号
        if(negFlag)
            return int(-res);
        return res;
    }
};

1.4 Reflection on learning problem solutions

My solution:
time complexity O( ( log ( a / b ) ) 2 (log (a/b))^2(log(a/b))2 ),
when calculating the multiple of the divisor, it needs at most log(a/b) + 1 times
. When calculating the division result, it needs at most log(a/b) + 1 cycle. In the cycle, it is necessary to find the value that can be subtracted every time. Multiples of divisors, using binary is also log(a/b) + 1 lookups,
and a block is O(( log ( a / b ) ) 2 (log (a/b))^2(log(a/b))2 )
The space complexity is O(log(a/b)), and the multiples of the divisor and the corresponding coefficients need to be stored

Learning problem solution:
In the problem solution, change the solution target, change to Z×Y≥X>(Z+1)×Y, and also use the binary method to find Z, which makes the space complexity in the problem solution become O(1), wonderful . In addition, it is emphasized that the details (Z+1)×Y may overflow and need to be deformed again (this detail must be missed if I write it). The
class binary search in the solution is not very clear, and it feels a bit similar to my writing.

In addition, I found that there is no coefficient stored in the solution, because directly using the bit operation 1<<i can express the coefficient corresponding to the subscript i, fine, learned again.

1.5 bug diary

1.5.1 Negative overflow situation

1.5.2 Division result overflow

2. Postscript

Only sharing my own thoughts, comments and pointers are very grateful

рекомендация

отblog.csdn.net/qq_51204877/article/details/131260319
рекомендация