50. Pow(x, n)
快速幂的思路很简单,就是对于一个数 k ,我们求其 n 次幂,就只需要将n进行拆分就行
即:对于 k^9 来说,9可以表示为 1001,即 2^3 + 2^0即求:k^(2^3) + k^(2^0)那么求解的时候就可以:左移幂,不断乘以2,如果最后一位为1的时候,说明这个幂可以放入作为幂次计算此时将幂次计算进去即可
代码如下:
pub fn my_pow(mut x: f64, mut n: i32) -> f64 {if n == 0 { return 1.0; }// 注意这一句,在负数最大的时候会溢出,边界let mut n = n as i64;if n < 0 {x = 1.0_f64 / x;n = -n;}let mut res = 1.0;let mut contribute = x;while n > 0 {if n & 1 == 1 {res *= contribute;}n = n >> 1;// 注意每一次的增加的值都是自身相乘contribute *= contribute;}res}
上面的快速幂算法可以引导出倍增算法,我们可以使用这种思想实现乘法
从快速幂到倍增:实现乘法
直接看代码:
注意比较倍增与二次幂的区别
// 倍增的思想实现乘法pub fn multiply(mut x: i64, mut y: i64) -> i64{// 对于x*y,我们可以转换为 x*y(2)// 比如 k * 9 = k * (1001) = k + k * 8 = k + (k + K)重复8次 倍增// 比较二次幂: k^9 = k^(1001) = (k*K)重复8次 + K 倍乘let mut res = 0;let mut flag = 0;// 处理正负问题if (x<0 && y>0) || (y<0 && x>0) {flag = 1;}if x < 0 { x = -x; }if y < 0 { y = -y; }while y > 0 {if y & 1 == 1 {res += x;}y = y >> 1;x += x;}return match flag {0 => res,1 => -res,_ => panic!("wrong!!!!")}}
倍增的应用:29. 两数相除
两数相除的暴力解法就是o(n)的一直减下去,另一个做法就是使用中间值去试乘
注意一个点:这儿只能用右二分,返回左
// 两数相除:x/ypub fn divide(mut x: i32, mut y: i32) -> i32 {// 这个情况很恶心,在x为i32::MIN时会被绕过if y == 1 { return x; }let mut flag = 0;// 注意处理溢出,很简单,转换即可let mut x = x as i64;let mut y = y as i64;// 处理正负问题if (x<0 && y>0) || (y<0 && x>0) {flag = 1;}if x < 0 { x = -x; }if y < 0 { y = -y; }let mut l = 0 as i64;let mut r = x;while l < r {let mid = l + ((r - l +1) >> 1);if Self::multiply(mid, y) <= x {l = mid ;}else { r = mid -1 ; }}// 因为返回i32,所以还要处理溢出if l > i32::MAX as i64 || l < i32::MIN as i64 {return i32::MAX}else {return match flag {0 => l as i32,1 => -l as i32,_ => panic!("!!!!")}}}
