目录
1.不同路径
题解
2140. 解决智力问题
题解
2873. 有序三元组中的最大值
题解
1.不同路径
链接:62. 不同路径
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
题解
这个机器人位于左上角位置,每次只能向右和向下移动
- 问从开始位置到终点一共有多少种不同的路径。
- 我们下标从1开始计数,这样就少了很多边界情况。
接下来我们用记忆化搜索解决这个问题。
如果纯记忆化搜索我们只要两步就可以了。
- 第一步 先想出暴搜(递归)的代码。
- 第二步 暴搜代码改成记忆化搜索,但是前提是能否改!
1.暴搜(递归)
我们最后向求出的m,n位置有多少种不同的走法
- 那么就这样搞dfs,dfs我给你两个参数,dfs(i,j)
- 你直接给我返回1,1到达i,j有多少种走法。
具体dfs你内部怎么走我不关心,我相信你一定能够完成任务。
- 接下来想想这个函数体 如何设计,我想从1,1到达这个三角的位置一共有多少种方式,其实只用关心两个位置就可以。
- 因为想到达三角的位置,必须要从这两个圆圈到达,要求只能向右走向下走。
- 如果此时我知道到达圆圈有多少种方式那在多走一步就走到三角了。
- 也就是说到达圆圈有多少种方式,到达这个三角也有多少种方式。
因此仅需要达到两个圆圈有多少种方式加起来就是到达三角位置的方式 dfs(i-1,j) + dfs(i,j-1)。
递归出口 我们考虑某个位置的时候,我们仅会考虑它上面的位置以及左边的位置。
- 有可能i=1的时候去考虑i-1不就越界了吗
- i=0的时候不能从非法位置达到这里。
- 同理j=0也是一种非法情况,我们既要考虑上边也要考虑左边。因此
i == 0 || j == 0 return 0;
但还有一种隐藏递归出口
- 当i == 1 && j == 1的时候是位于起点的
- 上面和左边都没有所以需要特殊处理 i == 1 && j == 1 return 1
class Solution {
public:int uniquePaths(int m, int n) {//爆搜return dfs(m,n);}int dfs(int m,int n){//出口if(m==0 || n==0) return 0;if(m==1 && n==1) return 1;return dfs(m-1,n)+dfs(m,n-1);}
};
上面会超时,下面看看能否暴搜的代码改成记忆化搜索。
在递归过程种发现大量重复的相同问题就可以用记忆化搜索。
记忆化搜索
我们发现在递归过程种发现大量重复的相同问题因此可以用记忆化搜索
搞一个备忘录
- 递归之前,查找一下备忘录
- 返回之前,把结果存在备忘录中
搞一个备忘录 上一道题是搞一个一维数组,但是这道题dfs函数里面是有两个可变参数,i和j一直在变化。
- 里面的值是int,因此我可以搞一个int [m+1][n+1] 二维数组。
- 因为要访问到m,n的位置。
进前 瞅瞅。return 前 存存
class Solution {
public:vector<vector<int>> memo;int uniquePaths(int m, int n) {//记忆化搜索memo.resize(m+1,vector<int>(n+1,0));return dfs(m,n);}int dfs(int m,int n){if(memo[m][n]) return memo[m][n];//出口if(m==0 || n==0) return 0;if(m==1 && n==1) return 1;memo[m][n]=dfs(m-1,n)+dfs(m,n-1);return dfs(m-1,n)+dfs(m,n-1);}
};
解下来把记忆化搜索改成动态规划。
- 多加一层的 初始化
- 循环内 要注意起点的值 continue ,防止被修改
2140. 解决智力问题
链接:2140. 解决智力问题
给你一个下标从 0 开始的二维整数数组 questions
,其中 questions[i] = [pointsi, brainpoweri]
。
这个数组表示一场考试里的一系列题目,你需要 按顺序 (也就是从问题 0
开始依次解决),针对每个问题选择 解决 或者 跳过 操作。解决问题 i
将让你 获得 pointsi
的分数,但是你将 无法 解决接下来的 brainpoweri
个问题(即只能跳过接下来的 brainpoweri
个问题)。如果你跳过问题 i
,你可以对下一个问题决定使用哪种操作。
- 比方说,给你
questions = [[3, 2], [4, 3], [4, 4], [2, 5]]
:
-
- 如果问题
0
被解决了, 那么你可以获得3
分,但你不能解决问题1
和2
。 - 如果你跳过问题
0
,且解决问题1
,你将获得4
分但是不能解决问题2
和3
。
- 如果问题
请你返回这场考试里你能获得的 最高 分数。
题解
刚好今天的每日一题
- 暴力 选 or 不选 会超时
class Solution {
public:typedef long long ll;queue<vector<int>> q;ll ret;long long mostPoints(vector<vector<int>>& questions) {//dpdfs(questions,0,0);return ret;}void dfs(vector<vector<int>>& questions,int p,ll count){if(p>=questions.size()) //向下 再向上 //暴力 是会经历两次的{ret=max(ret,count);return;}
//选dfs(questions,p+questions[p][1]+1,count+questions[p][0]);
//不选dfs(questions,p+1,count); }
};
采用 记忆化搜索,记录 结果的记忆化递归,避免 重复进行
class Solution
{int n = 0;unordered_map<int, long long> memo;
public:long long dfs(vector<vector<int>>& questions, int pos){if (pos >= n)return 0;if (memo.count(pos))return memo[pos];// 选 - 跳到 pos + brain + 1long long ret = questions[pos][0] + dfs(questions, pos + questions[pos][1] + 1);// 不选 - 跳到 pos + 1ret = max(ret, dfs(questions, pos + 1));memo[pos] = ret; //记录 结果的记忆化递归return ret;}long long mostPoints(vector<vector<int>>& questions){n = questions.size();return dfs(questions, 0);}
};
采用动态规划,优化
2873. 有序三元组中的最大值
链接:2873. 有序三元组中的最大值 I
给你一个下标从 0 开始的整数数组 nums
。
请你从所有满足 i < j < k
的下标三元组 (i, j, k)
中,找出并返回下标三元组的最大值。如果所有满足条件的三元组的值都是负数,则返回 0
。
下标三元组 (i, j, k)
的值等于 (nums[i] - nums[j]) * nums[k]
。
题解
暴力
class Solution {
public:typedef long long ll;long long maximumTripletValue(vector<int>& nums) {//暴力ll ret=0;int n=nums.size();for(int i=0;i<n-2;i++){for(int j=i+1;j<n-1;j++){for(int k=j+1;k<n;k++){ret = max(ret,(ll)(nums[i] - nums[j]) * nums[k]);//!!!强转}}}return ret;}
};
注意 max 比较对 ll 的强转~
解法二:
类比:11.盛水最多的容器
利用单调性来进行空间换时间
class Solution {
public:typedef long long ll;long long maximumTripletValue(vector<int>& nums) {//利用单调性int n=nums.size();if (n < 3) return 0; // 🌟 新增边界条件ll ret=0;vector<int> max_left(n,0); //ivector<int> max_right(n,0); //k//空间换时间for(int j=1;j<n;j++){max_left[j]=max(max_left[j-1],nums[j-1]);
//!!!!!存储当前位置所对应的最大左右值}for(int j=n-2;j>=0;j--){max_right[j]=max(max_right[j+1],nums[j+1]);}for(int j=1;j<n-1;j++){ret=max(ret,(ll)(max_left[j]-nums[j])*max_right[j]);}return ret;}
};
//!!!!!存储当前位置所对应的最大左右值