zoukankan      html  css  js  c++  java
  • LeetCode-29. Divide Two Integers

    一、问题描述

      实现两个int数的相除,返回它们相除的int值,但是不能使用乘法、除法、和mod运算。

    二、问题解决

      最开始能想到的方法就是不断用被除数去减除数,等到被除数小于0的时候相减了多少轮就是两数相除的int值,但是一个很大的数除以一个很小的数可能会超时,实验一下,果然会超时。

      要解决这个问题还需要使用减法,只是要想办法提高相减的次数。这里使用右移运算,假设被除数为M,除数为N,M第一次减去N,第二次减去N<<1,第三次减去(N<<1)<<1,使被除数快速的减小,当发现N右移n次后比M大的时候,用M减去N右移n-1次的结果,然后又重复上面的寻找n的步骤。由于每次是从N开始,相当于每次N*2的方式增大,但是有不用到乘法。

      举个例子:假设使用M=15除N=3,第一次使用15-3,发现12大于3,然后又使用15-(3<<1)=9,发现9还是比3大,然后用15-((3<<1)<<1)=3,发现还是不小于3,于是使用15-(((3<<1)<<1)<<1)=-9,是小于3的,于是令M=15-((3<<1)<<1)=3,次数n=n+(1<<1)<<1=4(初始n=0)。再使用M(现在等于3)去减N(还是从初始N开始),发现M-N<N,所以这次不用右移,n=n+1,所以n=5,即两数相除等于5。

      代码实现:

    int divide(int dividend, int divisor) {
        if (divisor == 0 || (dividend == INT_MIN && divisor==-1))return INT_MAX;
        int sig = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;
        int time = 0;
        long long d1 = labs(dividend);
        long long d2 = labs(divisor);
        while (d1 >= d2) {
            long long temp = d2, a = 1;
            while (d1 >= (temp << 1)) {
                temp <<= 1;
                a <<= 1;
            }
            d1 -= temp;
            time += a;
        }
        return sig == 1 ? time : -time;
    }
    
    int main()
    {
        cout << divide(1,-1) << endl;
    
        system("pause");
        return 0;
    }

     三、问题思考

      1、在这次的代码中,对dividend和divisor求绝对值的时候使用了long long类型,但凡考虑绝对值的情况一定考虑INT_MAX和INT_MIN的情况,这里如果对INT_MIN去绝对值就会溢出,所以使用long long类型。

      2、总结一下c++各个数据类型的范围:

    数据类型名称 字节数 别名 取值范围
    int 4 signed,signed int 操作系统决定,即与操作系统的"字长"有关(一般为4个字节)
    unsigned int 4 unsigned 由操作系统决定,即与操作系统的"字长"有关(一般为4个字节)
    __int8 1 char,signed char –128 到 127
    __int16 2 short,short int,signed short int –32,768 到 32,767
    __int32 4 signed,signed int –2,147,483,648 到 2,147,483,647
    __int64 8 –9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
    bool 1 false 或 true
    char 1 signed char –128 到 127
    unsigned char 1 0 到 255
    short 2 short int,signed short int –32,768 到 32,767
    unsigned short 2 unsigned short int 0 到 65,535
    long 4或8 long int,signed long int –2,147,483,648 到 2,147,483,647
    long long 8 none (but equivalent to __int64) –9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
    unsigned long 4 unsigned long int 0 到 4,294,967,295
    enum * 由操作系统决定,即与操作系统的"字长"有关
    float 4 3.4E +/- 38 (7 digits)
    double 8 1.7E +/- 308 (15 digits)
    long double 8 1.7E +/- 308 (15 digits)
    wchar_t 2 __wchar_t 0 到 65,535

      在32位系统之中,long为32位,64位系统之中,long为64位。int始终为32位。

      3、代码中在右移的时候使用变量a,a也是long long 类型,发现使用int值时会超时,而使用long long就不会。思考的是会不会64位系统之中64位数据移位运算会比32位数据移位运算更快?随手下了下面的例子:

    long long looptime = 100000000;
    
    void test2() {
        long long a;
        for (int t = 0; t < looptime; t++) {
            for (auto i = 0; i < 30; i++) {
                a << i;
            }
        }
    }
    
    void test1() {
        int a;
        for (int t = 0; t < looptime; t++) {
            for (auto i = 0; i < 30; i++) {
                a << i;
            }
        }
    }
    
    int main()
    {
        double start1, stop1, duration1, start2, stop2, duration2;
        start1 = clock();
        test1();
        stop1 = clock();
        start2 = clock();
        test2();
        stop2 = clock();
        duration1 = ((double)(stop1 - start1)) / CLK_TCK;
        duration2 = ((double)(stop2 - start2)) / CLK_TCK;
        cout << duration1 << " "<< duration2 <<endl;
    
        system("pause");
        return 0;
    }

       发现事实好像并不是这样,和long long 还是int类型无关,倒是先算计算的一定比后计算的快,即duration1小于duration2,于是我改成两个测试函数一样,都使用int或都使用long long,发现还是这个结果。

      我又使用同一函数,时刻1使用int值,时刻2使用long long,发现结果也并不是这样,使用long long时间又是也高过int。

      没搞清楚这是为什么,希望以后能弄明白,现在先记在这里。

  • 相关阅读:
    不知如何摧毁Kendo UI for jQuery小部件?这份指南不得不看
    MyEclipse导航代码第二弹,Java开发更便捷
    索引扫描与索引查找区别
    Chrome使用技巧
    什么是中台?所有的中台都是业务中台
    跨域资源共享CORS详解
    多线程之入门起步(三)
    聊天程序——基于Socket、Thread (二)
    多线程的相关概念(一)
    使用BCP实用工具导出导入数据
  • 原文地址:https://www.cnblogs.com/likaiming/p/8316955.html
Copyright © 2011-2022 走看看