給定兩個整數,被除數 dividend 和除數 divisor。將兩數相除,要求不使用乘法、除法和 mod 運算符。 返回被除數 dividend 除以除數 divisor 得到的商。 示例 1: 輸入: dividend = 10, divisor = 3 輸出: 3 示例 2: 輸入: dividend = 7, divisor = -3 輸出: -2 說明: 被除數和除數均爲 32 位有符號整數。 除數不爲 0。 假設我們的環境只能存儲 32 位有符號整數,其數值範圍是 [−231, 231 − 1]。本題中,如果除法結果溢出,則返回 231 − 1。
思路一:
就是小學時候還沒學除法的時候用的辦法,用被減數去重複減去減數,但是毫無疑問這種辦法效率並不高。如果其中一個Integer.MAX_VALUE
另一個是1,就得循環那麼多次,顯然這不是做這個的好的解決辦法。
思路二:
那麼除了一個個將還有什麼效率好的辦法呢,我開始也想用移位,但是還是沒能想出來,畢竟太菜。
因爲dividend即被減數規定了範圍,那麼能夠被減數能整除的最大整數就是2的31次方,那麼,從2的31依次開始試探,試探數之間的關係就是二倍關係。二倍關係就跟移位操作掛上夠了,左移相當於X2,右移相當於/2,如果被除數/2^i(i=31,30...1,0)的商是大於除數的,則本題答案可以加上此時的2^i,同時,將被減數減去2^i,當然,在此之前,爲了避免兩個數異號而帶來的不便,事先將兩個數字做一下絕對值處理就好了。
然後根據這條思路寫出瞭如下代碼:
class Solution { public int divide(int dividend, int divisor) { boolean is = false; int res = 0; if(dividend==0) return 0; if(divisor==1) return dividend; if(dividend==Integer.MIN_VALUE&&divisor==-1) return Integer.MAX_VALUE; if((dividend<0&&divisor>0)||(dividend>0&&divisor<0)) is = true;//如果異號 long divd = Math.abs(dividend); long divs = Math.abs(divisor); for(int i = 31;i>=0;i--){ if((divd>>i)>=divs){ res+=1<<i; divd-=divs<<i; } } return is?-res:res;//異號結果變負 } }
測幾個用例,誒好像沒問題。提交,WA(哭)
輸入: -2147483648 2 輸出: 0 預期: -1073741824
一時半會沒想通,直到看見Math.abs()的源代碼:
/** * Returns the absolute value of an {@code int} value. * If the argument is not negative, the argument is returned. * If the argument is negative, the negation of the argument is returned. * * <p>Note that if the argument is equal to the value of * {@link Integer#MIN_VALUE}, the most negative representable * {@code int} value, the result is that same value, which is * negative. * * @param a the argument whose absolute value is to be determined * @return the absolute value of the argument. */ public static int abs(int a) { return (a < 0) ? -a : a; }
如果是Integer.MIN_VALUE,不返回絕對值,返回本身。。所以這裏算是一個小坑點了,做法就是,將int轉化爲long來去絕對值(因爲本題規定了被除數範圍,如果沒有規定,強制轉爲long也可能沒用。。)
最後的AC代碼:
class Solution { public int divide(int dividend, int divisor) { boolean is = false; int res = 0; if(dividend==0) return 0; if(divisor==1) return dividend; if(dividend==Integer.MIN_VALUE&&divisor==-1) return Integer.MAX_VALUE; if((dividend<0&&divisor>0)||(dividend>0&&divisor<0)) is = true;//如果異號 long divd = Math.abs((long)(dividend)); long divs = Math.abs((long)(divisor)); for(int i = 31;i>=0;i--){ if((divd>>i)>=divs){ res+=1<<i; divd-=divs<<i; } } return is?-res:res;//異號結果變負 } }