斐波那契数列
1、爬楼梯
T70. Climbing Stairs (Easy)
class Solution {
public:
int climbStairs(int n) {
if (n <= 1) return 1;
vector<int> dp(n);
dp[0] = 1; dp[1] = 2;
for (int i = 2; i < n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp.back();
}
};
2、强盗抢劫
T198. House Robber (Easy)
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
vector<int> dp = {nums[0], max(nums[0], nums[1])};
for (int i = 2; i < nums.size(); ++i) {
dp.push_back(max(nums[i] + dp[i - 2], dp[i - 1]));
}
return dp.back();
}
};
3、强盗在环形街区抢劫
T213. House Robber II (Medium)
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
return max(rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));
}
int rob(vector<int> &nums, int left, int right) {
if (right - left <= 1) return nums[left];
vector<int> dp(right, 0);
dp[left] = nums[left];
dp[left + 1] = max(nums[left], nums[left + 1]);
for (int i = left + 2; i < right; ++i) {
dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);
}
return dp.back();
}
};
1、矩阵的最小路径和
T64. Minimum Path Sum (Medium)
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
int m = grid.size(), n = grid[0].size();
vector<vector<int>> dp(m, vector<int>(n));
dp[0][0] = grid[0][0];
for (int i = 1; i < m; ++i) dp[i][0] = grid[i][0] + dp[i - 1][0];
for (int j = 1; j < n; ++j) dp[0][j] = grid[0][j] + dp[0][j - 1];
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[m - 1][n - 1];
}
};
2、矩阵的总路径数
T62. Unique Paths (Medium)
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> dp(n, 1);
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
dp[j] += dp[j - 1];
}
}
return dp[n - 1];
}
};
1、数组区间和
T303. Range Sum Query - Immutable (Easy)
class NumArray {
public:
NumArray(vector<int> &nums) {
dp = nums;
for (int i = 1; i < nums.size(); ++i) {
dp[i] += dp[i - 1];
}
}
int sumRange(int i, int j) {
return i == 0? dp[j] : dp[j] - dp[i - 1];
}
private:
vector<int> dp;
};
2、数组中等差递增子区间的个数
T413. Arithmetic Slices (Medium)
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
int res = 0, len = 2, n = A.size();
for (int i = 2; i < n; ++i) {
if (A[i] - A[i - 1] == A[i - 1] - A[i - 2]) {
++len;
} else {
if (len > 2) res += (len - 1) * (len - 2) * 0.5;
len = 2;
}
}
if (len > 2) res += (len - 1) * (len - 2) * 0.5;
return res;
}
};
1、分割整数的最大乘积
T343. Integer Break (Medim)
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n + 1, 1);
for (int i = 3; i <= n; ++i) {
for (int j = 1; j < i; ++j) {
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]));
}
}
return dp[n];
}
};
2、按平方数来分割整数
T279. Perfect Squares(Medium)
class Solution {
public:
int numSquares(int n) {
vector<int> result(n+1, 0x7FFFFFFF); // 每个数的最优解都存在result数组里
result[0] = 0;
for (int i = 1; i <= n; i++){
for(int j = 1; i-j*j >= 0 ; j++) { // 观察比N小的数,且符合N = IxI + N'的数值
result[i] = min(result[i], result[i-j*j] + 1); // 把最优解(最小值)+ 1 写入result
}
}
return result[n];
}
};
3、分割整数构成字母字符串
T91. Decode Ways (Medium)
class Solution {
public:
int numDecodings(string s) {
if (s.empty() || s[0] == '0') return 0;
vector<int> dp(s.size() + 1, 0);
dp[0] = 1;
for (int i = 1; i < dp.size(); ++i) {
dp[i] = (s[i - 1] == '0') ? 0 : dp[i - 1];
if (i > 1 && (s[i - 2] == '1' || (s[i - 2] == '2' && s[i - 1] <= '6'))) {
dp[i] += dp[i - 2];
}
}
return dp.back();
}
};
1、最长递增子序列
T300. Longest Increasing Subsequence (Medium)
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> dp(nums.size(), 1);
int res = 0;
for (int i = 0; i < nums.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
res = max(res, dp[i]);
}
return res;
}
};
2、一组整数对能够构成的最长链
T646. Maximum Length of Pair Chain (Medium)
class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
stack<vector<int>> st;
sort(pairs.begin(), pairs.end(), [](vector<int>& a, vector<int>& b) {
return a[1] < b[1];
});
for (auto pair : pairs) {
if (st.empty()) st.push(pair);
else {
auto t = st.top();
if (pair[0] > t[1]) st.push(pair);
}
}
return st.size();
}
};
3、最长摆动子序列
T376. Wiggle Subsequence (Medium)
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if (nums.empty()) return 0;
vector<int> p(nums.size(), 1);
vector<int> q(nums.size(), 1);
for (int i = 1; i < nums.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) p[i] = max(p[i], q[j] + 1);
else if (nums[i] < nums[j]) q[i] = max(q[i], p[j] + 1);
}
}
return max(p.back(), q.back());
}
};
1、最长公共子序列
T1143. Longest Common Subsequence
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int n=text1.size(),m=text2.size();
int dp[m+1],last=0,temp;
fill(dp,dp+m+1,0);
for(int i=1;i<=n;++i,last=0){
for(int j=1;j<=m;++j){
temp=dp[j];
if(text1[i-1]==text2[j-1]) dp[j]=last+1;
else dp[j]=max(dp[j],dp[j-1]);
last=temp;
}
}
return dp[m];
}
};
1、划分数组为和相等的两部分
T416. Partition Equal Subset Sum (Medium)
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0), target = sum >> 1;
if (sum & 1) return false;
vector<bool> dp(target + 1, false);
dp[0] = true;
for (int num : nums) {
for (int i = target; i >= num; --i) {
dp[i] = dp[i] || dp[i - num];
}
}
return dp[target];
}
};
2、改变一组数的正负号使得它们的和为一给定数
T494. Target Sum (Medium)
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int res = 0;
helper(nums, S, 0, res);
return res;
}
void helper(vector<int>& nums, long S, int start, int& res) {
if (start >= nums.size()) {
if (S == 0) ++res;
return;
}
helper(nums, S - nums[start], start + 1, res);
helper(nums, S + nums[start], start + 1, res);
}
};
3、01 字符构成最多的字符串
T474. Ones and Zeroes (Medium)
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
for (string str : strs) {
int zeros = 0, ones = 0;
for (char c : str) (c == '0') ? ++zeros : ++ones;
for (int i = m; i >= zeros; --i) {
for (int j = n; j >= ones; --j) {
dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1);
}
}
}
return dp[m][n];
}
};
4、找零钱的最少硬币数
T322. Coin Change (Medium)
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 1, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int j = 0; j < coins.size(); ++j) {
if (coins[j] <= i) {
dp[i] = min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return (dp[amount] > amount) ? -1 : dp[amount];
}
};
5、找零钱的硬币数组合
T518. Coin Change 2 (Medium)
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<vector<int>> dp(coins.size() + 1, vector<int>(amount + 1, 0));
dp[0][0] = 1;
for (int i = 1; i <= coins.size(); ++i) {
dp[i][0] = 1;
for (int j = 1; j <= amount; ++j) {
dp[i][j] = dp[i - 1][j] + (j >= coins[i - 1] ? dp[i][j - coins[i - 1]] : 0);
}
}
return dp[coins.size()][amount];
}
};
6、字符串按单词列表分割
T139. Word Break (Medium)
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size() + 1);
dp[0] = true;
for (int i = 0; i < dp.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (dp[j] && wordSet.count(s.substr(j, i - j))) {
dp[i] = true;
break;
}
}
}
return dp.back();
}
};
7、组合总和
T377. Combination Sum IV (Medium)
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target + 1, 0);
dp[0] = 1;
for (int i = 0; i <= target; i++) {
for (int j = 0; j < nums.size(); j++) {
if (i < nums[j]) continue;
dp[i] = (dp[i] >= INT_MAX - dp[i - nums[j]]) ? INT_MAX : dp[i] + dp[i - nums[j]];
}
}
return dp[target];
}
};
1、需要冷却期的股票交易
T309. Best Time to Buy and Sell Stock with Cooldown(Medium)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int buy = INT_MIN, pre_buy = 0, sell = 0, pre_sell = 0;
for (int price : prices) {
pre_buy = buy;
buy = max(pre_sell - price, pre_buy);
pre_sell = sell;
sell = max(pre_buy + price, pre_sell);
}
return sell;
}
};
2、需要交易费用的股票交易
T714. Best Time to Buy and Sell Stock with Transaction Fee (Medium)
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
vector<int> sold(prices.size(), 0), hold = sold;
hold[0] = -prices[0];
for (int i = 1; i < prices.size(); ++i) {
sold[i] = max(sold[i - 1], hold[i - 1] + prices[i] - fee);
hold[i] = max(hold[i - 1], sold[i - 1] - prices[i]);
}
return sold.back();
}
};
3、只能进行两次的股票交易
T123. Best Time to Buy and Sell Stock III (Hard)
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size()==0) return 0;
int *dp=new int[prices.size()];
int *dp_2=new int[prices.size()];
int ans=0;
left(prices,dp);
right(prices,dp_2);
for(int i=0;i<prices.size();i++)
ans=max(ans,dp[i]+dp_2[i]);
return ans;
}
void left( vector<int> prices, int *&dp)
{
int ans=0;
int low=prices[0];
for(int i=0;i<prices.size();i++)
{
ans=max(ans,prices[i]-low);
dp[i]=ans;
low=min(low,prices[i]);
}
}
void right(vector<int> prices,int *&dp)
{
int ans=0;
int high=prices[prices.size()-1];
for(int i=prices.size()-1;i>=0;i--)
{
ans=max(ans,high-prices[i]);
dp[i]=ans;
high=max(high,prices[i]);
}
}
};
4、只能进行 k 次的股票交易
T188. Best Time to Buy and Sell Stock IV (Hard)
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
if (prices.size() <= 1) return 0;
//std::vector> dp(k+1, {-prices[0], 0});
// 这里有一个隐藏很深的 bug, 就如果 k 的值很大, 就会直接把栈爆掉!!
// 所以应该按照 k 值做优化, 将 vector 声明在 if 语句内部
if (k < prices.size() / 2) {
std::vector<std::pair<int, int>> dp(k+1, {-prices[0], 0});
for(int i=1;i<prices.size();i++)
{
for(int j=1; j < k+1; j++)
{
int hold = std::max(dp[j].first, dp[j-1].second-prices[i]);
int not_hold = std::max(dp[j].second, dp[j].first+prices[i]);
dp[j].first = hold; dp[j].second = not_hold;
}
}
return dp[k].second; //max(dp[k].first, dp[k].second);
} else {
std::pair<int, int> dp = {-prices[0], 0};
for (int i=1; i<prices.size(); i++) {
int hold = std::max(dp.first, dp.second-prices[i]);
int not_hold = std::max(dp.second, dp.first+prices[i]);
dp.first = hold; dp.second = not_hold;
}
return dp.second;
}
}
};
1、删除两个字符串的字符使它们相等
T583. Delete Operation for Two Strings (Medium)
class Solution {
public:
int minDistance(string word1, string word2) {
int n1 = word1.size(), n2 = word2.size();
vector<vector<int>> dp(n1 + 1, vector<int>(n2 + 1, 0));
for (int i = 1; i <= n1; ++i) {
for (int j = 1; j <= n2; ++j) {
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return n1 + n2 - 2 * dp[n1][n2];
}
};
2、编辑距离
T72. Edit Distance (Hard)
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 0; i <= m; ++i) dp[i][0] = i;
for (int i = 0; i <= n; ++i) dp[0][i] = i;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
}
}
}
return dp[m][n];
}
};
3、复制粘贴字符
T650. 2 Keys Keyboard (Medium)
class Solution {
public:
int minSteps(int n) {
if (n == 1) return 0;
int res = n;
for (int i = n - 1; i > 1; --i) {
if (n % i == 0) {
res = min(res, minSteps(n / i) + i);
}
}
return res;
}
};