题目链接:力扣
你有一个凸的 n
边形,其每个顶点都有一个整数值。给定一个整数数组 values
,其中 values[i]
是第 i
个顶点的值(即 顺时针顺序 )。
假设将多边形 剖分 为 n - 2
个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 n - 2
个三角形的值之和。
返回 多边形进行三角剖分后可以得到的最低分 。
示例 1:
输入:values = [1,2,3] 输出:6 解释:多边形已经三角化,唯一三角形的分数为 6。
示例 2:
输入:values = [3,7,4,5] 输出:144 解释:有两种三角剖分,可能得分分别为:3*7*5 + 4*5*7 = 245,或 3*4*5 + 3*4*7 = 144。最低分数为 144。
示例 3:
输入:values = [1,3,1,4,1,5] 输出:13 解释:最低分数三角剖分的得分情况为 1*1*3 + 1*1*4 + 1*1*5 + 1*1*1 = 13。
提示:
n == values.length
3 <= n <= 50
1 <= values[i] <= 100
官方题解注释
class Solution {
public:
int minScoreTriangulation(vector<int>& values) {
// 记忆化存储已经计算过的子问题的解
unordered_map<int, int> memo;
int n = values.size();
// 定义 dp 函数
function<int(int, int)> dp = [&](int i, int j) -> int {
// 三角形的边长小于 3,不需要划分,返回 0
if (i + 2 > j) {
return 0;
}
// 三角形的边长等于 3,只有一个三角形,返回这个三角形的分数
if (i + 2 == j) {
return values[i] * values[i + 1] * values[j];
}
// 计算 memo 的 key
int key = i * n + j;
// 如果当前子问题的解没有计算过
if (!memo.count(key)) {
int minScore = INT_MAX;
// 枚举划分位置 k,计算每种划分方式的分数,取最小值
for (int k = i + 1; k < j; k++) {
minScore = min(minScore, values[i] * values[k] * values[j] + dp(i, k) + dp(k, j));
}
// 存储当前子问题的解
memo[key] = minScore;
}
// 返回当前子问题的解
return memo[key];
};
// 返回最终问题的解
return dp(0, n - 1);
}
};
ChatGPT题解注释版
class Solution {
public:
int minScoreTriangulation(vector<int>& values) {
int n = values.size();
// dp[i][j]表示从第i个点到第j个点所需的最小分数
vector<vector<int>> dp(n, vector<int>(n));
// 遍历区间长度
for (int len = 3; len <= n; len++) {
// 遍历区间起点
for (int i = 0; i + len - 1 < n; i++) {
// 区间终点
int j = i + len - 1;
// 初始化dp[i][j]
dp[i][j] = INT_MAX;
// 遍历区间中间点
for (int k = i + 1; k < j; k++) {
// 求解dp[i][j]
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + values[i] * values[j] * values[k]);
}
}
}
// dp[0][n-1]即为答案
return dp[0][n - 1];
}
};
unordered_map<int, int>
unordered_map<int, int> 是 C++ STL(标准模板库)中的一个关联容器,它可以将一组键值对映射到唯一的值。在这个特定的代码中, unordered_map<int, int> memo; 用来存储已经计算过的结果以便后续使用,避免了重复计算,从而提高了代码的效率。
vector<int>&
vector<int>& 表示一个引用,它用于将一个 vector<int> 类型的变量作为函数的参数,以便在函数中直接修改该变量,而不是创建一个新的副本。通过使用引用,可以避免在函数中复制大量数据,从而提高程序的效率。同时,引用还可以用于将函数的返回值传递给调用方。
function<int(int, int)> dp = [&](int i, int j) -> int
这句代码使用了lambda表达式,其结构如下:
[&](int i, int j) -> int {
// 函数体
return 0;
}
其中 &
表示使用lambda表达式所在作用域的变量,int i, int j
表示参数列表,-> int
表示返回值类型为 int
。这样就定义了一个返回值为 int
,带两个整型参数的lambda函数。
在本题中,这个lambda函数被用作动态规划函数,用于计算从第 i 个点到第 j 个点所需的最小得分。