移位操作搞定两数之商

五一漫长的假期,外面的世界是人山人海,反而在家刷题算得上一个好的休闲方式。刚好我开始写这道题:

复制代码
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))))
 }
相关推荐
福大大架构师每日一题13 小时前
ollama v0.30.7 正式发布:Hermes 桌面端落地,接口、文档、底层依赖全方位优化
golang·log4j
不爱编程的小陈15 小时前
深入解析 Go 网络 I/O 的底层引擎:从 epoll 到 netpoll
服务器·网络·golang
何以解忧,唯有..19 小时前
Go 语言数据类型详解:从基础到复合类型
开发语言·golang·mfc
踏着七彩祥云的小丑19 小时前
Go学习第7天:Map集合 + 递归函数 + 类型转换
开发语言·学习·golang·go
何以解忧,唯有..19 小时前
Go语言变量的声明方式详解
开发语言·后端·golang
寂夜了无痕19 小时前
Go 多版本管理工具G 保姆级安装配置教程
golang·go多版本管理
张忠琳20 小时前
【Go 1.26.4】Golang Slice 深度解析
开发语言·后端·golang
张忠琳1 天前
【Go 1.26.4】Golang Channel 深度解析
开发语言·后端·golang
张忠琳2 天前
【Go 1.26.4】Golang Map 深度解析
开发语言·后端·golang
何以解忧,唯有..2 天前
Go 语言安装与环境配置完整指南
开发语言·后端·golang