题目链接
代码随想录文章讲解链接
用时:18m22s
采用后序遍历,因为要先知道两个子节点偷了多少钱,才能知道当前节点能偷多少钱。
对于以当前节点为根节点的二叉树,能偷的最高金额取决于两种情况:
能偷的最高金额为两者中较高者。由于情况1和情况2会重复计算子节点,所以可以用一个哈希表存储已经计算过的子节点的值。
class Solution {
private:
unordered_map<TreeNode*, int> hashMap;
public:
int rob(TreeNode* root) {
if (root == nullptr) return 0;
if (root->left == nullptr && root->right == nullptr) return root->val;
// 如果已经计算过当前节点,则直接从哈希表取值
if (hashMap.find(root) != hashMap.end()) return hashMap[root];
// 情况一:偷父节点
int val1 = root->val;
if (root->left) val1 += rob(root->left->left) + rob(root->left->right);
if (root->right) val1 += rob(root->right->left) + rob(root->right->right);
// 情况二:不偷父节点
int val2 = 0;
if (root->left) val2 += rob(root->left);
if (root->right) val2 += rob(root->right);
// 记录当前节点的值
hashMap[root] = max(val1, val2);
return hashMap[root];
}
};
用时:12m26s
dp数组:dp[0] 表示偷当前节点能获得的金额,dp[1] 表示不偷当前节点能获得的金额
状态转移:通过递归函数的返回值来传递状态,采用后序遍历,因为要先知道子节点的状态,才能更新当前节点的状态
class Solution {
private:
pair<int, int> dfs(TreeNode* node) {
if (node == nullptr) return pair<int, int>(0, 0);
pair<int, int> left = dfs(node->left);
pair<int, int> right = dfs(node->right);
// pair<偷当前节点的金额, 不偷当前节点的金额>
return pair<int, int>(node->val + left.second + right.second, max(left.first, left.second) + max(right.first, right.second));
}
public:
int rob(TreeNode* root) {
pair<int, int> p = dfs(root);
return max(p.first, p.second);
}
};
无。
无。
题目链接
代码随想录文章讲解链接
用时:7m33s
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() < 2) return 0;
int res = 0;
int low = prices[0];
for (int i = 1; i < prices.size(); ++i) {
if (prices[i] <= low) low = prices[i];
else res = max(prices[i] - low, res);
}
return res;
}
};
dp数组:dp[i][0]表示第i天持有股票的最大收支,dp[i][1]
表示第i天不持有股票的最大收支。
状态转移:
dp[i][0]
:第i天持有股票的最大收支可以分为两种情况:一是上一天持有股票,当天不卖掉;二是上一天不持有股票,当天买入。dp[i][0] = max(dp[i - 1][0], -prices[i])
dp[i][1]
:第i天不持有股票的最大收支也可以分为两种情况:一是上一天持有股票,当天卖掉;二是上一天不持有股票,当天也不买。dp[i][1] = max(dp[i - 1][0] + prices[i], dp[i - 1][1])
由于第i天的状态只跟前一天的有关,所以可以不用记录之前的状态,空间上可以优化,只用一个变量存储当前状态然后不断更新即可。
class Solution {
public:
int maxProfit(vector<int>& prices) {
pair<int, int> dp(-prices[0], 0); // (持有股票的收支,不持有股票的收支)
for (int i = 1; i < prices.size(); ++i) {
// 当天不持有股票:1.上一天持有股票,当天卖掉;2.上一天不持有股票,当天也不买
dp.second = max(dp.first + prices[i], dp.second);
// 当天持有股票:1.上一天持有股票,当天不卖掉;2.上一天不持有股票,当天买入
dp.first = max(dp.first, -prices[i]);
}
return dp.second;
}
};
感觉这个dp的解法本质上跟贪心是一致的。
无。
题目链接
代码随想录文章讲解链接
用时:2m13s
局部最优:只要当天的股价高于前一天,那么就在前一天买入,在当天卖出。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
for (int i = 1; i < prices.size(); ++i) {
if (prices[i] > prices[i - 1]) res += prices[i] - prices[i - 1];
}
return res;
}
};
用时:19m31s
跟上一题差不多,不同点在于,当天持有股票的情况,上一题由于只能买一次股票,所以若先前没有买股票,当天买的话,收支是为-prices[i]。而本题是可以多次买卖,所以当天买的话也得算上先前的收支,即dp1 - prices[i]。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int dp0 = -prices[0], dp1 = 0;
for (int i = 1; i < prices.size(); ++i) {
int newDp0 = max(dp0, dp1 - prices[i]); // 当天持有股票
dp1 = max(dp0 + prices[i], dp1); // 当天不持有股票
dp0 = newDp0;
}
return dp1;
}
};
这两题用贪心就很容易想,用dp感觉有点绕。
无。
题目链接
代码随想录文章讲解链接
用时:58m3s
dp数组:dp[i][0]表示第i天还未买过股票;dp[i][1]表示第i天第一次持有股票;dp[i][2]表示第i天已经卖出了1次股票;dp[i][3]表示第i天第二次持有股票;dp[i][4]表示第i天已经卖出了两次股票。
状态转移与121m题类似,只是多了几个状态。
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(5, 0)); // (未买过,第一次持有,第一次不持有,第二次持有,第二次不持有)
dp[0][1] = -prices[0], dp[0][3] = -prices[0];
for (int i = 1; i < prices.size(); ++i) {
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
return dp[prices.size() - 1][4];
}
};
用时:1m48s
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<int> dp(5, 0); // (未买过,第一次持有,第一次不持有,第二次持有,第二次不持有)
dp[1] = -prices[0], dp[3] = -prices[0];
for (int i = 1; i < prices.size(); ++i) {
dp[4] = max(dp[4], dp[3] + prices[i]);
dp[3] = max(dp[3], dp[2] - prices[i]);
dp[2] = max(dp[2], dp[1] + prices[i]);
dp[1] = max(dp[1], dp[0] - prices[i]);
}
return dp[4];
}
};
无。
无。
三天没刷题,搞比赛去了,手感掉了一些,还是得每天刷一刷,要是时间紧每天少刷点。