class Solution {
public:
int countNeighborhoods(const vector<int>& houses) {
int neighborhoods = 0;
int m = houses.size();
for (int i = 0; i < m; i++) {
if (houses[i] != 0 && (i == 0 || houses[i] != houses[i - 1])) {
neighborhoods++;
}
}
return neighborhoods;
}
int solve(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target, int idx, int tCost) {
if (idx >= m && target != 0)
return 1000000;
if (idx >= m && target == 0)
return tCost;
int ans = 1000000;
if (houses[idx] != 0) {
ans = min(ans, solve(houses, cost, m, n, target, idx + 1, tCost));
} else {
for (int i = 0; i < n; i++) {
bool left_same = (idx > 0 && houses[idx - 1] == i + 1);
bool right_same = (idx < m - 1 && houses[idx + 1] == i + 1);
houses[idx] = i + 1;
if (!left_same && !right_same) {
ans = min(ans, solve(houses, cost, m, n, target - 1, idx + 1, tCost + cost[idx][i]));
} else {
ans = min(ans, solve(houses, cost, m, n, target, idx + 1, tCost + cost[idx][i]));
}
houses[idx] = 0;
}
}
return ans;
}
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
int initialNeighborhoods = countNeighborhoods(houses);
int requiredNeighborhoods = target - initialNeighborhoods;
if (requiredNeighborhoods < 0) return -1;
int ans = solve(houses, cost, m, n, requiredNeighborhoods, 0, 0);
return (ans == 1000000) ? -1 : ans;
}
};
上面是我为以下 leetcode 问题创建的代码 -
https://leetcode.com/problems/paint-house-iii/
我的代码中的逻辑是简单地递归迭代数组,用所有可能的颜色绘制房屋,并使用代码中的 if 语句来告诉我需要如何更改社区的数量,然后递归调用该函数.
代码似乎确实给出了正确的答案,尽管我无法记住它,以下是一个解决方案,它通过利用不同的逻辑来检查社区数量来解决问题 -
class Solution {
public:
int solve(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target, int idx, int neighborhoods, int last_color) {
if (idx == m) {
return (neighborhoods == target) ? 0 : 1e6; // Cost 0 if exact neighborhoods; else, a large invalid cost.
}
if (neighborhoods > target) return 1e6; // Invalid if neighborhoods exceed target
int ans = 1e6;
if (houses[idx] != 0) {
int new_neighborhoods = neighborhoods + (houses[idx] != last_color);
ans = solve(houses, cost, m, n, target, idx + 1, new_neighborhoods, houses[idx]);
} else {
for (int color = 1; color <= n; color++) {
int new_neighborhoods = neighborhoods + (color != last_color);
int current_cost = cost[idx][color - 1] + solve(houses, cost, m, n, target, idx + 1, new_neighborhoods, color);
ans = min(ans, current_cost);
}
}
return ans;
}
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
int result = solve(houses, cost, m, n, target, 0, 0, 0);
return result == 1e6 ? -1 : result;
}
};
我的问题是,为什么我的代码不能被记忆,如果可以,那么如何,因为我似乎无法弄清楚相同的问题,这围绕着我在 DP 问题中经常遇到的一个问题我倾向于提出的逻辑与解决问题所需的逻辑非常相似,但在实现类似逻辑时略有不同,这会因某种原因导致错误的答案,我该如何解决这样的问题这是 DSA 和 CP 中的常见问题吗?是否有某种技巧可以使您的解决方案以可记忆的方式递归?
听起来你应该远离这个特定的问题,花时间学习动态规划。这种研究将会带来难以置信的回报。不幸的是,在基础层面上学习算法设计并没有快速的技巧。方法就是找一本好书,比如 Cormen 等人的《算法导论》(CLRS),然后仔细阅读这本书并解决问题。例如,CLRS 第 15 章介绍了动态规划。幸运的是,麻省理工学院 OCW 提供了两门优秀课程,入门课程 6.006 和更高级的 6.046,它们与本书非常相配。根据您的口味,您可能会喜欢 2005 年提供的 6.046,这是由作者之一 Leiserson 博士教授的。 如果您研究了这些材料,您就会了解到,一般来说,DP 问题的第一步是表征最优解的“结构”。然后,您使用
递归关系定义解的值。这是不用电脑,用铅笔和纸完成的。这两个步骤可能并不简单。然而,一旦完成,您就拥有了一个可证明正确的公式,并且为计算机编写算法通常非常简单。您的问题的递归关系是什么?