目录
前言
本文为leetcode上的题目简单分析总结,仅作记录,欢迎提出建议,共同学习交流。
50.pow(x, n)
实现 pow(x, n) ,即计算 x
的整数 n
次幂函数(即, )。
示例 1:
输入:x = 2.00000, n = 10 输出:1024.00000示例 2:
输入:x = 2.10000, n = 3 输出:9.26100示例 3:
输入:x = 2.00000, n = -2 输出:0.25000 解释:2-2 = 1/22 = 1/4 = 0.25
方法一
直接调用Math类下的pow函数
class Solution {
public double myPow(double x, int n) {
return Math.pow(x, n);
}
}
方法二
暴力法:逐个遍历
时间复杂度:
对于数据较大的数时会超时,不推荐使用
class Solution {
public double myPow(double x, int n) {
double res = 1;
// 处理n为负数的情况
if(n < 0){
x = 1/x; // 直接将x变为倒数
n = -n; // 同时把n变成正数
}
// 处理特殊情况
for(int i=0; i<n; i++){
res *= x; // 逐项相乘
}
return res; //返回答案
}
}
方法三
快速幂(分而治之) + 递归
时间复杂度:
class Solution {
public double myPow(double x, int n) {
// 负指数幂则把n取负,最后的结果取倒数
if(n < 0) return 1 / quickMul(x, -n);
else return quickMul(x, n);
}
// 定义快速幂函数
public double quickMul(double x, int n) {
// 处理特殊情况
if (n == 0) {
return 1.0;
}
// 定义变量存储中间值
double y = quickMul(x, n / 2);
// 如果n为偶数,相除得到整数则只需y*y
// 如果n为奇数,相除会向下取整,因而需要多乘一个x
return n % 2 == 0 ? y * y : y * y * x;
}
}
方法解析
「快速幂算法」的本质是分治算法
详解请观看: . - 力扣(LeetCode)
如果我们要计算 我们可以按照:
的顺序,从 x 开始,每次直接把上一次的结果进行平方,计算 6 次就可以得到 的值,而不需要对 x 乘 63 次 x。
如果我们要计算 我们可以按照:
的顺序,在 ,, 这些步骤中,我们直接把上一次的结果进行平方,而在 ,, 这些步骤中,我们把上一次的结果进行平方后,还要额外乘一个 x。
直接从左到右进行推导看上去很困难,因为在每一步中,我们不知道在将上一次的结果平方之后,还需不需要额外乘 x。但如果我们从右往左看,分治的思想就十分明显了:
- 当我们要计算 时,我们可以先递归地计算出 ,其中 进行向下取整;
- 如果 n 为偶数,那么 ;
- 如果 n 为奇数,那么 ;
- 递归的边界为 n=0,任意数的 0 次方均为 1。
由于每次递归都会使得指数减少一半,因此递归的层数为 O(logn),算法可以在很快的时间内得到结果。
下面引入相同类型的题目:
2961.双模幂运算
给你一个下标从 0 开始的二维数组 variables
,其中 variables[i] = [ai, bi, ci, mi]
,以及一个整数 target
。
如果满足以下公式,则下标 i
是 好下标:
0 <= i < variables.length
((aibi % 10)ci) % mi == target
返回一个由 好下标 组成的数组,顺序不限 。
示例 1:
输入:variables = [[2,3,3,10],[3,3,3,1],[6,1,1,4]], target = 2 输出:[0,2] 解释:对于 variables 数组中的每个下标 i : 1) 对于下标 0 ,variables[0] = [2,3,3,10] ,(23 % 10)3 % 10 = 2 。 2) 对于下标 1 ,variables[1] = [3,3,3,1] ,(33 % 10)3 % 1 = 0 。 3) 对于下标 2 ,variables[2] = [6,1,1,4] ,(61 % 10)1 % 4 = 2 。 因此,返回 [0,2] 作为答案。示例 2:
输入:variables = [[39,3,1000,1000]], target = 17 输出:[] 解释:对于 variables 数组中的每个下标 i : 1) 对于下标 0 ,variables[0] = [39,3,1000,1000] ,(393 % 10)1000 % 1000 = 1 。 因此,返回 [] 作为答案。
分析
模运算恒等式:
(a * b) mod m=((a mod m) * (b mod m)) mod m
这里模运算可以分解为快速幂,再次运用上式得到多个部分放入一个方法中,在主函数中调用,满足此条件则把此下标添加到 list 中。
分解模 + 快速幂 + 递归
class Solution {
public List<Integer> getGoodIndices(int[][] variables, int target) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < variables.length; i++) {
int[] v = variables[i];
// 满足条件则添加
if (powMod(powMod(v[0], v[1], 10), v[2], v[3]) == target) {
list.add(i);
}
}
return list;
}
public int powMod(int x, int y, int mod){
int res = 1;
while(y != 0){
// 查看最后一位是否为1
if((y & 1) == 1)
// 乘相应阶数同时取模
res = res * x % mod;
// x的阶数翻倍同时取模
x = x * x % mod;
// y右移一位
y = y >> 1;
}
return res;
}
}