递归爬楼梯算法
Recursive stair climbing algorithm
我正在尝试将以下算法从递归更改为迭代,但在这样做时遇到了问题。 (书:"Cracking the Coding Interview.")
问题:"A child is running up a staircase with n steps, and can hop either 1, 2, or 3 steps at a time. Implement a method to count how many ways the child can run up the stairs."
书本答案(递归):
public static int countWays(int n, int[] map) {
if (n < 0)
return 0;
if (n == 0)
return 1;
if (map[n] > -1)
return map[n];
map[n] = countWays(n - 1, map) + countWays(n - 2, map) + countWays(n - 3, map);
return map[n];
}
我的回答(迭代):
public static int countWays(int n, int[] map) {
for (int i = 1; i <= n; i++) {
//Problem with writing it this way: index could be negative
map[i] = map[i - 1] + map[i - 2] + map[i - 3];
}
return map[n];
}
我给出的答案有一个问题是 "map[i - 1] + map[i - 2] + map[i - 3]" 行可能导致负索引,这会引发错误。
我的代码可能还有其他问题。
有人可以帮忙写这个吗?
将第一个索引硬编码为值为 1,然后将总和的每一项放入其自己的 if 语句中以检查负索引。如果索引为负数,则不将其计入总和。
或者,您可以只对前三个值进行硬编码,然后从 4 开始,不用担心。
因为这显然是一个编码面试问题...我将向您展示一个类似的复习解决方案,In Scala
,以帮助您学习基础知识。
import scala.annotation.tailrec
object Main {
/**
* Count ways to make change...
*/
def countChange(money: Int, coins: List[Int]): Int = {
def reduce(money: Int, coins: List[Int]): Int ={
if (money == 0) 1
else if (money < 0 || coins.isEmpty) 0
else reduce(money - coins.head, coins) + reduce(money, coins.tail)
}
reduce(money, coins)
}
}
public static int countWays(int n, int[] map) {
if(n == 0 || n==1)
return 1;
if(n == 2)
return 2;
map[0] = 1;
map[1] = 1;
map[2] = 2;
for (int i = 3; i <= n; i++) {
//Problem with writing it this way: index could be negative
map[i] = map[i - 1] + map[i - 2] + map[i - 3];
}
return map[n];
}
您使用的迭代方法称为自下而上的动态规划。它不同于带记忆的自顶向下递归。自下而上效率更高,因为您避免了与递归相关的堆栈开销。
Steps:
1 -> 1 = 1 way
2 -> 11, 2 = 2 ways
3 -> 111, 12, 21, 3 = 4 ways
4 -> 1111, 112, 121, 211, 22, 31, 31 = 7 ways
解决索引问题的另一种方法是创建一个最小大小为 3 的数组,并从第 3 个索引开始。您使用了更多 space 但它简化了您的代码。
public int countWaysDP(int n) {
if (n < 0) {
throw new IllegalArgumentException();
}
int[] dp = new int[Math.max(3, n)];
dp[0] = 1; // 1
dp[1] = 2; // 11, 2
dp[2] = 4; // 111, 12, 21, 3
for (int i = 3; i < n; i++) {
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
}
return dp[n - 1];
}
希望对你的训练有所帮助。
我正在尝试将以下算法从递归更改为迭代,但在这样做时遇到了问题。 (书:"Cracking the Coding Interview.")
问题:"A child is running up a staircase with n steps, and can hop either 1, 2, or 3 steps at a time. Implement a method to count how many ways the child can run up the stairs."
书本答案(递归):
public static int countWays(int n, int[] map) {
if (n < 0)
return 0;
if (n == 0)
return 1;
if (map[n] > -1)
return map[n];
map[n] = countWays(n - 1, map) + countWays(n - 2, map) + countWays(n - 3, map);
return map[n];
}
我的回答(迭代):
public static int countWays(int n, int[] map) {
for (int i = 1; i <= n; i++) {
//Problem with writing it this way: index could be negative
map[i] = map[i - 1] + map[i - 2] + map[i - 3];
}
return map[n];
}
我给出的答案有一个问题是 "map[i - 1] + map[i - 2] + map[i - 3]" 行可能导致负索引,这会引发错误。
我的代码可能还有其他问题。
有人可以帮忙写这个吗?
将第一个索引硬编码为值为 1,然后将总和的每一项放入其自己的 if 语句中以检查负索引。如果索引为负数,则不将其计入总和。
或者,您可以只对前三个值进行硬编码,然后从 4 开始,不用担心。
因为这显然是一个编码面试问题...我将向您展示一个类似的复习解决方案,In Scala
,以帮助您学习基础知识。
import scala.annotation.tailrec
object Main {
/**
* Count ways to make change...
*/
def countChange(money: Int, coins: List[Int]): Int = {
def reduce(money: Int, coins: List[Int]): Int ={
if (money == 0) 1
else if (money < 0 || coins.isEmpty) 0
else reduce(money - coins.head, coins) + reduce(money, coins.tail)
}
reduce(money, coins)
}
}
public static int countWays(int n, int[] map) {
if(n == 0 || n==1)
return 1;
if(n == 2)
return 2;
map[0] = 1;
map[1] = 1;
map[2] = 2;
for (int i = 3; i <= n; i++) {
//Problem with writing it this way: index could be negative
map[i] = map[i - 1] + map[i - 2] + map[i - 3];
}
return map[n];
}
您使用的迭代方法称为自下而上的动态规划。它不同于带记忆的自顶向下递归。自下而上效率更高,因为您避免了与递归相关的堆栈开销。
Steps:
1 -> 1 = 1 way
2 -> 11, 2 = 2 ways
3 -> 111, 12, 21, 3 = 4 ways
4 -> 1111, 112, 121, 211, 22, 31, 31 = 7 ways
解决索引问题的另一种方法是创建一个最小大小为 3 的数组,并从第 3 个索引开始。您使用了更多 space 但它简化了您的代码。
public int countWaysDP(int n) {
if (n < 0) {
throw new IllegalArgumentException();
}
int[] dp = new int[Math.max(3, n)];
dp[0] = 1; // 1
dp[1] = 2; // 11, 2
dp[2] = 4; // 111, 12, 21, 3
for (int i = 3; i < n; i++) {
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
}
return dp[n - 1];
}
希望对你的训练有所帮助。