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

    题目:

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

    If it is overflow, return MAX_INT.

    链接:https://leetcode.com/problems/divide-two-integers/#/description

    4/13/2017

    没做出来,时间超了

    以下是我没做出来的答案,通不过OA

     1 public class Solution {
     2     public int divide(int dividend, int divisor) {
     3         if (divisor == 0) return Integer.MAX_VALUE;
     4         if (dividend == 0 || dividend > 0 && divisor > 0 && dividend < divisor || dividend < 0 && divisor < 0 && dividend > divisor) return 0;
     5         if (divisor == 1) return dividend;
     6         else if (divisor == -1) {
     7             if (dividend == Integer.MIN_VALUE) return Integer.MAX_VALUE;
     8             return -dividend;
     9         }
    10         if (dividend == divisor) return 1;
    11         else if (dividend == -divisor) return -1;
    12 
    13         int sign = 1;
    14 
    15         if (dividend > 0 && divisor < 0) {
    16             divisor = -divisor;
    17             sign = -1;
    18         } else if (dividend < 0 && divisor > 0) {
    19             dividend = -dividend;
    20             sign = -1;
    21         }
    22 
    23         int initDivisor = divisor;
    24         int quotient = 0;
    25         int times = 0;
    26 
    27         while (dividend >= initDivisor) {
    28             while (dividend > divisor) {
    29                 divisor <<= 1;
    30                 if (times == 0) times = 1;
    31                 else             times <<= 1;
    32             }
    33             quotient += times;
    34             dividend -= divisor >> 1;
    35             divisor = initDivisor;
    36             times = 0;
    37         }
    38         return sign == 1? quotient: -quotient;
    39     }
    40 }

    需要再研究这道题,可以参考:

    http://www.cnblogs.com/yrbbest/p/4435159.html

    别人的做法,很喜欢这么详细的解释。

    不过要注意他在中间把signed int变成了unsigned int解决了中间计算溢出的问题,我认为最好还是不要这么做。

    we assure the factor ret's binary fomula is

    ret = a0 + a1*2 + a2*2^2 + ...... + a29*2^29 + a30*2^30 + a31*2^31; ai = 0 or 1, i = 0......31

    the dividend B and divisor A is non-negative, then

    A(a0 + a1*2 + a2*2^2 + ...... + a29*2^29 + a30*2^30 + a31*2^31) = B; Eq1

    (1) when Eq1 divided by 2^31, we can get A*a31 = B>>31; then a31 = (B>>31)/A;

    if (B>>31) > A, then a31 = 1; else a31 = 0;

    (2) when Eq1 divided by 2^30, we can get A*a30 + A*a30*2 = B>>30; then a30 = ((B>>30) - a30*A*2)/A; and (B>>30) - a31*A*2 can be rewritten by (B-a31*A<<31)>>30, so we make B' = B-a31*A<<31, the formula simplified to a30 = (B'>>30)/A

    if (B'>>31) > A, then a30 = 1; else a30 = 0;

    (3) in the same reason, we can get a29 = ((B-a31*A<<31-a30*A<<30)>>29)/A, we make B'' = B' - a30*A<<30, the formula simplified to a29 = (B''>>29)/A;

    do the same bit operation 32 times, we can get a31 ..... a0, so we get the ret finally.

    the C solution with constant time complexity

     1 int divide(int dividend, int divisor) {
     2     //special cases
     3     if(divisor == 0 || (dividend == INT_MIN && divisor == -1))
     4         return INT_MAX;
     5     
     6     // transform to unsigned int
     7     bool sign = (dividend > 0)^(divisor > 0);
     8     unsigned int A = (divisor < 0) ? -divisor : divisor;
     9     unsigned int B = (dividend < 0) ? -dividend : dividend;
    10     int ret = 0;
    11     
    12     // shift 32 times
    13     for(int i = 31; i >= 0; i--)
    14     {
    15         if((B>>i) >= A)
    16         {
    17             ret = (ret<<1)|0x01;
    18             B -= (A<<i);   // update B
    19         }
    20         else
    21             ret = ret<<1;
    22     }
    23     
    24     if(sign)
    25         ret = -ret;
    26     
    27     return ret;
    28 }

    https://discuss.leetcode.com/topic/17600/32-times-bit-shift-operation-in-c-with-o-1-solution

    更多讨论:

    https://discuss.leetcode.com/category/37/divide-two-integers 

    4/27/2017

    36ms, 97%

    自己重新做了一遍并且参考别人的答案。

    思路:

    按照之前的意思,通过计算最高位的系数来算答案。

    1. 当除数和被除数没有Integer.MIN_VALUE时,dividend, divisor都转化成positive来计算。

    当前剩余dividend >>i 和divisor比较,如果大于divisor,答案*2 + 1,并且dividend减去divisor;如果小于divisor,答案*2,不做额外加减。最后一步通过最初的符号来判断

    2. 当除数和被除数有一个是Integer.MIN_VALUE时

    转化为positive会造成overflow,需要用负数来计算。

    当除数divisor是Integer.MIN_VALUE,答案只有1(被除数也是MIN_VALUE)或者0(其他所有任何数)

    其他情况,将divisor也变成负数,所以这时除数和被除数都是负数。

    负数的判断,谁的值大,谁的绝对值小,根据第1中情况

    当前剩余dividend >>i 和divisor比较,如果大于divisor,答案*2 + 1,并且dividend减去divisor;如果小于divisor,答案*2,不做额外加减。最后一步通过最初的符号来判断

    当dividend >> i大于divisor时,其实当前高位应该是0,答案*2不做额外加减,当小于divisor时,dividend>>i绝对值大,当前高位应该是1,答案*2 + 1.

    特别重要的一点,移位运算,建议强制加括号,运算级太低了

    第43行,注意,其实dividend的值是越来越大的(绝对值越来越小)不会溢出,因为divisor是负数,divisor << i变成了一个绝对值更大的负数。dividend的值也越来越从负的接近于0

     1 public class Solution {
     2     /**
     3      * @param dividend the dividend
     4      * @param divisor the divisor
     5      * @return the result
     6      */
     7     public int divide(int dividend, int divisor) {
     8         // Write your code here
     9         if (divisor == 0 || dividend == Integer.MIN_VALUE && divisor == -1) {
    10             return Integer.MAX_VALUE;
    11         } else if (dividend == 0) {
    12             return 0;
    13         } else if (divisor == 1) {
    14             return dividend;
    15         } else if (divisor == -1) {
    16             return -dividend;
    17         }
    18 
    19         boolean isNegative = (dividend > 0)^(divisor > 0);
    20 
    21         int ret = 0;
    22         if (dividend != Integer.MIN_VALUE && divisor != Integer.MIN_VALUE) {
    23             dividend = Math.abs(dividend);
    24             divisor = Math.abs(divisor);
    25             for (int i = 31; i >= 0; i--) {
    26                 if ((dividend >> i) >= divisor) {
    27                     ret = (ret << 1) + 1;
    28                     dividend -= (divisor << i);
    29                 } else {
    30                     ret <<= 1;
    31                 }
    32             }
    33         } else {
    34             if (divisor == Integer.MIN_VALUE) {
    35                 return dividend == Integer.MIN_VALUE? 1: 0;
    36             }
    37             if (divisor > 0) {
    38                 divisor = - divisor;
    39             }            
    40             for (int i = 31; i >= 0; i--) {
    41                 if ((dividend >> i) <= divisor) {
    42                     ret = (ret << 1) + 1;
    43                     dividend -= (divisor << i);
    44                 } else {
    45                     ret <<= 1;
    46                 }
    47             }            
    48         }
    49         return isNegative? -ret: ret;
    50     }
    51 }
  • 相关阅读:
    ORA-12170 TNS 连接超时
    判断字符串里面是否包含汉字
    关于Try/Catch 代码块
    SOLID 原则
    整洁代码原则
    装箱 拆箱
    存储过程优缺点
    ANTLR Tool version 4.4中使用ANTLR 4.7.1
    The Apache Tomcat installation at this directory is version 8.5.40. A Tomcat 8.0 installation is expected.
    实现功能:构建一个JSON到XML的翻译器。
  • 原文地址:https://www.cnblogs.com/panini/p/6706919.html
Copyright © 2011-2022 走看看