• 算法面试题-美团校招题(拜访)


    题目很简单,注意方向只能选左右中的一个和上下中的一个,既然要走到目的地,那么方向已经决定了,就是尽量靠近目的地。

    分析:红色的圈表示起点,红色三角形表示终点。这里如果向上走或者向右走,那么永远到不了终点,所以路径只会在两个点构成的矩形中,并且方向只有两个。

    按照上图,假设向左走,走一步到绿色圈的位置,或者向下走一步到蓝色的圈的位置(这里暂时假设没有障碍),对于这两种走法,都会形成一个新的移动矩形(用不同颜色表示),子问题的解组成原问题的解,动态规划。

    设水平和垂直移动方向分别为v(左移为-1,右移为1,有障碍为0)和h,从起点坐标(x,y)到终点坐标(desX,desY)的方案数为f(x,y),则有下面状态转移方程:

    有了这个,代码就很容易了:

     1     public int countPath(int[][] map, int n, int m) {
     2         int x = 0, y = 0, desX = 0, desY = 0;
     3         int vertical;
     4         int horizontal;
     5         for (int i = 0; i < n; i++) { // 搜索起点和终点
     6             for (int j = 0; j < m; j++) {
     7                 if (map[i][j] == 1) {
     8                     x = i;
     9                     y = j;
    10                 }
    11                 if (map[i][j] == 2) {
    12                     desX = i;
    13                     desY = j;
    14                 }
    15             }
    16         }
    17         if (desX == x) { // 设定递归终止条件
    18             for (int i = Math.min(y, desY); i <= Math.max(y, desY); i++) {
    19                 if (map[x][i] == -1) { // 直线路径上是否有障碍
    20                     return 0;
    21                 }
    22             }
    23             return 1;
    24         }
    25         if (desY == y) {
    26             for (int i = Math.min(x, desX); i < Math.max(x, desX); i++) {
    27                 if (map[i][y] == -1) {
    28                     return 0;
    29                 }
    30             }
    31             return 1;
    32         }
    33         horizontal = desX - x > 0 ? 1 : -1; // 确定水平方向
    34         vertical = desY - y > 0 ? 1 : -1; // 确定垂直方向
    35         int[][] ver = new int[map.length][];
    36         for (int i = 0; i < ver.length; i++) {
    37             ver[i] = map[i].clone(); // 逐层拷贝,否则引用会和下面的数组相同
    38         }
    39         ver[x][y] = 0;
    40         ver[x + vertical][y] = 1;
    41         int[][] hor = new int[map.length][];
    42         for (int i = 0; i < hor.length; i++) {
    43             hor[i] = map[i].clone();
    44         }
    45         hor[x][y] = 0;
    46         hor[x][y + horizontal] = 1;
    47         if (map[x + vertical][y] == -1) { // 判断水平路径是否合法,即是否能水平移动
    48             return countPath(hor, n, m); // 如不能,则只垂直移动
    49         }
    50         if (map[x][y + horizontal] == -1) {
    51             return countPath(ver, n, m);
    52         }
    53         return countPath(ver, n, m) + countPath(hor, n, m); // 如果方向没限制,则结果为水平走和垂直的和
    54     }

    因为要把移动了之后的数组传入递归方法,所以需要对数组进行clone操作,这里不能直接对二维数组进行clone操作,需要通过for循环逐层拷贝,否则会因为引用相同而使得ver和hor数组的内容相同。

  • 相关阅读:
    比较两个日期的大小(年月日)
    js闭包
    星星点点
    刮刮卡刮奖效果
    html图片自适应屏幕大小(手机)
    将博客搬至CSDN
    类的讲义
    Anaconda教程
    css基础
    javascript
  • 原文地址:https://www.cnblogs.com/Fndroid/p/6180132.html
Copyright © 2020-2023  润新知