概述
定义:将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案。
- 设计感比较强
- 艺术性比较强
递归
原斐波那契数列,算法复杂度
1 2 3 4 5
| int fib(int n) { if (n == 0 || n == 1) return n; return fib(n - 1) + fib(n - 2); }
|
优化, 加入一个数组保存每次运算的值
记忆化搜索
自上而下的解
1 2 3 4 5 6 7 8 9
| vector<int> memo(n + 1, -1); int fib(int n) { if (n == 0 || n == 1) return n; if (memo[n] == -1) { memo[n] = fib(n - 1) + fib(n - 2); } return memo[n]; }
|
动态规划
自下而上的解
1 2 3 4 5 6 7 8 9 10
| int fib(int n) { vector<int> memo(n + 1, -1); memo[0] = 0; memo[1] = 1; for (int i = 2; i <= n; i ++) { memo[i] = memo[i - 1] + memo[i - 2]; } return memo[n]; }
|
LeetCode练习题
- No.120 Triangle
- No.64 Minimum Path Sum
例题:No.343 Integer Break
记忆化搜索:自顶向下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| int max3(int a, int b, int c) { return max(a, max(b, c)); } int breakInteger(int n, vector<int>& memo) { if (n == 1) return 1; if (memo[n] != -1) { return memo[n]; } int res = -1; for (int i = 1; i < n; i ++) { res = max3(res, i * (n - i), i * breakInteger(n - i, memo)); } memo[n] = res; return memo[n]; } int integerBreak(int n) { vector<int> memo(n+1, -1); return breakInteger(n, memo); }
|
动态规划:自下而上
1 2 3 4 5 6 7 8 9 10 11 12
| int integerBreak(int n ) { vector<int> memo(n + 1, -1); memo[1] = 1; for (int i = 2; i <= n; i ++) { for (int j = 1; j < i; j ++) { memo[i] = max3(memo[i], j * (i - j), j * memo[i - j]); } } return memo[n]; }
|
LeetCode练习题
No.279 Perfect Squares
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public: int numSquares(int n) { if (n <= 0) return 0; vector<int> step(n + 1, INT_MAX); step[0] = 0; step[1] = 1; for (int i = 2; i <= n; i ++) { int j = 1; while (i >= j) { step[i] = min(step[i], step[i - j * j] + 1); j ++; } } return step[n]; } };
|
No.91 Decode Ways
- No.62 Unique Paths
- No.63 Unique PathsII
例题:No.198 House Robber
状态转移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: int rob(vector<int>& nums) { if (nums.empty()) return 0; int n = nums.size(); if (n == 1) return nums[0]; vector<int> price(n + 1, 0); price[1] = nums[0]; price[2] = nums[1]; for (int i = 2; i < n; i++) { price[i + 1] = max(price[i - 1], price[i - 2]) + nums[i]; } return max(price[n], price[n - 1]); } };
|
LeetCode练习题
- No.213 House Robber II
- No.337 House Robber III
- No.309 Best Time to Buy and Sell Stock with Cooldown
看不懂,不会做啊啊啊!!!w(゚Д゚)w
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public: int maxProfit(vector<int>& prices) { int n = prices.size(); if (n == 0) return 0; vector<int> buy(n, 0); vector<int> sell(n, 0); vector<int> rest(n, 0); buy[0] = 0 - prices[0]; sell[0] = 0; rest[0] = 0; for (int i = 1; i < n; i ++) { buy[i] = max(rest[i - 1] - prices[i], buy[i - 1]); sell[i] = max(buy[i - 1] + prices[i], sell[i - 1]); rest[i] = sell[i - 1]; } return sell[n - 1]; } };
|
背包问题:
例题
练习题:
最长上升子序列
例题:No.300 Longest Increasint Subsequence
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int lengthOfLIS(vector<int> nums) { int n = nums.size(); if (n == 0) return 0; vector<int> len(n, 1); int res = 0; for (int i = 0; i < n; ++) { for (int j = i - 1; j >= 0; j --) { if (nums[i] > nums[j]) { len[i] = max(len[i], len[j] + 1); } } res = max(res, len[i]); } return res; }
|
LeetCode练习题
- No.376 Wiggle Subsequence
的解法,更好懂一些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: int wiggleMaxLength(vector<int>& nums) { int n = nums.size(); if (n == 0) return 0; vector<int> larger(n, 1); vector<int> less(n, 1); for (int i = 1; i < n; i ++) { for (int j = 0; j < i; j ++) { if (nums[i] > nums[j]) larger[i] = max(larger[i], less[j] + 1); if (nums[i] < nums[j]) { less[i] = max(less[i], larger[j] + 1); } } } return max(larger[n - 1], less[n - 1]); } };
|
的解法,我至今是懵逼的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public: int wiggleMaxLength(vector<int>& nums) { int n = nums.size(); if (n == 0) return 0; vector<int> larger(n, 1); vector<int> less(n, 1); for (int i = 1; i < n; i ++) { if (nums[i] > nums[i - 1]) { larger[i] = less[i - 1] + 1; less[i] = less[i - 1]; } if (nums[i] < nums[i - 1]) { less[i] = larger[i - 1] + 1; larger[i] = larger[i - 1]; } if (nums[i] == nums[i - 1]) { larger[i] = larger[i - 1]; less[i] = less[i - 1]; } } return max(larger[n - 1], less[n - 1]); } };
|
最长公共子序列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| int LCS(string a, string b) { int n = a.size(); int m = b.size(); if (n == 0 || m == 0) return 0; vector<vector<int>> memo(n, vector<int>(m + 1, 0)); for (int j = 1; j <= m; j ++) { memo[0][j] = max(memo[0][j - 1], a[0] == b[j - 1] ? 1 : 0); } for (int i = 1; i < n; i ++) { for (int j = 1; j <= m; j ++) { if (b[j - 1] == a[i]) { memo[i][j] = memo[i - 1][j - 1] + 1; } else { memo[i][j] = max(memo[i - 1][j], memo[i][j - 1]); } } } return memo[n - 1][m]; }
|
dijkstra单源最短路径算法
有权图最短路径