Skip to content

Commit 81730e0

Browse files
committed
Chapter 09 Optional 02 codes added.
1 parent 6850cba commit 81730e0

File tree

11 files changed

+180
-14
lines changed

11 files changed

+180
-14
lines changed

09-Dynamic-Programming/Course Code (C++)/Optional-01-More-about-Fibonacci/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ project(Optional_01_More_about_Fibonacci)
33

44
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
55

6-
set(SOURCE_FILES main.cpp)
6+
set(SOURCE_FILES main3.cpp)
77
add_executable(Optional_01_More_about_Fibonacci ${SOURCE_FILES})

09-Dynamic-Programming/Course Code (C++)/Optional-01-More-about-Fibonacci/main1.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ using namespace std;
1717
/// 依靠的依然是, 求第n个斐波那契数, 我们只需要n-1和n-2两个斐波那契数,
1818
/// 更小的斐波那契数不需要一直保存。
1919
///
20-
/// Time Complexity: O(n)
21-
/// Space Complexity: O(1)
20+
/// 时间复杂度: O(n)
21+
/// 空间复杂度: O(1)
2222
class Solution {
2323

2424
public:

09-Dynamic-Programming/Course Code (C++)/Optional-01-More-about-Fibonacci/main2.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ using namespace std;
1313
/// 幂运算可以使用分治法, 优化为O(logn)的复杂度
1414
/// 具体该方法的证明, 有兴趣的同学可以自行在互联网上搜索学习。
1515
///
16-
/// Time Complexity: O(logn)
17-
/// Space Complexity: O(1)
16+
/// 时间复杂度: O(logn)
17+
/// 空间复杂度: O(1)
1818
class Solution {
1919

2020
public:

09-Dynamic-Programming/Course Code (C++)/Optional-01-More-about-Fibonacci/main3.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ using namespace std;
1717
/// 注意: 这个方法的时间复杂度依然是O(logn)的,因为数的幂运算也需要logn的时间
1818
/// 但这个方法快于使用矩阵的幂运算符的方法
1919
///
20-
/// Time Complexity: O(logn)
21-
/// Space Complexity: O(1)
20+
/// 时间复杂度: O(logn)
21+
/// 空间复杂度: O(1)
2222
class Solution {
2323

2424
public:
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_02_More_about_LIS)
3+
4+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
5+
6+
set(SOURCE_FILES main.cpp)
7+
add_executable(Optional_02_More_about_LIS ${SOURCE_FILES})
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include <iostream>
2+
#include <vector>
3+
#include <cassert>
4+
5+
using namespace std;
6+
7+
/// 300. Longest Increasing Subsequence
8+
/// https://leetcode.com/problems/longest-increasing-subsequence/description/
9+
///
10+
/// 我们这一章介绍的动态规划法求解LIS问题, 时间复杂度为O(nlogn)的
11+
/// LIS有一个经典的, 同时也非常巧妙的动态规划方法, 其时间复杂度为O(nlogn)的
12+
/// 以下为参考代码和简单注释, 如果需要更详细的解释, 大家可以自行在互联网上搜索学习
13+
/// 通过这个例子, 也请大家再体会改变动态规划的状态定义,
14+
/// 带来解决问题方法的重大不同, 甚至是时间复杂度数量级上的巨大优化
15+
///
16+
/// 时间复杂度: O(nlogn)
17+
/// 空间复杂度: O(n)
18+
class Solution {
19+
20+
public:
21+
int lengthOfLIS(vector<int>& nums) {
22+
23+
if(nums.size() == 0)
24+
return 0;
25+
26+
// dp[i] 表示最长长度为i的递增子序列, 最后一个数字的最小值
27+
vector<int> dp(nums.size() + 1, INT_MIN);
28+
dp[1] = nums[0];
29+
int len = 1;
30+
for(int i = 1 ; i < nums.size() ; i ++) {
31+
if(nums[i] > dp[len]){
32+
len ++;
33+
dp[len] = nums[i];
34+
}
35+
else{
36+
// 我们的dp数组将是一个单调递增的数组, 所以可以使用二分查找法
37+
vector<int>::iterator iter = lower_bound(dp.begin(), dp.begin() + (len + 1), nums[i]);
38+
if(*iter != nums[i]){
39+
int index = iter - dp.begin();
40+
assert(index >= 1 && index <= len);
41+
dp[index] = min(dp[index], nums[i]);
42+
}
43+
}
44+
}
45+
46+
return len;
47+
}
48+
};
49+
50+
int main() {
51+
52+
int nums1[] = {10, 9, 2, 5, 3, 7, 101, 18};
53+
vector<int> vec1(nums1, nums1 + sizeof(nums1)/sizeof(int));
54+
cout << Solution().lengthOfLIS(vec1) << endl;
55+
// 4
56+
57+
// ---
58+
59+
int nums2[] = {4, 10, 4, 3, 8, 9};
60+
vector<int> vec2(nums2, nums2 + sizeof(nums2)/sizeof(int));
61+
cout << Solution().lengthOfLIS(vec2) << endl;
62+
// 3
63+
64+
// ---
65+
66+
int nums3[] = {2, 2};
67+
vector<int> vec3(nums3, nums3 + sizeof(nums3)/sizeof(int));
68+
cout << Solution().lengthOfLIS(vec3) << endl;
69+
// 1
70+
71+
// ---
72+
73+
int nums4[] = {1, 3, 6, 7, 9, 4, 10, 5, 6};
74+
vector<int> vec4(nums4, nums4 + sizeof(nums4)/sizeof(int));
75+
cout << Solution().lengthOfLIS(vec4) << endl;
76+
// 6
77+
78+
return 0;
79+
}

09-Dynamic-Programming/Course Code (Java)/Optional-01-More-about-Fibonacci/src/Solution1.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
/// 依靠的依然是, 求第n个斐波那契数, 我们只需要n-1和n-2两个斐波那契数,
1212
/// 更小的斐波那契数不需要一直保存。
1313
///
14-
/// Time Complexity: O(n)
15-
/// Space Complexity: O(1)
14+
/// 时间复杂度: O(n)
15+
/// 空间复杂度: O(1)
1616
public class Solution1 {
1717

1818
public int climbStairs(int n) {

09-Dynamic-Programming/Course Code (Java)/Optional-01-More-about-Fibonacci/src/Solution2.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
/// 幂运算可以使用分治法, 优化为O(logn)的复杂度
88
/// 具体该方法的证明, 有兴趣的同学可以自行在互联网上搜索学习。
99
///
10-
/// Time Complexity: O(logn)
11-
/// Space Complexity: O(1)
10+
/// 时间复杂度: O(logn)
11+
/// 空间复杂度: O(1)
1212
public class Solution2 {
1313

1414
public int climbStairs(int n) {

09-Dynamic-Programming/Course Code (Java)/Optional-01-More-about-Fibonacci/src/Solution3.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
/// 注意: 这个方法的时间复杂度依然是O(logn)的,因为数的幂运算也需要logn的时间
88
/// 但这个方法快于使用矩阵的幂运算符的方法
99
///
10-
/// Time Complexity: O(logn)
11-
/// Space Complexity: O(1)
10+
/// 时间复杂度: O(logn)
11+
/// 空间复杂度: O(1)
1212
public class Solution3 {
1313

1414
public int climbStairs(int n) {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import java.util.Arrays;
2+
3+
/// 300. Longest Increasing Subsequence
4+
/// https://leetcode.com/problems/longest-increasing-subsequence/description/
5+
///
6+
/// 我们这一章介绍的动态规划法求解LIS问题, 时间复杂度为O(nlogn)的
7+
/// LIS有一个经典的, 同时也非常巧妙的动态规划方法, 其时间复杂度为O(nlogn)的
8+
/// 以下为参考代码和简单注释, 如果需要更详细的解释, 大家可以自行在互联网上搜索学习
9+
/// 通过这个例子, 也请大家再体会改变动态规划的状态定义,
10+
/// 带来解决问题方法的重大不同, 甚至是时间复杂度数量级上的巨大优化
11+
///
12+
/// 时间复杂度: O(nlogn)
13+
/// 空间复杂度: O(n)
14+
public class Solution {
15+
16+
public int lengthOfLIS(int[] nums) {
17+
18+
if(nums.length == 0)
19+
return 0;
20+
21+
// dp[i] 表示最长长度为i的递增子序列, 最后一个数字的最小值
22+
int dp[] = new int[nums.length + 1];
23+
Arrays.fill(dp, Integer.MIN_VALUE);
24+
25+
int len = 1;
26+
dp[1] = nums[0];
27+
for(int i = 1 ; i < nums.length ; i ++)
28+
if(nums[i] > dp[len]){
29+
len ++;
30+
dp[len] = nums[i];
31+
}
32+
else{
33+
// 我们的dp数组将是一个单调递增的数组, 所以可以使用二分查找法
34+
int index = lowerBound(dp, 0, len, nums[i]);
35+
if(dp[index] != nums[i])
36+
dp[index] = Math.min(dp[index], nums[i]);
37+
}
38+
39+
return len;
40+
}
41+
42+
// lowerBound求出arr[l...r]范围里,大于等于target的第一个元素所在的索引
43+
private int lowerBound(int[] arr, int l, int r, int target){
44+
45+
int left = l, right = r + 1;
46+
while(left != right){
47+
int mid = left + (right - left) / 2;
48+
if(arr[mid] >= target)
49+
right = mid;
50+
else // arr[mid] < target
51+
left = mid + 1;
52+
}
53+
return left;
54+
}
55+
56+
public static void main(String[] args) {
57+
58+
int nums1[] = {10, 9, 2, 5, 3, 7, 101, 18};
59+
System.out.println((new Solution()).lengthOfLIS(nums1));
60+
// 4
61+
62+
// ---
63+
64+
int nums2[] = {4, 10, 4, 3, 8, 9};
65+
System.out.println((new Solution()).lengthOfLIS(nums2));
66+
// 3
67+
68+
// ---
69+
70+
int nums3[] = {2, 2};
71+
System.out.println((new Solution()).lengthOfLIS(nums3));
72+
// 1
73+
74+
// ---
75+
76+
int nums4[] = {1, 3, 6, 7, 9, 4, 10, 5, 6};
77+
System.out.println((new Solution()).lengthOfLIS(nums4));
78+
// 6
79+
}
80+
}

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
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/) |
123123
| 补充代码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/) |
124-
| 补充代码2:LIS问题的O(nlogn)解法 | [整理中] | [敬请期待] |
124+
| 补充代码2:LIS问题的O(nlogn)解法 | [C++](09-Dynamic-Programming/Course%20Code%20(C%2B%2B)/Optional-02-More-about-LIS/) | [Java](09-Dynamic-Programming/Course%20Code%20(Java)/Optional-02-More-about-LIS/src/) |
125125
| 补充代码3:更多和背包问题相关 | [整理中] | [敬请期待] |
126126
| 补充代码4:另一个经典DP模型:回文子串数 | [整理中] | [敬请期待] |
127127
| **第十章:贪心算法** | [章节C++源码](https://github.com/liuyubobobo/Play-with-Algorithm-Interview/tree/master/10-Greedy-Algorithms/Course%20Code%20(C%2B%2B)/) | [章节Java源码](10-Greedy-Algorithms/Course%20Code%20(Java)/) |

0 commit comments

Comments
 (0)