五一漫長的假期,外面的世界是人山人海,反而在家刷題算得上一個好的休閒方式。剛好我開始寫這道題:
Given two integers `dividend` and `divisor`, divide two integers **without** using multiplication, division, and mod operator.
The integer division should truncate toward zero, which means losing its fractional part. For example, `8.345` would be truncated to `8`, and `-2.7335` would be truncated to `-2`.
Return *the **quotient** after dividing* `dividend` *by* `divisor`.
**Note:** Assume we are dealing with an environment that could only store integers within the **32-bit** signed integer range: `[−231, 231 − 1]`. For this problem, if the quotient is **strictly greater than** `231 - 1`, then return `231 - 1`, and if the quotient is **strictly less than** `-231`, then return `-231`.
**Example 1:**
Input: dividend = 10, divisor = 3
Output: 3
Explanation: 10/3 = 3.33333.. which is truncated to 3.
**Example 2:**
Input: dividend = 7, divisor = -3
Output: -2
Explanation: 7/-3 = -2.33333.. which is truncated to -2.
**Constraints:**
- `-231 <= dividend, divisor <= 231 - 1`
- `divisor != 0`
看懂題目上說的,就是不能用乘法、除法以及取餘操作來算出兩個給定整數的商。這個時候我想到利用移位操作來實現。
雖然工作多年,但是真正在實際專案中用到移位操作的時候是很少的。
邏輯移位:
- 邏輯移位將位向左或向右移動,並在空位填充零。
- 在左邏輯移位(<<)中,位向左移動,從右側填充零。
- 在右邏輯移位(>>)中,位向右移動,從左側填充零。
簡單來說,如果1<<2, 就是1乘以2的2次方,以此類推。
所以我的解法就很明確了, 處理好被除數和除數的符號,然後再透過迴圈裡面使用移位操作計算出商的:
func divide(dividend int, divisor int) int {
quotient := 0
maxInt := math.MaxInt32
minInt := math.MinInt32
if divisor == 0 || (dividend == minInt && divisor == -1) {
return maxInt
}
// determine the sign of the quotient
sign := -1
if (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0) {
sign = 1
}
// Convert the dividend and divisor to be positive number
positiveDividend, positiveDivisor := int(math.Abs(float64(dividend))), int(math.Abs(float64(divisor)))
for positiveDividend >= positiveDivisor {
shift := 0
for positiveDividend >= (positiveDivisor << shift) {
shift += 1
}
quotient += (1<< (shift - 1))
positiveDividend -= (positiveDivisor << (shift - 1))
}
return int(math.Min(float64(maxInt), math.Max(float64(sign) * float64(quotient), float64(minInt))))
}
總結
移位操作雖然好,但也不是唯一解,回憶一下小時候還沒學乘法的時候,我們也可以用加法去模擬乘法,所以利用累加來模擬出兩數之商更直觀。
經過我的嘗試,我發現完全減法會導致超時問題,不得不結合shifting操作,程式碼如下所示:
func divide(dividend int, divisor int) int {
quotient := 0
maxInt := math.MaxInt32
minInt := math.MinInt32
if divisor == 0 || (dividend == minInt && divisor == -1) {
return maxInt
}
// determine the sign of the quotient
sign := -1
if (dividend ^ divisor) >= 0 {
sign = 1
}
// Convert the dividend and divisor to be positive number
positiveDividend, positiveDivisor := int(math.Abs(float64(dividend))), int(math.Abs(float64(divisor)))
// Every time postiveDividend subtract with the value of the divisor
for positiveDividend >= positiveDivisor {
// Initialize variables for binary search
tempDivisor := positiveDivisor
multiple := 1
// Perform binary search-like division
for positiveDividend >= (tempDivisor << 1) {
tempDivisor <<= 1
multiple <<= 1
}
// Subtract the multiple of divisor from dividend
positiveDividend -= tempDivisor
// Add the multiple to quotient
quotient += multiple
}
return int(math.Min(float64(maxInt), math.Max(float64(sign) * float64(quotient), float64(minInt))))
}