剑指offer11 实现power方法,不使用库函数:
也就是说求 a**b,不直接使用power方法。
解答:
- 最简单的循环相乘法,临界条件:累计乘b次得到结果
- 边界条件:base=0时,输出全为0;exp为0时,输出全为1(对于0**0无意义,可以单独得到结果,解释即可);exp为正时,正常;exp为负时,结果为1/res。
代码:省略。
tips:
可能遇到超时问题,一步步相乘时,过程不够高效,可以进行优化。
考虑,对于极大的b,先得到a ^2 ,然后 a ^4,接着a ^8…这样类似于二分法的方法极大地降低了时间复杂度。
等式表示:
a^b = a ^(b/2) * a ^(b/2) b为偶数
= a^((b-1)/2) * a^((b-1)/2) * a b为奇数
这里可以使用递归了。因为递归是从大往小分(实际输出是先小后大),所以不用担心结果在a ^15次方这样卡在8和16的情况时是否需要返回上一步的做法(15变为7,7变为3,3变为1,为奇数的时候注意要在得到的结果再进行一次乘base)。
新的解答:
- 边界条件:base=0时,直接回0
- else 里面 将 base与exp全化为非负数处理。sign1默认为1 表示exp正,然后判断 exp如果<0,则将其变为-1(最后的结果再判定1/res); base变为正数,同时sign2代表其正负。
- 进入下一步,exp的边界分析:exp为0时直接返回1,exp为1时返回base(适用于递归以及常规情况)
- 下一步,exp的常规情况:进入递归,exp>>1表示取模的效果,得到之前的值后,res*res,这里表示exp模2的同时,res自己相乘(倒过来看就是上个递归的res自乘,同时exp乘2)。
- 此处注意对每次的exp进行奇数的判断,如果时则还需要乘以自身
- 最后,根据sign1和sign2进行最后结果的输出(同样适用于递归时,因为递归时都是正数,状态均为1)。
代码:
def myPower(base,exp):
if base ==0:
return 0
else:
base,sign2 = abs(base), base/abs(base)
sign1 = 1
if exp<0:
sign1 = -1
exp = abs(exp)
if exp == 0:
return 1
elif exp ==1:
return base
else:
res = myPower(base,exp>>1)
print(res)
res = res*res
if exp%2==1:
res = res*base
if sign2 == -1:
res = -res
if sign1 == -1:
res = 1/res
return res
#return res if sign1>0 else 1/res
base1,base2,base3,base4 = 0,-3,5,18
exp1,exp2,exp3,exp4 = 0,-3,4,30
print(myPower(base3,exp4),5**(30))
#print(myPower(-3,3),-3**3)