一:零钱兑换

1. 记忆化搜索
本质上属于迭代,找出子目标数据的最小值,自顶向下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public: vector<int> count; int coinChange(vector<int>& coins, int amount) { count.resize(amount); return recursion(coins, amount); } int recursion(vector<int>& coins, int amount) { if (amount == 0) return 0; if (amount < 0) return -1; if (count[amount - 1] != 0) return count[amount - 1]; int minNum = INT_MAX; for (auto& coin : coins) { int temp = recursion(coins, amount - coin); if (temp >= 0 && temp < minNum) minNum = temp + 1; } count[amount - 1] = minNum == INT_MAX ? -1 : minNum; return count[amount - 1]; } };
|

2. 动态规划
使用动态规划的关键点在于找出状态转移方程,该题目可求出当前硬币对应的上一个目标值的最小硬币数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: int coinChange(vector<int>& coins, int amount) { int max = amount + 1; vector<int> count(amount + 1, max); count[0] = 0; for (int i = 1; i <= amount; ++i) { for (auto& coin : coins) { if (coin <= i) { count[i] = min(count[i], count[i - coin] + 1); } } } return count[amount] = count[amount] == amount + 1 ? -1 : count[amount]; } };
|

二:单词拆分

1. 动态规划
假设当前位于x,对于0 ~ x的子串需要寻找一个位置 j,使0 ~ j位于给定数组中,然后再判断j + 1 ~ x是否位于数组中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public: bool wordBreak(string s, vector<string>& wordDict) { unordered_set<string> hashWord; int len = s.size(); for (auto& word : wordDict) hashWord.insert(word); vector<bool> dp(len + 1); dp[0] = true; for (int i = 1; i <= len; ++i) for (int j = 0; j < i; ++j) if (dp[j] && hashWord.find(s.substr(j, i - j)) != hashWord.end()) { dp[i] = true; break; } return dp[len]; } };
|

三:最长递增子序列

1. 动态规划
使用一个数组来记录以给定数组的每个元素结尾的子序列的长度,如果当前值大于某个最长子序列的最后一个值,则把它加入
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution { public: int lengthOfLIS(vector<int>& nums) { int len = nums.size(); vector<int> dp(len, 1); for (int i = 0; i < len; ++i) for (int j = 0; j < i; ++j) if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1); return *max_element(dp.begin(), dp.end()); } };
|

2. 贪心+二分查找
使用一个数组来维护最长子序列的最后一个值,如果下个值大于最后一个值则加入,如果不大于则替换数组中首个大于该元素的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Solution { public: int lengthOfLIS(vector<int>& nums) { int len = nums.size(); int size = 1; vector<int> dp(len + 1, 0); dp[size] = nums[0]; for (int i = 1; i < len; ++i) { if (nums[i] > dp[size]) dp[++size] = nums[i]; else { int left = 1, right = size; int pos = 0; while (left <= right) { int mid = (left + right) >> 1; if (dp[mid] < nums[i]) { pos = mid; left = mid + 1; } else right = mid - 1; } dp[pos + 1] = nums[i]; } } return size; } };
|
