移位操作搞定两数之商

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

复制代码
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))))
 }
相关推荐
kgduu32 分钟前
go ethreum之Trie
开发语言·后端·golang
Wzx1980123 小时前
go接受输入方式
开发语言·后端·golang
南猿北者4 小时前
go环境搭建--Linux
linux·开发语言·golang
Lovely Ruby16 小时前
前端er Go-Frame 的学习笔记:实现 to-do 功能(三),用 docker 封装成镜像,并且同时启动前后端数据库服务
前端·学习·golang
互亿无线明明21 小时前
如何为全球业务构建可扩展的“群发国际短信接口”?
java·c++·python·golang·eclipse·php·erlang
张较瘦_1 天前
[论文阅读] 软件工程 - 供应链 | 从Log4Shell到Go组件漏洞:一篇文看懂开源依赖安全的核心痛点与解决方案
论文阅读·golang·开源
wadesir1 天前
Go语言反射之结构体的深比较(详解reflect.DeepEqual在结构体比较中的应用)
开发语言·后端·golang
古城小栈1 天前
Go 72变之 编成 C语言
c语言·python·golang
卿雪1 天前
认识Redis:Redis 是什么?好处?业务场景?和MySQL的区别?
服务器·开发语言·数据库·redis·mysql·缓存·golang
foxsen_xia1 天前
go(基础10)——错误处理
开发语言·后端·golang