官术网_书友最值得收藏!

第1章 整數

1.1 整數的基礎知識

整數是一種基本的數據類型。編程語言可能會提供占據不同內存空間的整數類型,每種類型能表示的整數的范圍也不相同。例如,Java中有4種不同的整數類型,分別為8位的byte(-27~27-1)、16位的short(-215~215-1)、32位的int(-231~231-1)和64位的long(-263~263-1)。

Java中的整數類型都是有符號整數,即如果整數的二進制表示的最高位為0則表示其為正數,如果整數的二進制表示的最高位為1則表示其為負數。有些語言(如C/C++)支持無符號整數。無符號整數無論二進制表示的最高位是0還是1,都表示其為一個正數。無符號的32位整數的范圍是0~232-1。

通常,編程語言中的整數運算都遵循四則運算規則,可以使用任意嵌套的小括號。需要注意的是,由于整數的范圍限制,如果計算結果超出了范圍就會產生溢出。產生溢出時運行不會出錯,但結果可能會出乎意料。如果除數為0,那么整數的除法在運行時將報錯。

面試題1:整數除法

題目:輸入2個int型整數,它們進行除法計算并返回商,要求不得使用乘號'*'、除號'/'及求余符號'%'。當發生溢出時,返回最大的整數值。假設除數不為0。例如,輸入15和2,輸出15/2的結果,即7。

分析:這個題目限制我們不能使用乘號和除號進行運算。一個直觀的解法是基于減法實現除法。例如,為了求得15/2的商,可以不斷地從15里減去2,當減去7個2之后余數是1,此時不能再減去更多的2,因此15/2的商是7。我們可以用一個循環實現這個過程。

但這個直觀的解法存在一個問題。當被除數很大但除數很小時,減法操作執行的次數會很多。例如,求(231-1)/1,減1的操作將執行232-1次,需要很長的時間。如果被除數是n,那么這種解法的時間復雜度為On)。我們需要對這種解法進行優化。

可以將上述解法稍做調整。當被除數大于除數時,繼續比較判斷被除數是否大于除數的2倍,如果是,則繼續判斷被除數是否大于除數的4倍、8倍等。如果被除數最多大于除數的2k倍,那么將被除數減去除數的2k倍,然后將剩余的被除數重復前面的步驟。由于每次將除數翻倍,因此優化后的時間復雜度是O(logn)。

下面以15/2為例討論計算的過程。15大于2,也大于2的2倍(即4),還大于2的4倍(即8),但小于2的8倍(即16)。于是先將15減去8,還剩余7。由于減去的是除數的4倍,減去這部分對應的商是4。接下來對剩余的7和除數2進行比較,7大于2,大于2的2倍(即4),但小于2的4倍(即8),于是將7減去4,還剩余3。這一次減去的是除數2的2倍,對應的商是2。然后對剩余的3和除數2進行比較,3大于2,但小于2的2倍(即4),于是將3減去2,還剩余1。這一次減去的是除數的1倍,對應的商是1。最后剩余的數字是1,比除數小,不能再減去除數了。于是15/2的商是4+2+1,即7。

上述討論假設被除數和除數都是正整數。如果有負數則可以將它們先轉換成正數,計算正數的除法之后再根據需要調整商的正負號。例如,如果計算-15/2,則可以先計算15/2,得到的商是7。由于被除數和除數中有一個負數,因此商應該是負數,于是商應該是-7。

將負數轉換成正數存在一個小問題。對于32位的整數而言,最小的整數是-231,最大的整數是231-1。因此,如果將-231轉換為正數則會導致溢出。由于將任意正數轉換為負數都不會溢出,因此可以先將正數都轉換成負數,用前面優化之后的減法計算兩個負數的除法,然后根據需要調整商的正負號。

最后討論可能的溢出。由于是整數的除法并且除數不等于0,因此商的絕對值一定小于或等于被除數的絕對值。因此,int型整數的除法只有一種情況會導致溢出,即(-231)/(-1)。這是因為最大的正數為231-1,231超出了正數的范圍。

在全面地分析了使用減法實現除法的細節之后,我們可以開始編寫代碼。參考代碼如下所示:

上述代碼中的0x80000000為最小的int型整數,即-231,0xc0000000是它的一半,即-230

函數divideCore使用減法實現兩個負數的除法。當除數和被除數中有一個負數時,商為負數。因此,在使用函數divideCore計算商之后,需要再根據除數和被除數的負數的個數調整商的正負號。

主站蜘蛛池模板: 健康| 怀仁县| 大关县| 乌拉特中旗| 乐平市| 甘孜县| 当涂县| 凭祥市| 紫云| 普安县| 嘉兴市| 辉县市| 贵阳市| 桐城市| 重庆市| 纳雍县| 贡觉县| 读书| 阳泉市| 宜川县| 杭锦后旗| 峨眉山市| 师宗县| 五大连池市| 瑞昌市| 慈利县| 车致| 三河市| 广汉市| 抚州市| 澄迈县| 南岸区| 平顺县| 花莲县| 湖口县| 遂昌县| 呼伦贝尔市| 光山县| 米林县| 白玉县| 武冈市|