一、打家劫舍(动态规划)
class Solution
{
public:
int rob(vector<int>& nums)
{
if (nums.size()==0)
return 0;
if (nums.size() == 1)
return nums[0];
int n = nums.size();
vector<int> dp(n, 0);
//从后往前填表,从而避免递归的重复计算。最终结果是dp[0]。
dp[n - 1] = nums[n - 1];
dp[n - 2] = max(nums[n - 2], nums[n - 1]);
for (int i = n - 3; i >= 0; i--)
{
dp[i] = max(nums[i] + dp[i + 2], dp[i + 1]);
}
return dp[0];
}
};
//优化空间复杂度
class Solution
{
public:
int rob(vector<int>& nums)
{
int n = nums.size();
if (n == 0) return 0;
if (n == 1) return nums[0];
int prev1 = nums[n - 1];
int prev2 = max(nums[n - 2], nums[n - 1]);
for (int i = n - 3; i >= 0; --i)
{
int curr = max(nums[i] + prev1, prev2);
//后面的两个prev1和prev2决定curr,不需要dp数组的空间,用3个变量记录就行
prev1 = prev2;
prev2 = curr;
}
//因为最后把值赋给了prev2所以返回这个值
return prev2;
}
};
二、单词拆分(动态规划)
class Solution {
public:
bool wordBreak(string& s, vector<string>& wordDict)
{
// 创建一个dp数组,初始化为false,大小为s.size()+1,因为多了一个空字符串的位置
vector<bool> dp(s.size() + 1, false);
// 空字符串可以被拆分,因此dp[0]设为true
dp[0] = true;
// 遍历字符串s的每一个位置
for (int i = 0; i < s.size(); i++)
{
// 如果dp[i]为false,说明从0到i的子字符串不能被拆分成字典中的单词,继续下一个i
if (!dp[i])
continue;
// 遍历字典中的每一个单词
for (auto& word : wordDict)
{
// 检查当前单词是否可以匹配当前位置i开始的子字符串
// 条件1:单词长度加上i不能超过s的长度
// 条件2:s从位置i开始的子字符串与当前单词匹配
if (word.size() + i <= s.size() && s.substr(i, word.size()) == word)
{
// 如果匹配成功,设置dp[i+word.size()]为true
dp[i + word.size()] = true;
}
}
}
// 返回dp数组最后一个位置的值,表示整个字符串是否可以被拆分
return dp[s.size()];
}
};