Skip to content

Commit 6850cba

Browse files
committed
Chapter 09 Optional 01 codes added.
1 parent 2f6c887 commit 6850cba

File tree

8 files changed

+276
-1
lines changed

8 files changed

+276
-1
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
cmake_minimum_required(VERSION 3.5)
2+
project(Optional_01_More_about_Fibonacci)
3+
4+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
5+
6+
set(SOURCE_FILES main.cpp)
7+
add_executable(Optional_01_More_about_Fibonacci ${SOURCE_FILES})
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <iostream>
2+
#include <vector>
3+
#include <cassert>
4+
5+
using namespace std;
6+
7+
/// 70. Climbing Stairs
8+
/// https://leetcode.com/problems/climbing-stairs/description/
9+
///
10+
/// 在这一章的学习中, 我们看到了, 70号问题本质就是求斐波那契数
11+
/// 只不过 climbStairs(n) 的答案, 对应第 n+1 个斐波那契数
12+
/// 其中 f0 = 0, f(1) = 1, f(2) = 1, f(3) = 2...
13+
/// 首先, 我们可以非常简单的使用O(1)的空间求出斐波那契数
14+
/// 这个对空间的优化和我们在这个课程中所介绍的背包问题的空间优化, 其实是类似的思想
15+
/// 我们对背包问题的空间优化, 从O(n^2)优化到了O(n)
16+
/// 我们对斐波那契问题的优化,可以从O(n)优化到O(1)
17+
/// 依靠的依然是, 求第n个斐波那契数, 我们只需要n-1和n-2两个斐波那契数,
18+
/// 更小的斐波那契数不需要一直保存。
19+
///
20+
/// Time Complexity: O(n)
21+
/// Space Complexity: O(1)
22+
class Solution {
23+
24+
public:
25+
int climbStairs(int n) {
26+
27+
assert(n > 0);
28+
29+
if(n == 1)
30+
return 1;
31+
32+
int prev = 1, cur = 1;
33+
for(int i = 3 ; i <= n + 1; i ++){
34+
int f = cur + prev;
35+
prev = cur;
36+
cur = f;
37+
}
38+
return cur;
39+
}
40+
};
41+
42+
int main() {
43+
44+
cout << Solution().climbStairs(10) << endl;
45+
return 0;
46+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include <iostream>
2+
#include <vector>
3+
#include <cassert>
4+
5+
using namespace std;
6+
7+
/// 70. Climbing Stairs
8+
/// https://leetcode.com/problems/climbing-stairs/description/
9+
///
10+
/// 斐波那契数可以根据一个特殊矩阵的幂的形式求出。
11+
/// | F(n+1) F(n) | = | 1 1 |^n
12+
/// | F(n) F(n-1) | | 1 0 |
13+
/// 幂运算可以使用分治法, 优化为O(logn)的复杂度
14+
/// 具体该方法的证明, 有兴趣的同学可以自行在互联网上搜索学习。
15+
///
16+
/// Time Complexity: O(logn)
17+
/// Space Complexity: O(1)
18+
class Solution {
19+
20+
public:
21+
int climbStairs(int n) {
22+
23+
assert(n > 0);
24+
25+
if(n == 1)
26+
return 1;
27+
28+
vector<vector<int>> base = {{1, 1}, {1, 0}};
29+
return matrix_pow(base, n)[0][0];
30+
}
31+
32+
private:
33+
vector<vector<int>> matrix_pow(const vector<vector<int>>& m, int n){
34+
35+
if(n == 1)
36+
return m;
37+
38+
vector<vector<int>> t = matrix_pow(m, n / 2);
39+
vector<vector<int>> res = matrix_multiply(t, t);
40+
if(n % 2)
41+
return matrix_multiply(res, m);
42+
return res;
43+
}
44+
45+
vector<vector<int>> matrix_multiply(const vector<vector<int>>& m1,
46+
const vector<vector<int>>& m2){
47+
vector<vector<int>> res(2, vector<int>(2, 0));
48+
res[0][0] = m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0];
49+
res[0][1] = m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1];
50+
res[1][0] = m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0];
51+
res[1][1] = m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1];
52+
return res;
53+
}
54+
};
55+
56+
int main() {
57+
58+
cout << Solution().climbStairs(10) << endl;
59+
return 0;
60+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/// Source : https://leetcode.com/problems/climbing-stairs/description/
2+
/// Author : liuyubobobo
3+
/// Time : 2017-11-20
4+
5+
#include <iostream>
6+
#include <cmath>
7+
#include <cassert>
8+
9+
using namespace std;
10+
11+
/// 70. Climbing Stairs
12+
/// https://leetcode.com/problems/climbing-stairs/description/
13+
///
14+
/// 对于第n个斐波那契数, 可以推导出其公式
15+
/// Fn = 1/sqrt(5) * {[(1+sqrt(5))/2]^n - [(1-sqrt(5))/2]^n}
16+
/// 具体推导过程, 有兴趣的同学可以自行在互联网上搜索学习。
17+
/// 注意: 这个方法的时间复杂度依然是O(logn)的,因为数的幂运算也需要logn的时间
18+
/// 但这个方法快于使用矩阵的幂运算符的方法
19+
///
20+
/// Time Complexity: O(logn)
21+
/// Space Complexity: O(1)
22+
class Solution {
23+
24+
public:
25+
int climbStairs(int n) {
26+
27+
assert(n > 0);
28+
29+
if(n == 1)
30+
return 1;
31+
32+
double sqrt5 = sqrt(5.0);
33+
return (int)((pow((1 + sqrt5) / 2, n + 1) - pow((1 - sqrt5) / 2, n + 1)) / sqrt5);
34+
}
35+
36+
};
37+
38+
int main() {
39+
40+
cout << Solution().climbStairs(10) << endl;
41+
return 0;
42+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/// 70. Climbing Stairs
2+
/// https://leetcode.com/problems/climbing-stairs/description/
3+
///
4+
/// 在这一章的学习中, 我们看到了, 70号问题本质就是求斐波那契数
5+
/// 只不过 climbStairs(n) 的答案, 对应第 n+1 个斐波那契数
6+
/// 其中 f0 = 0, f(1) = 1, f(2) = 1, f(3) = 2...
7+
/// 首先, 我们可以非常简单的使用O(1)的空间求出斐波那契数
8+
/// 这个对空间的优化和我们在这个课程中所介绍的背包问题的空间优化, 其实是类似的思想
9+
/// 我们对背包问题的空间优化, 从O(n^2)优化到了O(n)
10+
/// 我们对斐波那契问题的优化,可以从O(n)优化到O(1)
11+
/// 依靠的依然是, 求第n个斐波那契数, 我们只需要n-1和n-2两个斐波那契数,
12+
/// 更小的斐波那契数不需要一直保存。
13+
///
14+
/// Time Complexity: O(n)
15+
/// Space Complexity: O(1)
16+
public class Solution1 {
17+
18+
public int climbStairs(int n) {
19+
20+
if(n <= 0)
21+
throw new IllegalArgumentException("n must be greater than zero");
22+
23+
if(n == 1)
24+
return 1;
25+
26+
int prev = 1, cur = 1;
27+
for(int i = 3 ; i <= n + 1; i ++){
28+
int f = cur + prev;
29+
prev = cur;
30+
cur = f;
31+
}
32+
return cur;
33+
}
34+
35+
public static void main(String[] args) {
36+
37+
System.out.println((new Solution1()).climbStairs(10));
38+
}
39+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/// 70. Climbing Stairs
2+
/// https://leetcode.com/problems/climbing-stairs/description/
3+
///
4+
/// 斐波那契数可以根据一个特殊矩阵的幂的形式求出。
5+
/// | F(n+1) F(n) | = | 1 1 |^n
6+
/// | F(n) F(n-1) | | 1 0 |
7+
/// 幂运算可以使用分治法, 优化为O(logn)的复杂度
8+
/// 具体该方法的证明, 有兴趣的同学可以自行在互联网上搜索学习。
9+
///
10+
/// Time Complexity: O(logn)
11+
/// Space Complexity: O(1)
12+
public class Solution2 {
13+
14+
public int climbStairs(int n) {
15+
16+
if(n <= 0)
17+
throw new IllegalArgumentException("n must be greater than zero");
18+
19+
if(n == 1)
20+
return 1;
21+
22+
int[][] base = {{1, 1}, {1, 0}};
23+
return matrix_pow(base, n)[0][0];
24+
}
25+
26+
private int[][] matrix_pow(int[][] m, int n){
27+
28+
if(n == 1)
29+
return m;
30+
31+
int[][] t = matrix_pow(m, n / 2);
32+
int[][] res = matrix_multiply(t, t);
33+
if(n % 2 == 1)
34+
return matrix_multiply(res, m);
35+
return res;
36+
}
37+
38+
int[][] matrix_multiply(int[][] m1, int[][] m2){
39+
int[][] res = new int[2][2];
40+
res[0][0] = m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0];
41+
res[0][1] = m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1];
42+
res[1][0] = m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0];
43+
res[1][1] = m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1];
44+
return res;
45+
}
46+
47+
public static void main(String[] args) {
48+
49+
System.out.println((new Solution2()).climbStairs(10));
50+
}
51+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/// 70. Climbing Stairs
2+
/// https://leetcode.com/problems/climbing-stairs/description/
3+
///
4+
/// 对于第n个斐波那契数, 可以推导出其公式
5+
/// Fn = 1/sqrt(5) * {[(1+sqrt(5))/2]^n - [(1-sqrt(5))/2]^n}
6+
/// 具体推导过程, 有兴趣的同学可以自行在互联网上搜索学习。
7+
/// 注意: 这个方法的时间复杂度依然是O(logn)的,因为数的幂运算也需要logn的时间
8+
/// 但这个方法快于使用矩阵的幂运算符的方法
9+
///
10+
/// Time Complexity: O(logn)
11+
/// Space Complexity: O(1)
12+
public class Solution3 {
13+
14+
public int climbStairs(int n) {
15+
16+
if(n <= 0)
17+
throw new IllegalArgumentException("n must be greater than zero");
18+
19+
if(n == 1)
20+
return 1;
21+
22+
double sqrt5 = Math.sqrt(5.0);
23+
return (int)((Math.pow((1 + sqrt5) / 2, n + 1) - Math.pow((1 - sqrt5) / 2, n + 1)) / sqrt5);
24+
}
25+
26+
public static void main(String[] args) {
27+
28+
System.out.println((new Solution3()).climbStairs(10));
29+
}
30+
}

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120
| 9-7 面试中的0-1背包问题 Partition Equal Subset Sum | [C++源码](https://github.com/liuyubobobo/Play-with-Algorithm-Interview/tree/master/09-Dynamic-Programming/Course%20Code%20(C%2B%2B)/07-Partition-Equal-Subset-Sum/) | [Java源码](09-Dynamic-Programming/Course%20Code%20(Java)/07-Partition-Equal-Subset-Sum/src/) |
121121
| 9-8 LIS问题 Longest Increasing Subsequence | [C++源码](https://github.com/liuyubobobo/Play-with-Algorithm-Interview/tree/master/09-Dynamic-Programming/Course%20Code%20(C%2B%2B)/08-Longest-Increasing-Subsequence/) | [Java源码](09-Dynamic-Programming/Course%20Code%20(Java)/08-Longest-Increasing-Subsequence/src/) |
122122
| 9-9 LCS,最短路,求动态规划的具体解以及更多 | [C++源码](https://github.com/liuyubobobo/Play-with-Algorithm-Interview/tree/master/09-Dynamic-Programming/Course%20Code%20(C%2B%2B)/09-Longest-Common-Subsequence/) | [Java源码](09-Dynamic-Programming/Course%20Code%20(Java)/09-Longest-Common-Subsequence/src/) |
123-
| 补充代码1:更多和斐波那契数相关 | [整理中] | [敬请期待] |
123+
| 补充代码1:更多和斐波那契数相关 | [C++](09-Dynamic-Programming/Course%20Code%20(C%2B%2B)/Optional-01-More-about-Fibonacci/) | [Java](09-Dynamic-Programming/Course%20Code%20(Java)/Optional-01-More-about-Fibonacci/src/) |
124124
| 补充代码2:LIS问题的O(nlogn)解法 | [整理中] | [敬请期待] |
125125
| 补充代码3:更多和背包问题相关 | [整理中] | [敬请期待] |
126126
| 补充代码4:另一个经典DP模型:回文子串数 | [整理中] | [敬请期待] |

0 commit comments

Comments
 (0)