337.打家劫舍III
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
1.暴力递归法:虽然好想 但是超时了。根据代码随想录的思路,使用记忆化递归来做,用一个哈希表来存储树的节点和对应的值,因为树形dp存储的值是(当偷这个节点时可以获得的最大价值) 这样的话当在遇到这个节点之后就可以不用计算直接返回此值。
class Solution {
public:
int rob(TreeNode* root) {
if(root==nullptr){
return 0;
}
if(root->left==nullptr&&root->right==nullptr){
return root->val;
}
//偷父节点
int max1=root->val;
if(root->left)
max1+=rob(root->left->left)+rob(root->left->right);
if(root->right)
max1+=rob(root->right->left)+rob(root->right->right);
int max2=0;
//不偷父节点
max2+=rob(root->left)+rob(root->right);
return max(max1,max2);
}
};
2.记忆化递归法:注意 不要在函数内定义unordered_map 这样的话每次调用函数时都会创建一个map容器,对时间复杂度很不友好。
class Solution {
public:
unordered_map<TreeNode*,int> mp;
int rob(TreeNode* root) {
if(root==nullptr){
return 0;
}
if(root->left==nullptr&&root->right==nullptr){
return root->val;
}
if(mp[root])
return mp[root];
//偷父节点
int max1=root->val;
if(root->left)
max1+=rob(root->left->left)+rob(root->left->right);
if(root->right)
max1+=rob(root->right->left)+rob(root->right->right);
int max2=0;
//不偷父节点
max2+=rob(root->left)+rob(root->right);
mp[root]=max(max1,max2);
return max(max1,max2);
}
};
3.动态规划:树形dp 有难度 dp[i] 只有两个值 取还是不取: 0或是1 dp[1]代表偷当前节点的最大值,dp[0]代表不偷当前节点的最大值
class Solution {
public:
int rob(TreeNode* root) {
vector<int> result = robTree(root);
return max(result[0], result[1]);
}
// 长度为2的数组,0:不偷,1:偷
vector<int> robTree(TreeNode* cur) {
if (cur == NULL) return vector<int>{0, 0};
vector<int> left = robTree(cur->left);
vector<int> right = robTree(cur->right);
// 偷cur,那么就不能偷左右节点。// 0 不偷 1 偷
int val1 = cur->val + left[0] + right[0];
// 不偷cur,那么可以偷也可以不偷左右节点,则取较大的情况
int val2 = max(left[0], left[1]) + max(right[0], right[1]);
return { val2, val1 };
//0 1
}
};
121.买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
1.暴力法:思路比较清晰些 但是超时了 思考如何优化呢?
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res=0;
for(int i=0;i<prices.size();i++){
for(int j=i+1;j<prices.size();j++){
res=max(res,prices[j]-prices[i]);
}
}
return res;
}
};
想一想 是不是根本不需要双层for循环逐个遍历 只需要找到左侧最小值 然后让他逐个遍历找到最优解即可 代码如下: 这样提交就可以过了
class Solution {
public:
int maxProfit(vector<int>& prices) {
int low=INT_MAX;
int res=0;
for(int i=0;i<prices.size();i++){
low=min(low,prices[i]);
res=max(res,prices[i]-low);
}
return res;
}
};
3.动态规划:明日再谈哈
二.MySql
197.上升的温度:
编写解决方案,找出与之前(昨天的)日期相比温度更高的所有日期的 id 。
返回结果 无顺序要求 。
思路:题目倒是不难,主要在于学会使用datediff函数,他是用来计算存储日期的函数,当如下所示时代表a.recordDate,b.recordDate相差日期为1.
select a.id from Weather a join Weather b
on a.Temperature >b.Temperature
and datediff(a.recordDate,b.recordDate)=1;
1661.每台机器的进程平均运行时间
现在有一个工厂网站由几台机器运行,每台机器上运行着 相同数量的进程 。编写解决方案,计算每台机器各自完成一个进程任务的平均耗时。
完成一个进程任务的时间指进程的'end' 时间戳 减去 'start' 时间戳。平均耗时通过计算每台机器上所有进程任务的总耗费时间除以机器上的总进程数量获得。
结果表必须包含machine_id(机器ID) 和对应的 average time(平均耗时) 别名 processing_time,且四舍五入保留3位小数。
以 任意顺序 返回表。
思路:此题有些意思,就是上述表格中计算时间的题目 由于共有三台机器 ROUND(..., 3)函数: 这个函数用于将括号内的表达式结果进行四舍五入,保留到小数点后三位。 然后就是avg(a.timestamp - b.timestamp)部分: avg是求平均值的函数。然后在后续的约束条件中 让机器的id对应上 而且让a代表end, b代表start 并依据表中所示 将机器分组。
select a.machine_id,
ROUND(avg(a.timestamp-b.timestamp),3) as processing_time
from Activity a
join Activity b
on a.machine_id=b.machine_id AND
a.process_id = b.process_id AND
a.activity_type='end' AND
b.activity_type='start'
group by a.machine_id;