我试图理解书中提供的解决方案以下问题:
“一个孩子正在爬楼梯,有n个台阶,可以一步一跳,两步或三步。实施一种方法来计算孩子爬楼梯的方式。”
本书的解决方案如下,源于这样的事实:“最后一步可能是从n - 1的单步跳跃,从步骤n - 2的双步跳跃或从步骤n - 3的三步跳跃”
public static int countWaysDP(int n, int[] map) {
if (n < 0)
return 0;
else if (n == 0)
return 1;
else if (map[n] > -1)
return map[n];
else {
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map);
return map[n]; }
}
我的困惑是:
如果步数为零,为什么程序会返回1?我想到它的方式,如果步数为零,则有零路穿过楼梯。难道更好的解决方案不是像“if(n&lt; = 0)返回0;否则if(n == 1)返回1”?
我不确定我理解这个静态方法背后的理由吗?谷歌说静态方法是由整个类调用的方法,而不是类的对象。所以这本书的意图似乎是这样的:
class Staircase {
static int n;
public:
static int countWaysDP(int n, int[] map); }
而不是:
class Staircase {
int n;
public:
int countWaysDP(int n, int[] map); }
为什么呢?这个类有多个楼梯实例化的问题是什么?
感谢。
(注:书籍正在破解编码面试)
答案 0 :(得分:2)
回答你的第一个问题,它变成了数学之美:如果楼梯有一步,有一种方法可以解决它。如果有0个步骤,还有一种方法可以解决它,这是无所作为的。
对于n步楼梯来说,m次,你可以步行1,2或3步完成它。因此,如果n为1,则m为1,并且有1路。如果n为0,则m为0,并且还有1种方式 - 完全不采取任何步骤的方式。
如果你写出两步楼梯的所有方法,它是[[1, 1], [2]]
,对于一步楼梯,它是[[1]]
,对于0阶梯,它是{{ 1}},而不是[[]]
。数组[]
内的元素数是1,而不是0。
如果问题是你可以走1步或2步,这将成为斐波那契系列。注意fib(0)= 1和fib(1)= 1,它对应于同一个东西:当阶梯是1步时,有1种方法来解决它。当有0个步骤时,有1种方法可以解决它,而且它什么都不做。事实证明走两步楼梯的方法是fib(2)是2并且它等于fib(1)+ fib(0)= 1 + 1 = 2,如果它不起作用,它将不起作用fib(0)等于0.
答案 1 :(得分:1)
答案2: 静态方法意味着该函数不需要来自对象的任何信息。
该函数只接受一个输入(在参数中),处理它并返回一些东西。 当你没有看到任何&#34;这个&#34;在函数中,您可以将其设置为静态。
非静态方法通常会读取某些属性(此变量)和/或在某些属性中存储值。
答案1: 我将其转换为javascript,只是为了显示会发生什么。
http://jsbin.com/linake/1/edit?html,js,output
我想这就是重点。递归通常与您期望的相反。它通常以相反的顺序返回值。
5个楼梯:
首先它返回n = 1;那么n = 2,......直到n = 5;
n = 5必须等到n = 4准备好,n = 4必须等到n = 3准备就绪,......
所以这是你的n = 0和n <0: 函数的第一次返回有n = 1;这称之为
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map)
这就是
map[n] = countWaysDP(0, map) + countWaysDP(-1, map) + countWaysDP(-2, map)
有countWaysDP(0,map)返回1;其他术语没有意义,所以它们返回0.这就是为什么n == 0和n <0
这些子句的原因注意,你可以添加
+ countWaysDP(n - 4, map)
如果你想看看当孩子也能跳4个案件时会发生什么
另请注意: 正如我在回答2中所说,你看到这个功能并不需要任何对象。它只处理数据并返回一些东西。 所以,在你的情况下,在你的类中使用这个函数是有用的,因为你的函数被分组(它们不只是散布在脚本周围的松散函数),而是使它静态意味着编译器没有必要随身携带对象的内存(尤其是对象的属性)。
我希望这是有道理的。肯定有人可以提供更准确的答案;我对我的元素有点回答(我主要是做javascript)。
答案 2 :(得分:0)
为了尝试回答你的第一个问题,为什么它返回1而不是0,假设你正在看一个总共2步的楼梯,那么递归调用就会变成:
countWaysDP(2 - 1, map) + countWaysDP(2 - 2, map) + countWaysDP(2 - 3, map);
第二个递归调用是 n 变为零的那个,当我们找到一个成功的路径时,因为从2个步骤开始,显然有一个采取两个步骤的路径。现在,如果你按照你的建议写作:
n == 1: return 1
你不会接受从两个阶梯走两步!该陈述的含义是,只有在一步结束时才计算路径!
答案 3 :(得分:0)
你需要考虑它有一个树,每个节点有3个可能的选项。 如果楼梯的大小是4 我们会有这样的事情:
(4)--1-->(3)--..(Choose a step and keep branching)...
|__2-->(2)--..(Until you get size of zero)............
|__3-->(1)--1-->(0) # <--Like this <--
最后,如果你计算所有大小为零的叶子,你将获得所有可能的方法。
所以你可以这样想,如果你采取措施,然后考虑像这个尺寸步骤更新楼梯的大小,你的步骤可以是(1,2,3)
这样做可以编写如下代码:
choices = (1, 2, 3)
counter = 0
def test(size):
global counter
if size == 0:
counter += 1
for choice in choices:
if size - choice >= 0:
test(size - choice)
return counter