题目一
力扣:2017
思路
1、这个题别看说的花花,总结一下,就是每个机器人只能向下走,或者向右走,因为只有两行,所以这个题就转化成了,我一直在第一行往右走,我去选择一下何时向下走,到第二行去向右走,这样一个问题。
2、一定要读好题,机器人1很坏,读好题,他的目的并不是得分最高,而是让机器人2得分最低。
3、机器人2的目的很纯粹,就是要最高分,一定要把两个机器人的策略搞清楚。所以在求第一个机器人策略的时候就不能之贪心最大分值,因为这不一定能保证机器人2得分最少
4、
代码:
注意
1、再求最大值的时候,初始值一般是要小于可能的目标答案,求最小值的时候,初始值一定是大于目标答案,所以一定注意对初始值的关注,一定要分析好该题答案的可能范围,初始值一定要设置好,否则会出错。
2、因为需要快速求区间和,所以用区间上的一维前缀和技术,在O(1)内求出答案
class Solution {
public:
long long tmp[2][50005] = {
};//存前缀和
vector<vector<int>> item;//临时表格
long long n = 0;
long long find_path() {
for (long long i = 1; i <= n; i++) {
tmp[0][i] = item[0][i - 1];
tmp[1][i] = item[1][i - 1];
}
for (long long i = 1; i <= n; i++) {
//求前缀和
tmp[0][i] += tmp[0][i - 1];
tmp[1][i] += tmp[1][i - 1];
}
long long ans = LONG_MAX;//这里一定要注意,答案是long long类型,远超过int最大值,所以这里用long 的最值来作为初始值,保证一定大于答案
for (long long i = 1; i <= n; i++) {
long long tmp1 = tmp[0][n] - tmp[0][i];//求两个段
long long tmp2 = tmp[1][i - 1] - tmp[1][0];
ans = min(ans, max(tmp1, tmp2));//满足两个机器人各自的需求
}
return ans;
}
long long gridGame(vector<vector<int>>& grid) {
item = grid;
n = grid[0].size();
return find_path();
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(N)
题目二(9月28号每日一题)
力扣:437
思路
(今天只介绍DFS的算法,树上前缀和算法明天在介绍).
其实这个题很明显,需要把任意一个非叶子节点当成根节点,把对应的子树搜一遍,所以很明显了,暴力解法就是递归嵌套递归就行,一个递归所检索所有节点,一个递归找对应子树有多少个合法路径。这里分为两个方向,由上向下和回溯。
自顶至底的DFS
我就是从根节点开始向下走,边走边记录已经加好的和,一旦碰到满足的节点了,在全局记录答案的地方++即可,走到空节点截止。
回溯的DFS
1、这个就是先走到最后再回过头来逐层向上进行统计,想好这种方法只需要想任意一个特殊节点就行,假设到了节点a,此时目标是找到和是targetSum,因为这里是统计路径和,走到了节点a,,所以加上了a,那么给他的子节点剩下的值为targetSum-a.val,这样,他就要问一问他的左右儿子,你们那两个分支中有多少个和为targetSum-a.val的串,获得个数之后,看看自己能不能匹配上targetSum,匹配上了,说明从上面到自己这里,恰好是一个答案,所以个数++。
2、说了这么多,其实就是针对某个子树,按照树上的节点先从上到下按照每个节点的val,瓜分targetSum,到了最底下,往回看,如果当前节点正好匹配上了分给他的targetSum,说明肯定匹配到了串,就这样回溯计算。
代码
自顶至底的DFS
class Solution {
public:
int ans = 0;
void finding(TreeNode* root, int sums, int target) {
//sums在记录每一条路径的和
if (root == nullptr) {
return;
}
int item = sums + root->val;
if (item == target) {
ans++;
}
finding(root->left, item, target);
finding(root->right, item, target);
}
void go(TreeNode* root, int target) {
if (root == nullptr) {
return;
}
finding(root, 0, target);
go(root->left, target);
go(root->right, target);
}
int pathSum(TreeNode* root, int targetSum) {
go(root, targetSum);
return ans;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度O(N^2)
空间复杂度O(N)
回溯
class Solution {
public:
int rootSum(TreeNode* root, int target) {
if (root == nullptr) {
return 0;
}
int ans = 0;
ans += rootSum(root->left, target - root->val);//后根遍历用于回溯
ans += rootSum(root->right, target - root->val);
if (root->val == target) {
ans++;
}
return ans;
}
int pathSum(TreeNode* root, int targetSum) {
if (root == nullptr) {
return 0;
}
ans += pathSum(root->left, targetSum);//后根遍历用于回溯
ans += pathSum(root->right, targetSum);
int ans = rootSum(root, targetSum);
return ans;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度O(N^2)
空间复杂度O(N)