很久之前接触过这样一道题目,总共有十层阶梯,从1层开始往上爬,每次可以上1层或者2层,问到10层总共有多少种方法?
思路:这个问题就是动态规划的一个经典例子,所谓动态规划,就是把复杂的问题进行拆解,拆解成一个个子问题,而这类问题最后非常适合使用递归来解决。诸如这道题目,可以记到某层阶梯的走法为F(n),那么到10层阶梯就是F(10)。 那么F(10)等于什么呢,这里进行假设,如果只差最后一次就可以走到10层,那么此时有几种情况呢?
- 在9层,往上走1步即可。
- 在8层,往上走2步即可。
那么此时可以得出F(10)=F(9)+F(8); — 最优子结构
其实这里就可以得出F(n)=F(n-1) + F(n-2) — 状态转移方程
而当n=2时,也就是走上2层,马上可以知道只有2种方法(0->2,0->1->2)
也就是F(2)=2,同理F(1)=1. — 边界情况
写成代码也很容易,这里就不写了。
然后这次还遇到了一个类似的题目,源自力扣
链接
其实大致的思路还是一样的,只是增加了对二维数组中,某一个数字的判断逻辑,刚刚开始我是这样做的
/**
* @param {number[][]} obstacleGrid
* @return {number}
*/
var uniquePathsWithObstacles = function(obstacleGrid) {
// 坐标轴向下为x轴,向右为y轴
// obstacleGrid的数组长度为n,表示矩阵高度
// 其中每个元素的长度都是m,表示矩阵宽度
var map = new Map();
var F = function (x,y){
// x,y 分别为网格的纵坐标.横坐标
/* 0=<x<=n-1 */
/* 0=<y<=m-1 */
if (x ===0 && y === 0) {
return obstacleGrid[x][y]==0 ? 1:0;
}
if (obstacleGrid[x][y] === 1){
return 0;
} else {
if (x === 0) {
return F(x,y-1);
} else if (y === 0) {
return F(x-1,y);
} else {
return F(x-1,y) + F(x,y-1);
}
}
}
return F(obstacleGrid.length - 1,obstacleGrid[0].length - 1);
};
但是某一个测试用例却显示超时了,所以这里得做一些额外的处理,我的思路是对某些计算的结果做一下缓存,每一次执行F(n)时先去Map里面取,如果取不到再进行递归运算,并缓存下来。改动后的代码如下
/**
* @param {number[][]} obstacleGrid
* @return {number}
*/
var uniquePathsWithObstacles = function(obstacleGrid) {
// 坐标轴向下为x轴,向右为y轴
// obstacleGrid的数组长度为n,表示矩阵高度
// 其中每个元素的长度都是m,表示矩阵宽度
var map = new Map();
var cacheCalc = function (x,y) {
if (map.has([x,y].join(','))) return map.get([x,y].join(','));
else {
var cacheValue = F(x,y);
map.set([x,y].join(','),cacheValue);
return cacheValue;
}
}
var F = function (x,y){
// x,y 分别为网格的纵坐标.横坐标
/* 0=<x<=n-1 */
/* 0=<y<=m-1 */
if (x ===0 && y === 0) {
return obstacleGrid[x][y]==0 ? 1:0;
}
if (obstacleGrid[x][y] === 1){
return 0;
} else {
if (x === 0) {
return cacheCalc(x,y-1);
} else if (y === 0) {
return cacheCalc(x-1,y);
} else {
return cacheCalc(x-1,y) + cacheCalc(x,y-1);
}
}
}
return F(obstacleGrid.length - 1,obstacleGrid[0].length - 1);
};
来源:CSDN
作者:大笨儿钟
链接:https://blog.csdn.net/u014298440/article/details/103678695