备忘录方法
动态规划算法的一个变形就是
备忘录方法
备忘录方法也用一个表格来保存已解决的子问题的答案.
在下次需要解决此问题时,只要简单地查看该子问题的解答,而不必重新计算.
但与动态规划不同:
-
备忘录方法的递归方式是自顶向下的,而动态规划算法则是自底向上递归的。
-
备忘录方法的控制结构与直接递归方法的控制结构相同
区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解
注意:
备忘录方法为每个子问题建立了一个记录项,初始化时,该记录项存入一个特殊的值,表示该子问题尚未求解
在求解过程中,对每个待求的子问题,首先查看相应的记录项。若记录项中存储的是初始化时存入的特殊值,则表示该子问题是第一次遇到,则此时计算出该子问题的解,并保存在相应的记录项中。若记录项中存储的已不是初始化时存入的特殊值,则表示该问题已被计算过,其相应的记录项中存储的是该子问题的解答。此时,只要从记录项中取出该子问题的解答即可。
LeetCode 135. Candy
Hard
/*
There are N children standing in a line. Each child is assigned a rating value.
N个小孩站在一条线上,每个小孩有一个rating value
You are giving candies to these children subjected to the following requirements:
按下面的规则给糖
Each child must have at least one candy.
每个小孩至少有一个糖!!!
Children with a higher rating get more candies than their neighbors.
有着高rate的小孩比它隔壁的小孩糖要多
What is the minimum candies you must give?
Input: [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.
*/
// 递归的方法,备忘录法?O(N)时间,O(N)空间
class Solution {
public:
int helper(vector<int>& ratings, vector<int>& res,int index) {
// 若没有求解,那么求解
if (res[index] == 0) {
res[index] = 1;//
if (index > 0 && ratings[index] > ratings[index - 1]) {
// 如果它比左边大
res[index] = max(res[index], helper(ratings, res, index - 1)+1);
}
// 如果它比右边大
res[index] = max(res[index], helper(ratings, res, index + 1)+1);
}
return res[index];
}
else {
return res[index];
}
}
int candy(vector<int>& ratings) {
int sz = ratings.size();
vector<int> res(sz); // 备忘录用于记录糖果数量,初始值为0,表示未求解
int sum = 0;
for (int i = 0; i < sz; i++) {
sum += helper(ratings, res, i);
}
return sum;
}
};