[LeetCode解題攻略] 29. Divide Two Integers

更新於 發佈於 閱讀時間約 9 分鐘

題目描述

實作一個函數 divide(dividend, divisor),計算兩個整數 dividenddivisor 的商,並返回其結果。

注意:不允許使用乘法、除法和取模運算子。

條件限制

  1. 如果結果超出 32 位整數範圍 [-2^31, 2^31 - 1],則返回 2^31 - 1 或 -2^31。
  2. 被除數 dividend和除數 divisor的範圍是 [-2^31, 2^31 - 1],且除數不為 0。

範例 1:

輸入

dividend = 10, divisor = 3

輸出

3

解釋:10 除以 3,商為 3。

範例 2:

輸入

dividend = 7, divisor = -3

輸出

-2

解釋:7 除以 -3,商為 -2。

範例 3:

輸入

dividend = -2147483648, divisor = -1

輸出

2147483647

解釋:結果超出 32 位整數範圍,返回 2^31 - 1。


解題思路

要解決這道題,我們需要考慮以下幾個方面:

  1. 符號處理
    • 商的符號由被除數和除數的符號決定,兩者異號則商為負數。
  2. 模擬除法
    • 使用減法或位運算來模擬除法運算。
  3. 邊界條件
    • 如果結果超出 32 位整數範圍,需返回邊界值。
    • 特殊情況如 dividend = -2^31, divisor = -1。

解法一:減法模擬

思路

我們可以用多次減法來模擬除法運算:

  1. 不斷從被除數中減去除數,計算可以減去的次數。
  2. 注意符號的處理。

詳細步驟

  1. 紀錄結果的符號(正負)。
  2. 取絕對值處理,簡化計算。
  3. 使用一個迴圈不斷從被除數中減去除數,直到被除數小於除數。
  4. 檢查結果是否超出 32 位整數範圍。

程式碼實現

class Solution:
def divide(self, dividend: int, divisor: int) -> int:
if dividend == -2**31 and divisor == -1:
return 2**31 - 1 # 處理溢出情況

# 確定結果的正負
negative = (dividend < 0) ^ (divisor < 0)

# 取絕對值進行計算
dividend, divisor = abs(dividend), abs(divisor)

result = 0
while dividend >= divisor:
dividend -= divisor
result += 1

# 恢復符號
result = -result if negative else result

return max(-2**31, min(result, 2**31 - 1))

時間與空間複雜度

  • 時間複雜度:O(n),其中 n=商值,因為每次減去一個除數。
  • 空間複雜度:O(1)。

解法二:倍增減法

思路

用單次減法效率較低,尤其是被除數很大時。我們可以採用指數倍增的方式來加速:

  1. 每次減去當前除數的倍數(例如 2⋅除數,4⋅除數 等),倍數每次翻倍。
  2. 當倍增的除數超過被除數時,回退到上一個倍數。

詳細步驟

  1. 紀錄符號並取絕對值。
  2. 使用一個倍增方式快速逼近被除數。
  3. 當倍數無法繼續增加時,將被除數減去當前倍增的值,並繼續迴圈。

程式碼實現

class Solution:
def divide(self, dividend: int, divisor: int) -> int:
if dividend == -2**31 and divisor == -1:
return 2**31 - 1 # 處理溢出情況

# 確定結果的正負
negative = (dividend < 0) ^ (divisor < 0)

# 取絕對值進行計算
dividend, divisor = abs(dividend), abs(divisor)

result = 0
while dividend >= divisor:
temp_divisor, multiple = divisor, 1
while dividend >= (temp_divisor << 1):
temp_divisor <<= 1
multiple <<= 1

dividend -= temp_divisor
result += multiple

# 恢復符號
result = -result if negative else result

return max(-2**31, min(result, 2**31 - 1))

時間與空間複雜度

  • 時間複雜度:O(logn),其中 n=被除數。倍增法每次將剩餘的被除數減小到一半。
  • 空間複雜度:O(1)。

解法三:位運算(位移法)

思路

位運算的基本思路是利用位移操作來高效計算倍增。通過計算 divisor 向左移動幾位可以逼近 dividend,從而快速確定商的大小。

詳細步驟

  1. 紀錄結果符號並取絕對值。
  2. 將除數不斷向左移位,直到超過被除數。
  3. 每次找到一個可以減去的倍數,更新被除數並累加到結果。

程式碼實現

class Solution:
def divide(self, dividend: int, divisor: int) -> int:
if dividend == -2**31 and divisor == -1:
return 2**31 - 1 # 處理溢出情況

# 確定結果的正負
negative = (dividend < 0) ^ (divisor < 0)

# 取絕對值
dividend, divisor = abs(dividend), abs(divisor)

result = 0
for i in range(31, -1, -1):
if (dividend >> i) >= divisor:
result += 1 << i
dividend -= divisor << i

# 恢復符號
result = -result if negative else result

return max(-2**31, min(result, 2**31 - 1))

時間與空間複雜度

  • 時間複雜度:O(log⁡n),其中 n=被除數。最多進行 32 次迴圈操作。
  • 空間複雜度:O(1)。

總結

  • 暴力減法:簡單直觀,但效率較低。
  • 倍增減法:用指數倍增來優化,效率更高。
  • 位運算:利用位移操作,進一步優化時間複雜度。

倍增法與位移法是實際開發中常用的高效解法。如果你有任何疑問,歡迎留言討論!

歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
給定一個按非降序排序的整數數組 nums,就地刪除重複項,使得每個元素只出現一次。元素的相對順序應保持相同。然後傳回 nums 中唯一元素的數量。
給定一個鏈表,將鏈表的節點每 k 個一組進行反轉,並返回修改後的鏈表。如果節點總數不是 k 的倍數,則保留最後剩餘節點的順序。要求在不改變節點值的情況下進行反轉(即直接操作鏈表結構)。
給定一個鏈表,每次交換相鄰的兩個節點,返回交換後的鏈表。要求在不改變節點值的情況下進行節點交換(即直接操作鏈表結構)。
給定 k 個遞增排序的鏈表,將它們合併成一個遞增排序的鏈表,並返回合併後的鏈表。
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
給定一個按非降序排序的整數數組 nums,就地刪除重複項,使得每個元素只出現一次。元素的相對順序應保持相同。然後傳回 nums 中唯一元素的數量。
給定一個鏈表,將鏈表的節點每 k 個一組進行反轉,並返回修改後的鏈表。如果節點總數不是 k 的倍數,則保留最後剩餘節點的順序。要求在不改變節點值的情況下進行反轉(即直接操作鏈表結構)。
給定一個鏈表,每次交換相鄰的兩個節點,返回交換後的鏈表。要求在不改變節點值的情況下進行節點交換(即直接操作鏈表結構)。
給定 k 個遞增排序的鏈表,將它們合併成一個遞增排序的鏈表,並返回合併後的鏈表。
你可能也想看
Google News 追蹤
Thumbnail
/ 大家現在出門買東西還會帶錢包嗎 鴨鴨發現自己好像快一個禮拜沒帶錢包出門 還是可以天天買滿買好回家(? 因此為了記錄手機消費跟各種紅利優惠 鴨鴨都會特別注意銀行的App好不好用! 像是介面設計就是會很在意的地方 很多銀行通常會為了要滿足不同客群 會推出很多App讓使用者下載 每次
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目敘述 Subarray Sums Divisible by K 給定一個整數陣列,請計算有幾個區間和能夠整除k的連續區間? 測試範例 Input: nums = [4,5,0,-2,-3,1], k = 5 Output: 7
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
題目給定一個布林代數的二元樹,要求我們計算最後的結果。 葉子節點都是真假值 非葉子節點都是布林運算子
Thumbnail
題目敘述 輸入給定一個二元的二維矩陣grid 每次可以翻轉一條row,讓每個元素的01反相。 也可以翻轉一條column,讓每個元素的01反相。 可以操作任意多次。 最後把每條row視為一條二進位表達式的數字,並且進行加總,得到最後的分數。 請問分數的最大值是多少? 原本的英文題目敘
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
分享一道數學證明題 題目是將1~10的正整數分成兩組,分別為A組、B組 其中A組數字由小到大排列,B組數字則是由大到小排列,試求兩兩相減的絕對值總和
Thumbnail
/ 大家現在出門買東西還會帶錢包嗎 鴨鴨發現自己好像快一個禮拜沒帶錢包出門 還是可以天天買滿買好回家(? 因此為了記錄手機消費跟各種紅利優惠 鴨鴨都會特別注意銀行的App好不好用! 像是介面設計就是會很在意的地方 很多銀行通常會為了要滿足不同客群 會推出很多App讓使用者下載 每次
Thumbnail
題目敘述 Combination Sum II_Leetcode #40 給定一個整數陣列candidates 和 目標值target。 每個陣列元素只能選擇一次,請問有多少種組合方法,可以使得組合數總和 = target? 請把滿足組合數總和 = target的組合方法以陣列的形式返回答案
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目敘述 Subarray Sums Divisible by K 給定一個整數陣列,請計算有幾個區間和能夠整除k的連續區間? 測試範例 Input: nums = [4,5,0,-2,-3,1], k = 5 Output: 7
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
題目給定一個布林代數的二元樹,要求我們計算最後的結果。 葉子節點都是真假值 非葉子節點都是布林運算子
Thumbnail
題目敘述 輸入給定一個二元的二維矩陣grid 每次可以翻轉一條row,讓每個元素的01反相。 也可以翻轉一條column,讓每個元素的01反相。 可以操作任意多次。 最後把每條row視為一條二進位表達式的數字,並且進行加總,得到最後的分數。 請問分數的最大值是多少? 原本的英文題目敘
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
分享一道數學證明題 題目是將1~10的正整數分成兩組,分別為A組、B組 其中A組數字由小到大排列,B組數字則是由大到小排列,試求兩兩相減的絕對值總和