Skip to content

Commit 1971e05

Browse files
committed
合并dev
2 parents fb823dd + 1bbcece commit 1971e05

File tree

9 files changed

+300
-3
lines changed

9 files changed

+300
-3
lines changed

readme.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ tags: 目录
3131
| 数组 | [二维数组中的查找](./剑指offer/二维数组中的查找/readme.md) | [c++](./剑指offer/二维数组中的查找/src/cpp/二维数组中的查找.cpp) | [python](./剑指offer/二维数组中的查找/src/python/二维数组中的查找.py) |
3232
| 字符串 | [替换空格](./剑指offer/替换空格/readme.md) | [c++](./剑指offer/替换空格/src/cpp/替换空格.cpp) | [python](./剑指offer/替换空格/src/python/替换空格.py) |
3333
| 链表 | [从尾到头打印链表](./剑指offer/从尾到头打印链表/readme.md) | [c++](./剑指offer/从尾到头打印链表/src/cpp/从尾到头打印链表.cpp) | [python](./剑指offer/从尾到头打印链表/src/python/从尾到头打印链表.py) |
34-
| 二叉树 | [重建二叉树](./剑指offer/重建二叉树/readme.md) | [c++](./剑指offer/重建二叉树/src/cpp/重建二叉树.cpp) | [python](./剑指offer/重建二叉树/src/python/重建二叉树.py) |
35-
| 栈 队列 | [用两个栈实现队列](./剑指offer/用两个栈实现队列/readme.md) | [c++](./剑指offer/用两个栈实现队列/src/cpp/用两个栈实现队列.cpp) | [python](./剑指offer/用两个栈实现队列/src/python/用两个栈实现队列.py) |
36-
34+
| 二叉树 | [重建二叉树](./剑指offer/重建二叉树/readme.md) | [c++](./剑指offer/重建二叉树/src/cpp/重建二叉树.cpp) | [python](./剑指offer/重建二叉树/src/python/重建二叉树.py)
35+
| 栈 队列 | [用两个栈实现队列](./剑指offer/用两个栈实现队列/readme.md) | [c++](./剑指offer/用两个栈实现队列/src/cpp/用两个栈实现队列.cpp) | [python](./剑指offer/用两个栈实现队列/src/python/用两个栈实现队列.py)
36+
| 二分查找 | [旋转数组的最小数字](./剑指offer/旋转数组的最小数字/readme.md) | [c++](./剑指offer/旋转数组的最小数字/src/cpp/旋转数组的最小数字.cpp) | [python](./剑指offer/旋转数组的最小数字/src/python/旋转数组的最小数字.py)
37+
| 递归 | [斐波那契数列](./剑指offer/斐波那契数列/readme.md) | [c++](./剑指offer/斐波那契数列/src/cpp/斐波那契数列.cpp) | [python](./剑指offer/斐波那契数列/src/python/斐波那契数列.py)
38+
| 位运算 | [二进制中1的个数](./剑指offer/二进制中1的个数/readme.md) | [c++](./剑指offer/二进制中1的个数/src/cpp/二进制中1的个数.cpp) | [python](./剑指offer/二进制中1的个数/src/python/二进制中1的个数.py)
3739
## 经典算法&&数据结构
3840
| 考察点 | 题目&&题解 | c++ | python |
3941
| ---- | ---- | ---- | ---- |
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#递归 二进制中1的个数
2+
3+
tags: 位运算
4+
5+
---
6+
7+
## 题目原文
8+
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
9+
n<=39
10+
11+
## 解题思路
12+
### 低效率不实用的方法
13+
斐波那契数列的求解方法最容易些想到的就是如下的递归形式
14+
```c++
15+
long long Fibonacci(unsigned int n){
16+
if (n<=0)
17+
return 0;
18+
19+
if (n==1)
20+
return 1;
21+
22+
return Fibonacci(n-1)+Fibonacci(n-2)
23+
}
24+
```
25+
上面的递归形式看起来很简单,但效率却很低,因为在递归的过程中存在着大量的重复计算。例如,计算f(10)的时候需要计算f(8)和f(9),在计算f(9)的时候又要计算一遍f(8),因此,计算的时间复杂度会随着n的增大而指数级增大。
26+
27+
### 改进方法
28+
29+
上面的方法问题在于递归的过程存在大量的重复计算,因此可以考虑在计算的过程中把计算结果保存下来,比如建立一个数组保存中间计算结果,但这也不是好的方法,因为耗费了额外的内存空间。
30+
31+
换种思路,先根据f(0)和f(1)计算出f(2),再依次计算出f(3),f(4),...,f(n),这种计算方法的空间复杂度是常数,时间复杂度是$\Theta(n)$
32+
33+
34+
### 时间复杂度为$\Theta(logn)$但不是很实用的解法
35+
介绍解法之前先介绍下面的数学公式:
36+
37+
$$\begin{bmatrix}f(n)&f(n-1)\\f(n-1)&f(n-2) \end{bmatrix}=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$$
38+
39+
这个公式可以用数学归纳法证明,有了这个公示后,原来的问题就变成了求矩阵$=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$,若果只是简单的从0开始循环计算,n次方需要n次计算,时间复杂度仍为$\Theta(n)$,与前面的方法相同,但可以考虑乘方的如下性质
40+
41+
$$a^n=\begin{cases} a^{n/2}.a^{n/2} &\text{n为偶数} \\ a^{(n-1)/2}.a^{(n-1)/2}.a & \text{n为奇数} \end{cases}$$
42+
43+
但这种方法隐含的时间常数比较大(不是很懂),很少会有软件采用这种算法,另外这种算法实现复杂,有多个递归基,不适合面试。
44+
45+
### 拓展 青蛙跳台阶
46+
题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。
47+
48+
通过题目的描述,可以很清晰地看到,这就是一个Fibonacci数列。
49+
50+
题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级……也可以跳n级。求总共有多少总跳法,并分析算法的时间复杂度。
51+
52+
用f(n)表示青蛙上n级台阶的跳法数,设f(0)=1(f(0)的值代表从起点直接到达终点),所以有
53+
54+
f(1)=1
55+
56+
f(2)=f(1)+f(0)
57+
58+
...
59+
60+
f(n)=f(n-1)+f(n-2)+...+f(n-n)&nbsp; &nbsp; &nbsp; (a)
61+
62+
f(n-1)=f(n-2)+f(n-3)+...+f(n-n)&nbsp; &nbsp; &nbsp; (b)
63+
64+
(a)减去(b)整理之后得到$f(n)=2f(n-1)$
65+
66+
所以有递归公式如下:
67+
68+
$$f(n)=\begin{cases} 1 &\text{n=0}\\1 & \text{n=1}\\
69+
2*f(n-1) & \text{n>2}\end{cases}$$
70+
71+
### 拓展2 铺瓷砖问题
72+
我们可以用2x1的小矩形横着或者竖着取覆盖更大的矩阵,请问用8个2x1的小矩形取无重叠地覆盖一个2x8的大矩形,总共有多少种方法?
73+
74+
![斐波那契数列拓展2][1]
75+
<center><small> 斐波那契数列拓展2</small></center>
76+
77+
记2x8的覆盖方法记为f(8),用第一个1x2的小矩形取覆大矩形的的最左边时有两个选择,竖着放或者横着放,竖着放的时候,覆盖方法为f(7),横着放的时候,比如在左上角,则左下角也只能在横着放一个小矩形,因此,横着放的时候覆盖方法为f(6),因此f(8)=f(7)+f(6),可以看出这仍然是斐波那契数列。
78+
79+
80+
81+
## 代码
82+
### [c++代码](./src/cpp/二进制中1的个数.cpp)
83+
84+
```c++
85+
class Solution {
86+
public:
87+
int Fibonacci(int n) {
88+
int result[2]={0,1};
89+
if (n<2)
90+
return result[n];
91+
long long int f_zero=0, f_one=1,f_res=0;
92+
int count=1;
93+
while(count<n){
94+
f_res=f_zero+f_one;
95+
f_zero=f_one;
96+
f_one=f_res;
97+
count++;
98+
}
99+
return f_res;
100+
}
101+
};
102+
```
103+
104+
### [python代码](./src/python/二进制中1的个数.py)
105+
106+
```python
107+
108+
# -*- coding:utf-8 -*-
109+
class Solution:
110+
def Fibonacci(self, n):
111+
tempArray = [0, 1]
112+
if n >= 2:
113+
for i in range(2, n+1):
114+
tempArray[i%2] = tempArray[0] + tempArray[1]
115+
return tempArray[n%2]
116+
```
117+
118+
[1]:./img/斐波那契数列拓展2.png
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Solution {
2+
public:
3+
int Fibonacci(int n) {
4+
int result[2]={0,1};
5+
if (n<2)
6+
return result[n];
7+
long long int f_zero=0, f_one=1,f_res=0;
8+
int count=1;
9+
while(count<n){
10+
f_res=f_zero+f_one;
11+
f_zero=f_one;
12+
f_one=f_res;
13+
count++;
14+
}
15+
return f_res;
16+
}
17+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
# -*- coding:utf-8 -*-
3+
class Solution:
4+
def Fibonacci(self, n):
5+
tempArray = [0, 1]
6+
if n >= 2:
7+
for i in range(2, n+1):
8+
tempArray[i%2] = tempArray[0] + tempArray[1]
9+
return tempArray[n%2]
Loading
+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#递归 斐波那契数列
2+
3+
tags: 递归
4+
5+
---
6+
7+
## 题目原文
8+
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
9+
n<=39
10+
11+
## 解题思路
12+
### 低效率不实用的方法
13+
斐波那契数列的求解方法最容易些想到的就是如下的递归形式
14+
```c++
15+
long long Fibonacci(unsigned int n){
16+
if (n<=0)
17+
return 0;
18+
19+
if (n==1)
20+
return 1;
21+
22+
return Fibonacci(n-1)+Fibonacci(n-2)
23+
}
24+
```
25+
上面的递归形式看起来很简单,但效率却很低,因为在递归的过程中存在着大量的重复计算。例如,计算f(10)的时候需要计算f(8)和f(9),在计算f(9)的时候又要计算一遍f(8),因此,计算的时间复杂度会随着n的增大而指数级增大。
26+
27+
### 改进方法
28+
29+
上面的方法问题在于递归的过程存在大量的重复计算,因此可以考虑在计算的过程中把计算结果保存下来,比如建立一个数组保存中间计算结果,但这也不是好的方法,因为耗费了额外的内存空间。
30+
31+
换种思路,先根据f(0)和f(1)计算出f(2),再依次计算出f(3),f(4),...,f(n),这种计算方法的空间复杂度是常数,时间复杂度是$\Theta(n)$
32+
33+
### 代码
34+
#### [c++代码](./src/cpp/斐波那契数列.cpp)
35+
36+
```c++
37+
class Solution {
38+
public:
39+
int Fibonacci(int n) {
40+
int result[2]={0,1};
41+
if (n<2)
42+
return result[n];
43+
long long int f_zero=0, f_one=1,f_res=0;
44+
int count=1;
45+
while(count<n){
46+
f_res=f_zero+f_one;
47+
f_zero=f_one;
48+
f_one=f_res;
49+
count++;
50+
}
51+
return f_res;
52+
}
53+
};
54+
```
55+
56+
#### [python代码](./src/python/斐波那契数列.py)
57+
58+
```python
59+
60+
# -*- coding:utf-8 -*-
61+
class Solution:
62+
def Fibonacci(self, n):
63+
tempArray = [0, 1]
64+
if n >= 2:
65+
for i in range(2, n+1):
66+
tempArray[i%2] = tempArray[0] + tempArray[1]
67+
return tempArray[n%2]
68+
```
69+
70+
### 时间复杂度为$\Theta(logn)$但不是很实用的解法
71+
介绍解法之前先介绍下面的数学公式:
72+
73+
$$\begin{bmatrix}f(n)&f(n-1)\\f(n-1)&f(n-2) \end{bmatrix}=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$$
74+
75+
这个公式可以用数学归纳法证明,有了这个公示后,原来的问题就变成了求矩阵$=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$,若果只是简单的从0开始循环计算,n次方需要n次计算,时间复杂度仍为$\Theta(n)$,与前面的方法相同,但可以考虑乘方的如下性质
76+
77+
$$a^n=\begin{cases} a^{n/2}.a^{n/2} &\text{n为偶数} \\ a^{(n-1)/2}.a^{(n-1)/2}.a & \text{n为奇数} \end{cases}$$
78+
79+
但这种方法隐含的时间常数比较大(不是很懂),很少会有软件采用这种算法,另外这种算法实现复杂,有多个递归基,不适合面试。
80+
81+
82+
实现上面的方法时,需要定义一个2×2的矩阵,并且定义好矩阵的乘法以及乘方运算,比较麻烦,可以将递归公式转换一下形式:
83+
84+
85+
原理:观察:f(n)=f(n-1)+f(n-2)=2f(n-2)+f(n-3)=3f(n-3)+2f(n-4)=5f(n-4)+3f(n-5)=...=f(k).f(n-k+1)+f(k-1).f(n-k)
86+
87+
若令n=2k,则有f(2k)=f(k).f(k+1)+f(k-1).f(k)=f(k).(f(k)+f(k-1))+f(k-1).f(k)=f(k)^2+2.f(k).f(k-1)
88+
89+
若令n=2*k-1,则有f(2k-1)
90+
### 拓展 青蛙跳台阶
91+
题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。
92+
93+
通过题目的描述,可以很清晰地看到,这就是一个Fibonacci数列。
94+
95+
题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级……也可以跳n级。求总共有多少总跳法,并分析算法的时间复杂度。
96+
97+
用f(n)表示青蛙上n级台阶的跳法数,设f(0)=1(f(0)的值代表从起点直接到达终点),所以有
98+
99+
f(1)=1
100+
101+
f(2)=f(1)+f(0)
102+
103+
...
104+
105+
f(n)=f(n-1)+f(n-2)+...+f(n-n)&nbsp; &nbsp; &nbsp; (a)
106+
107+
f(n-1)=f(n-2)+f(n-3)+...+f(n-n)&nbsp; &nbsp; &nbsp; (b)
108+
109+
(a)减去(b)整理之后得到$f(n)=2f(n-1)$
110+
111+
所以有递归公式如下:
112+
113+
$$f(n)=\begin{cases} 1 &\text{n=0}\\1 & \text{n=1}\\
114+
2*f(n-1) & \text{n>2}\end{cases}$$
115+
116+
### 拓展2 铺瓷砖问题
117+
我们可以用2x1的小矩形横着或者竖着取覆盖更大的矩阵,请问用8个2x1的小矩形取无重叠地覆盖一个2x8的大矩形,总共有多少种方法?
118+
119+
![斐波那契数列拓展2][1]
120+
<center><small> 斐波那契数列拓展2</small></center>
121+
122+
记2x8的覆盖方法记为f(8),用第一个1x2的小矩形取覆大矩形的的最左边时有两个选择,竖着放或者横着放,竖着放的时候,覆盖方法为f(7),横着放的时候,比如在左上角,则左下角也只能在横着放一个小矩形,因此,横着放的时候覆盖方法为f(6),因此f(8)=f(7)+f(6),可以看出这仍然是斐波那契数列。
123+
124+
125+
[1]:./img/斐波那契数列拓展2.png
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Solution {
2+
public:
3+
int Fibonacci(int n) {
4+
int result[2]={0,1};
5+
if (n<2)
6+
return result[n];
7+
long long int f_zero=0, f_one=1,f_res=0;
8+
int count=1;
9+
while(count<n){
10+
f_res=f_zero+f_one;
11+
f_zero=f_one;
12+
f_one=f_res;
13+
count++;
14+
}
15+
return f_res;
16+
}
17+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
# -*- coding:utf-8 -*-
3+
class Solution:
4+
def Fibonacci(self, n):
5+
tempArray = [0, 1]
6+
if n >= 2:
7+
for i in range(2, n+1):
8+
tempArray[i%2] = tempArray[0] + tempArray[1]
9+
return tempArray[n%2]

0 commit comments

Comments
 (0)