传送门:https://leetcode-cn.com/problems/powx-n/
一、LeetCode 50. Pow(x, n)
1、题目描述
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
2、示例
示例 1:
输入: 2.00000, 10
输出: 1024.00000
示例 2:
输入: 2.10000, 3
输出: 9.26100
示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/2^2 = 1/4 = 0.25
3、说明
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
4、分析
本题重点在于边界条件的分析和处理
- 如果 n < 0,是不是 n = -n, x = 1 / x ,再进行递归就能解决了呢?
- 如果 n = Intege.MIN_VALUE,n = -n 会出现溢出,怎么办呢?
- 我们可以先将 n / 2 赋值给 a,再将 a = -n,就不会出现溢出问题。
5、实现
class Solution {
public:
double myPow(double x, int n) {
if(n == 0)
return 1;
int a = n/2;
if(n < 0)
{
a = -a;
x = 1.0/x;
}
double res = myPow(x, a);
if(n % 2 == 0)
return res * res;
else
return res * res * x;
}
};
二、递归
1、定义
- 若一个对象部分的包含自己或用它自己给自己定义,则这个对象是递归的;
- 若一个过程直接或间接的调用自己,则这个过程是递归的。
2、思想
把问题分解为规模更小具有与原问题相同解法的子问题
==》优点:思考的方式更加简单,程序也更加简练。
==》缺点:增加了压栈开销,因此空间复杂度比较高。
3、递归条件
- 减小问题规模,并使子问题与原问题有相同解法。
- 设置出口,如果没有出口那么程序会一直递归下去。
三、斐波那契数列
斐波那契数列是一个非常典型的递归问题。
1、循环方法
long Fibonacci1(size_t N)
{
long first = 1;
long second = 1;
long sum = 0;
if(N < 3)
return 1;
else
{
for(size_t i = 3; i <= N; i++)
{
sum = first + second;
first = second;
second = sum;
}
return sum;
}
}
==》时间复杂度:O(n)
==》空间复杂度:O(1)
2、递归方法1
long Fibonacci2(size_t N)
{
if(N < 3)
return 1;
else
return Fibonacci2(N-1) + Fibonacci2(N-2);
}
==》由后向前计算
==》时间复杂度:O(n2)
==》空间复杂度:O(n)
3、递归方法2
long Fibonacci3(long first, long second, size_t N)
{
if(N < 3)
return second;
else
return Fibonacci3(second, first + second, N - 1);
}
==》前向后计算——尾递归方法
==》在进行递归时函数只会使用第一次压栈所开辟的栈空间,在一个栈空间内循环,而不会开辟别的栈空间,所以这种方式时间复杂度为O(N),空间复杂度为O(1),是一种非常高效的递归方式。
4、递归方法3
long *Fibonacci4(size_t N)
{
long *array = new long[N+1];
if(N == 0)
return NULL;
array[0] = 1;
array[1] = 1;
for(size_t i = 2; i <= N; i++)
{
array[i] = array[i-1] + array[i-2];
}
return array;
}
四、递归函数的复杂度
在算法的分析中,当一个算法中包含递归调用时,其时间复杂度的分析==》一个递归方程的求解。
而对递归方程的求解,目前主流的方法:代入法,迭代法,公式法,母函数法,差分方程法。
1、代入法
- 首先要对这个问题的时间复杂度做出预测;
- 然后将预测带入原来的递归方程,如果没有出现矛盾,则是可能的解;
- 最后用数学归纳法证明。
示例
递归问题:T(n)=4T(n/2)+O(n)
(1)预测时间复杂度:O(n2)
(2)设T(n)=kn2(其中k为常数),将该结果带入方程
(3)可得:左=kn2,右=4k(n/2)2+O(n)=kn2+O(n)
(4)由于n2 的阶高于 n 的阶,因而左右两边是相等的;
(5)数学归纳法进行验证即可
2、迭代法
- 迭代的展开方程的右边,直到没有可以迭代的项为止;
- 这时通过对右边的和进行估算来估计方程的解。
- 比较适用于分治问题的求解。
递归方程的一般形式
示例
(1)递归方程如下:
T
(
n
)
=
2
T
(
n
/
2
)
+
n
2
T(n) = 2T(n / 2) + n^2
T(n)=2T(n/2)+n2
(2)迭代过程如下:
T
(
n
)
=
2
T
(
n
2
)
+
n
2
T(n) = 2T(\frac{n}{2}) + n^2
T(n)=2T(2n)+n2
=
n
2
+
2
(
(
n
2
)
2
+
2
T
(
n
4
)
)
= n^2 +2((\frac{n}{2})^2 + 2T(\frac{n}{4}))
=n2+2((2n)2+2T(4n))
=
n
2
+
2
(
(
n
2
)
2
+
2
(
(
n
4
)
2
+
2
T
(
n
8
)
)
)
= n^2 +2((\frac{n}{2})^2 + 2((\frac{n}{4})^2 + 2T(\frac{n}{8})))
=n2+2((2n)2+2((4n)2+2T(8n)))
=
n
2
+
2
(
(
n
2
)
2
+
2
(
(
n
4
)
2
+
.
.
.
+
2
(
(
n
2
i
)
2
+
2
T
(
n
2
i
+
1
)
)
)
)
= n^2 +2((\frac{n}{2})^2 + 2((\frac{n}{4})^2 +...+ 2((\frac{n}{2^i})^2 + 2T(\frac{n}{2^{i+1}}))))
=n2+2((2n)2+2((4n)2+...+2((2in)2+2T(2i+1n))))
容易知道,直到
n
2
i
+
1
=
1
\frac{n}{2^{i+1}}=1
2i+1n=1 时,递归过程结束,这时我们计算如下:
T
(
n
)
=
n
2
+
2
n
2
2
2
+
2
2
n
2
4
2
+
2
2
n
2
8
2
+
.
.
.
T(n) = n^2 + 2 \frac{n^2}{2^2}+2^2\frac{n^2}{4^2}+2^2\frac{n^2}{8^2}+...
T(n)=n2+222n2+2242n2+2282n2+...
=
n
2
(
1
+
1
2
+
1
4
+
1
8
+
.
.
.
)
=n^2(1+\frac{1}{2}+\frac{1}{4}+\frac{1}{8}+...)
=n2(1+21+41+81+...)
=
2
n
2
=2n^2
=2n2
==》该算法的时间复杂度:O(n2)
3、公式法
针对形如:T(n) = aT(n/b) + f(n)的递归方程
==》分治法的时间复杂度,即一个规模为n的问题被分成规模均为n/b的a个子问题,递归地求解这a个子问题,然后通过对这a个子问题的解的综合,得到原问题的解。
==》公式法对于分治问题最好的解法
T
(
n
)
=
{
O
(
n
l
o
g
b
a
)
,
O
(
n
l
o
g
b
a
)
>
O
(
f
(
n
)
)
O
(
f
(
n
)
∗
l
o
g
n
)
,
O
(
n
l
o
g
b
a
)
=
O
(
f
(
n
)
)
O
(
f
(
n
)
)
,
O
(
n
l
o
g
b
a
)
<
O
(
f
(
n
)
)
T(n)=\begin{cases} O(n^{log_ba}), & O(n^{log_ba}) > O(f(n))\\ O(f(n)*{logn}), & O(n^{log_ba}) = O(f(n)) \\ O(f(n)), & O(n^{log_ba}) < O(f(n)) \end{cases}
T(n)=⎩⎪⎨⎪⎧O(nlogba),O(f(n)∗logn),O(f(n)),O(nlogba)>O(f(n))O(nlogba)=O(f(n))O(nlogba)<O(f(n))
其中,
a
>
1
,
b
>
1
a>1,b>1
a>1,b>1均为常数,
f
(
n
)
f(n)
f(n)是确定正函数。
==》分析:实际是比较
O
(
n
l
o
g
b
a
)
O(n^{log_ba})
O(nlogba)和
O
(
f
(
n
)
)
O(f(n))
O(f(n))的阶,若不等,则
T
(
n
)
T(n)
T(n) 取较大者;若阶相等,则任选其一再乘以
l
o
g
n
logn
logn即可。
注意
上面的公式并不包含所有的情况:
f
(
n
)
f(n)
f(n)是小于前者,但是并不是多项式的小于前者。
当
f
(
n
)
=
0
f(n) = 0
f(n)=0 时,则有:
T
(
n
)
=
{
O
(
n
l
o
g
b
a
)
,
a
≠
1
O
(
l
o
g
n
)
,
a
=
1
T(n)=\begin{cases} O(n^{log_ba}), & a≠1\\ O({logn}), & a = 1 \end{cases}
T(n)={O(nlogba),O(logn),a̸=1a=1
4、母函数法
应用在一个无穷序列的幂级数,其递归形如:
T
(
n
)
=
c
1
T
(
n
−
1
)
+
c
2
T
(
n
−
2
)
+
c
3
T
(
n
−
3
)
+
.
.
.
+
+
c
k
T
(
n
−
k
)
+
f
(
n
)
T(n)=c_1T(n-1)+c_2T(n-2)+c_3T(n-3)+...++c_kT(n-k)+f(n)
T(n)=c1T(n−1)+c2T(n−2)+c3T(n−3)+...++ckT(n−k)+f(n)
示例——斐波那契数列
(1)递归公式:
T
(
n
)
=
T
(
n
−
1
)
+
T
(
n
−
2
)
T(n)=T(n-1)+T(n-2)
T(n)=T(n−1)+T(n−2)
(2)不妨设
F
(
n
)
F(n)
F(n) 为第
n
n
n 项的运算量,可得:
F
(
n
)
=
F
(
n
−
1
)
+
F
(
n
−
2
)
F(n)=F(n-1)+F(n-2)
F(n)=F(n−1)+F(n−2)
(3)构造母函数
G
(
x
)
=
F
(
1
)
x
+
F
(
2
)
x
2
+
F
(
3
)
x
3
+
.
.
.
可
推
导
如
下
:
F
(
)
G(x) = F(1)x+F(2)x^2+F(3)x^3+... \\ 可推导如下:F()
G(x)=F(1)x+F(2)x2+F(3)x3+...可推导如下:F()