日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java不使用除号实现除法运算_LeetCode29 Medium 不用除号实现快速除法

發(fā)布時(shí)間:2024/1/23 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java不使用除号实现除法运算_LeetCode29 Medium 不用除号实现快速除法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文始發(fā)于個(gè)人公眾號(hào):TechFlow,原創(chuàng)不易,求個(gè)關(guān)注

鏈接

難度

Medium

描述

給定兩個(gè)整數(shù),被除數(shù)和除數(shù),要求在不使用除號(hào)的情況下計(jì)算出兩數(shù)的商

Given two integers dividend and divisor, divide two integers without using

multiplication, division and mod operator.

Return the quotient after dividing dividend by divisor.

The integer division should truncate toward zero.

樣例 1:

Input: dividend = 10, divisor = 3

Output: 3

樣例 2:

Input: dividend = 7, divisor = -3

Output: -2

注意:

除數(shù)和被除數(shù)都在32位int的范圍內(nèi)

除數(shù)不為0

對(duì)于超界的情況返回\(2^{31}-1\)

Both dividend and divisor will be 32-bit signed integers.

The divisor will never be 0.

Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [?\(2^{31}\), \(2^{31}\) ? 1]. For the purpose of this problem, assume that your function returns \(2^{31}\) ? 1 when the division result overflows.

題解

老規(guī)矩,我們依然從最簡(jiǎn)單的情況開(kāi)始入手。我們都知道,在計(jì)算機(jī)內(nèi)部,是二進(jìn)制的,而二進(jìn)制是只能進(jìn)行加減的。所以沒(méi)錯(cuò),所有的乘法和除法的操作其實(shí)最終都會(huì)轉(zhuǎn)換為加減法來(lái)進(jìn)行。對(duì)于這道題而言也是一樣的,既然禁止我們使用除法,那么我們可以用減法來(lái)代替。

暴力

最簡(jiǎn)單的策略就是我們可以用一個(gè)循環(huán)去不停地減,然后用一個(gè)累加器計(jì)算到底執(zhí)行了多少次減法,當(dāng)不夠減的時(shí)候則停止。整個(gè)流程非常簡(jiǎn)單,但是我們還需要考慮一下正負(fù)號(hào)的問(wèn)題,按照排列組合來(lái)看,被除數(shù)和除數(shù)一共有4中正負(fù)號(hào)的情況。但我們并不需要考慮那么多,這四種情況可以簡(jiǎn)單地歸并成是否同號(hào)兩種,然后進(jìn)一步分析又會(huì)發(fā)現(xiàn)是否同號(hào)的計(jì)算過(guò)程并沒(méi)有差別,唯一會(huì)影響的只有最后結(jié)果的正負(fù)號(hào)。

還有一點(diǎn)比較令人在意的是提示當(dāng)中說(shuō)的可能會(huì)超界的情況,我們來(lái)分析一下,其實(shí)會(huì)超界的可能性只有一個(gè)。那就是\(-2^{31}\)除以-1的情況,會(huì)得到\(2^{31}\),而32位int的正數(shù)范圍最大是\(2^{31}-1\),所以我們需要在意這個(gè)問(wèn)題。不過(guò)好在對(duì)于Python而言,int是沒(méi)有范圍的,所以可以忽略這個(gè)問(wèn)題,只需要最后特判一下結(jié)果,但是對(duì)于C++和Java等語(yǔ)言而言,需要特判一下這個(gè)case。

我們來(lái)總結(jié)一下上面的過(guò)程,我們可以先將除數(shù)和被除數(shù)全部轉(zhuǎn)化為正數(shù),然后用一個(gè)標(biāo)記flag來(lái)記錄它們是否同號(hào)。再計(jì)算完結(jié)果之后,需要判斷一下結(jié)果的范圍是否越界,如果越界返回\(2^{31}-1\)。

代碼如下:

class Solution:

def divide(self, dividend: int, divisor: int) -> int:

# 判斷是否同號(hào)

flag = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)

ret = 0

# 全部賦值為正

dividend, divisor = abs(dividend), abs(divisor)

start = 0

# 模擬除法

while start + divisor <= dividend:

start += divisor

ret += 1

# 防止越界,注意只有正數(shù)才有可能越界

return min(ret, (1 << 31) - 1) if flag else -ret

這個(gè)代碼當(dāng)然是沒(méi)有問(wèn)題的,但是如果你真的這么提交,那么一定會(huì)超時(shí)。原因也很簡(jiǎn)單,當(dāng)除數(shù)非常小,比如是1的時(shí)候,那么我們的循環(huán)次數(shù)就是被除數(shù)的大小。當(dāng)我們給定一個(gè)很大的被除數(shù)的時(shí)候,會(huì)超時(shí)就是顯然的了。

二進(jìn)制優(yōu)化

接下來(lái)講的這個(gè)算法很重要,是快速冪等許多算法的基礎(chǔ),由于本題當(dāng)中不是進(jìn)行的冪運(yùn)算,所以不能稱作是快速冪算法,一時(shí)間也沒(méi)有什么好的名字,由于本質(zhì)上是通過(guò)二進(jìn)制的運(yùn)算來(lái)優(yōu)化,所以就稱為二進(jìn)制優(yōu)化吧。

在講解算法之前,我們先來(lái)分析一下bad case出現(xiàn)的原因。之所以會(huì)超時(shí),是因?yàn)橛锌赡鼙怀龜?shù)非常小,比如是1,這個(gè)時(shí)候我們一位一位地減就非常耗時(shí)。那么很自然地可以想到,我們可不可以每次不是減去一個(gè)1,而是若干個(gè)1,最后把這些減去的數(shù)量加起來(lái),是不是會(huì)比每次減去一個(gè)要更快一些呢?但是還有細(xì)節(jié)我們不清楚,我們?cè)趺磥?lái)確定這個(gè)每次應(yīng)該減去的數(shù)量呢?如果確定了之后發(fā)現(xiàn)不夠減,又應(yīng)該怎么辦呢?

要回答上面這個(gè)問(wèn)題,需要對(duì)二進(jìn)制有比較深入的理解。我們先把剛才的問(wèn)題放一放,來(lái)看一看二進(jìn)制對(duì)于除法的解釋。舉個(gè)簡(jiǎn)單的例子,比如15 / 3 = 5。我們知道15等于5個(gè)3相乘,那么我們把它們都寫成二進(jìn)制。15的二進(jìn)制是1111,3的二進(jìn)制是0011,5的二進(jìn)制是0101,我們重點(diǎn)來(lái)看這個(gè)5的二進(jìn)制。

5的二進(jìn)制寫成0101,展開(kāi)的話會(huì)得到是\(2^2 + 2^0 = 4 + 1\),也就是說(shuō)我們可以把15看成\((2^2+2^0)*3\),這個(gè)式子寫成是\((0*2^3+1*2^2+0*2^1+1*2^0)*3=15\)。也就是說(shuō)我們可以把被除數(shù)看成是若干個(gè)2的冪乘上除數(shù)的和,這就把一個(gè)除法問(wèn)題轉(zhuǎn)化成了加法問(wèn)題。同樣我們把求解商轉(zhuǎn)化成了求解商的二進(jìn)制表達(dá),二進(jìn)制表達(dá)有了,最后的商無(wú)非是再進(jìn)行一個(gè)求和累加即可。

最后,我們來(lái)分析一下,為什么能夠優(yōu)化。因?yàn)轭}目當(dāng)中已經(jīng)限定了,除數(shù)和被除數(shù)都在32位的int范圍。也就是說(shuō)最多只有32個(gè)二進(jìn)制位,那么我們的循環(huán)次數(shù)最多也就是32次。通過(guò)二進(jìn)制優(yōu)化,我們把原本一個(gè)\(O(n)\)的問(wèn)題,降級(jí)成了\(O(\log n)\),這兩者之間差了不止一個(gè)數(shù)量級(jí),當(dāng)然要快得多。

我們把上面這個(gè)思路寫成代碼,就可以得到答案:

class Solution:

def divide(self, dividend: int, divisor: int) -> int:

# 前面處理和之前一樣

flag = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)

ret = 0

dividend, divisor = abs(dividend), abs(divisor)

# 預(yù)處理二進(jìn)制數(shù)組

binary = [0 for _ in range(33)]

# 第0位即2的零次方乘上除數(shù),所以就是除數(shù)本身

binary[0] = divisor

for i in range(1, 33):

# 后面每一位是前面一位的兩倍,因?yàn)槎M(jìn)制

# << 是位運(yùn)算左移操作,等價(jià)于*2,但是速度更快

binary[i] = binary[i-1] << 1

for i in range(32, -1, -1):

if binary[i] <= dividend:

dividend -= binary[i]

# 答案加上2^i

ret += (1 << i)

return min(ret, (1 << 31) - 1) if flag else -ret

這段代碼不長(zhǎng),也沒(méi)有用到什么特別牛哄哄的算法,無(wú)非是對(duì)二進(jìn)制的一些運(yùn)用。但是對(duì)于對(duì)二進(jìn)制不夠熟悉的初學(xué)者而言,想完全搞明白可能有些費(fèi)勁,這也是很正常的。希望大家能夠沉下心來(lái)好好理解,如果實(shí)在看不懂也沒(méi)關(guān)系,在以后快速冪等算法當(dāng)中,還會(huì)和它見(jiàn)面的。

今天的文章就是這些,如果覺(jué)得有所收獲,請(qǐng)順手掃碼點(diǎn)個(gè)關(guān)注吧,你們的舉手之勞對(duì)我來(lái)說(shuō)很重要。

總結(jié)

以上是生活随笔為你收集整理的java不使用除号实现除法运算_LeetCode29 Medium 不用除号实现快速除法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。