一、题目解析
我们先来看一下题,题目告诉我们给了我们一个二数组frame,其中frame[i][j]为该位置的珠宝价值,我们只能从左上角也就是[0][0]位置开始拿珠宝,每次只能往右或者往下走一步,然题目问我们到达右下角的时候可以拿到的最高价值。相信大家都知道这道题让我们做什么了,好,接下来我们看一下怎么解决这道问题。
二、算法原理
1、状态表示
根据我们做前面几道题的经验加上题目要求,我们可以直接定义一个状态表示。
dp[i[[j]表示:到达[i][j]位置,取得的珠宝最高价值。
2、状态转移方程
根据题目的要求,我们有两种方式到达[i][j]位置,第一种是从[i-1][j]的位置到达[i][j]位置,另一种是从[i][j-1]的位置到达[i][j]位置,我们先来看第一种。
我们从[i-1][j]位置到[i][j],我们只要知道到达[i-1][j]的珠宝最高价值,在加上[i][j]位置的珠宝价值是不是就是[i][j]位置的价值呢?[i-1][j]的珠宝最高价值在哪里呢?不就在我们的状态表示里面吗?也就是dp[i-1][j]里面。
同理,我们从[i][j-1]位置到[i][j],也需要到达知道[i][j-1]的珠宝最高价值,它就在dp[i][j-1]里面,在加上[i][j]位置的价值即可。
题目要求的是最大的价值,因此我们仅需要取一个最大值即可。
因此状态转移方程:dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + frame[i][j]
3、初始化
初始化的时候看状态转移方程,当我们填dp[0][0]位置的是会用到dp[-1][[0]和dp[0][-1]的值,但是这两个位置越界了呀,因此我们创建dp表的时候可以多开一行多开一列,然后从dp[1][1]的位置填表,那么这个我们会用到dp[0][1]和dp[1][0]这两个位置的值,那么我们初始化成什么呢?dp[1][1]表示到达[1][1]时候的最大价值,最大价值是什么?不就是frame[0][0]吗?因此将这两个位置初始化为0即可。那么第一行和第一列的其它位置初始化为什么呢?其实也初始化为0即可。这个地方要注意frame数组下标的映射关系。因为我们多开了一行一列,因此它的下标需要-1的。
4、填表
从上往下,从左往右填表即可。
5、返回结果
因为多开了一行多开了一列,因此直接返回dp[m][n]即可。
三、编写代码
希望大家可以根据算法原理自己尝试编写一下代码。
LCR 166. 珠宝的最高价值 - 力扣(LeetCode)
class Solution
{
public:
int jewelleryValue(vector<vector<int>>& frame)
{
int m = frame.size(), n = frame[0].size();
//1、创建dp表
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
//2、填表
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + frame[i - 1][j - 1];
//3、返回值
return dp[m][n];
}
};