第一个参数int N,有N个位置1,2,3,4~N,N>1
    第二个参数int S,开始位置,有个机器人停在哪个位置上,是1~N中间的。
    第三个参数int E,是目标位置,从S出发到E
    第四个参数int K,机器人必须走K步,要想从S到达E,有多少种方法?可以随意向左向右走

    1. public static int ways1(int N, int start, int aim, int K) {
    2. if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    3. return -1;
    4. }
    5. return process1(N,aim,start,K );
    6. }
    7. // 有哪些位置?1~N 固定参数
    8. // 最终的目标是aim, 固定参数
    9. // 机器人当前来到的位置是cur,可变参数
    10. // 机器人还有rest步需要去走, 可变参数
    11. // 返回:机器人从cur出发,走过rest步之后,最终停在aim的方法数,是多少?
    12. // 当可变参数确定,返回值确定
    13. // 暴力递归版本 O(2^k)
    14. public static int process1(int N, int aim, int cur, int rest ) {
    15. if (rest == 0) { // 如果已经不需要走了,走完了! basecase
    16. return cur == aim ? 1 : 0; // 剩0步到达aim就是一种方法
    17. }
    18. // 还有路可以走
    19. // rest>0 ,来到1,必须1→2,还剩rest-1。
    20. if (cur == 1) { // 1 -> 2
    21. return process1(N ,aim, 2, rest - 1 );
    22. }
    23. // 来到N,没有选择只能N-1后退, 还剩rest-1
    24. if (cur == N) { // N-1 <- N
    25. return process1(N ,aim, N - 1, rest - 1 );
    26. }
    27. // 机器人来到中间位置,有两种选择,往左迈一步,往右迈一步。
    28. return process1(N ,aim,cur - 1, rest - 1) + process1( N ,aim, cur + 1, rest - 1);
    29. }
    30. // 记忆化搜索,搞定可变参数组合 O(KxN)
    31. public static int ways2(int N, int start, int aim, int K) {
    32. if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    33. return -1;
    34. }
    35. // 开多大分析可变参数范围,0~K,K+1, 1~N,N+1,0位置是无法到达的
    36. int[][] dp = new int[N + 1][K + 1];
    37. // 初始化都置成-1,不是-1就代表计算过,直接返回。
    38. for (int i = 0; i <= N; i++) {
    39. for (int j = 0; j <= K; j++) {
    40. dp[i][j] = -1;
    41. }
    42. }
    43. // dp就是缓存表
    44. // dp[cur][rest] == -1 -> process1(cur, rest)之前没算过!
    45. // dp[cur][rest] != -1 -> process1(cur, rest)之前算过!返回值,dp[cur][rest]
    46. // N+1 * K+1
    47. return process2(start, K, aim, N, dp);
    48. }
    49. // cur 范: 1 ~ N
    50. // rest 范:0 ~ K
    51. public static int process2(int cur, int rest, int aim, int N, int[][] dp) {
    52. if (dp[cur][rest] != -1) { // 状态计算过返回
    53. return dp[cur][rest];
    54. }
    55. // 之前没算过!缓存没命中 尝试
    56. if (rest == 0) {
    57. dp[rest][cur] = cur == aim ? 1 : 0; // 记忆
    58. return dp[cur][rest];
    59. }
    60. // rest >0 有路可走
    61. if (cur == 1) {
    62. dp[rest][cur] = process2(2, rest - 1, aim, N, dp);// 记忆
    63. } else if (cur == N) {
    64. dp[rest][cur] = process2(N - 1, rest - 1, aim, N, dp);// 记忆
    65. } else {
    66. dp[rest][cur] = process2(cur - 1, rest - 1, aim, N, dp) + process2(cur + 1, rest - 1, aim, N, dp);// 记忆
    67. }
    68. return dp[cur][rest];
    69. }
    70. // DP 改递归代码从格子取值
    71. public static int ways3(int N, int start, int aim, int K) {
    72. if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
    73. return -1;
    74. }
    75. int[][] dp = new int[N + 1][K + 1];
    76. dp[aim][0] = 1;
    77. for (int rest = 1; rest <= K; rest++) {
    78. dp[1][rest] = dp[2][rest - 1];
    79. for (int cur = 2; cur < N; cur++) {
    80. dp[cur][rest] = dp[cur - 1][rest - 1] + dp[cur + 1][rest - 1];
    81. }
    82. dp[N][rest] = dp[N - 1][rest - 1];
    83. }
    84. return dp[start][K];
    85. }