【问题标题】:Find maximum visit-able nodes in matrix在矩阵中找到最大可访问节点
【发布时间】:2017-05-15 09:20:00
【问题描述】:

我在编码测试中遇到过这个问题,找不到有效的方法。

给定一个矩阵A,移动规则如下:

  1. 只能从任何元素向右或向下移动
  2. 只能在我们最初开始的同一行或同一列元素内移动。
  3. 只有当一个元素的值小于你开始的元素的值时,你才能访问或跨越一个元素。

查找可以访问的元素总数,如果一个从元素 A(i,j) 开始,其中 i-> 行并且
j-> 列。

注意:您必须为每个矩阵元素打印此输出。

输入矩阵:
1 2 3
2 3 1
3 1 2

输出:
1 1 3
1 3 1
3 1 1

说明:从 1 (i=0,j=0) 行开始,我们无法进一步遍历,因此可访问节点 = 1
此外,在列方面它是相同的。因此,对于 (i=0,j=0),最大节点总数为 1。

我的方法:

尝试了一个正常的解决方案,我们从每个元素遍历右侧和向下元素并找到两个可访问元素计数的最大值。 但这不是有效的。 有人可以告诉一个有效的方法来做到这一点。 提前致谢。

【问题讨论】:

  • 这种方法有重复。例如,当您计算 [0][2] 元素(即 3)时,您已经计算了 [1][2](即 1)。试试看是否可以重复使用信息。
  • @StutiRastogi:这里不是这样,正如你看到的第三条规则。对于 [1][2] 可访问元素计数仅为 1(本身),因为下一个向下 [2][2] 元素 =2 大于此值。但是对于 [0][2] 可访问计数为 3,因为 [1][2] , [2][2] 都更小并且包含自身。否则我可以使用 DP。
  • “在我们最初开始的元素的行和列内移动”——这是什么意思?
  • @n.m.这意味着向右或向下移动时没有锯齿形图案。因此,对于任何节点,两条路径被认为是向下(同一列增加行)和向右(同一行增加列)。
  • 我认为这将是“在同一行 列内移动”。

标签: algorithm matrix data-structures


【解决方案1】:

关键是我们永远不能越过大于当前元素的元素,并且大元素下方或右侧的较小元素的值是无关紧要的(因为当我们越过大元素时,我们' d 还能够根据问题陈述跳过所有较小的元素)。

  • 对于每一列,从底部到顶部,保留一个堆栈,该堆栈将按降序存储元素及其索引(实际上我们可以只存储索引,并使用它来查找元素在矩阵中)。

  • 对于我们访问的每个元素:

    • 从堆栈中弹出元素,直到堆栈中最大的元素大于或等于当前元素(或为空)。

    • 可以向下访问的单元格数是到堆栈最顶部元素的距离(或者如果堆栈为空,则到最后的所有单元格)。

    • 将该元素压入堆栈。

  • 从右到左重复上述过程,将上面得到的值相加。

  • 将所有内容加 1 以包括访问自身的单元格。

由于我们只为每个单元做固定数量的工作,这里的复杂度是O(rows*columns)

Java 代码:

int[][] array = {{1, 2, 3},
                 {2, 3, 1},
                 {3, 1, 2}};
Stack<Integer> stack = new Stack<Integer>(); // stores the index only
int[][] output = new int[array.length][array[0].length];
for (int i = array.length-1; i >= 0; i--) // direction not important
{
    stack.clear();
    for (int j = array[0].length-1; j >= 0; j--)
    {
        while (!stack.empty() && array[i][stack.peek()] < array[i][j])
            stack.pop();
        int offset;
        if (stack.empty())
            offset = array[0].length;
        else
            offset = stack.peek();
        output[i][j] = offset - j - 1;
        stack.push(j);
    }
}

// same as above, just with indices swapped
for (int i = array[0].length-1; i >= 0; i--) // direction not important
{
    stack.clear();
    for (int j = array.length-1; j >= 0; j--)
    {
        while (!stack.empty() && array[stack.peek()][i] < array[j][i])
            stack.pop();
        int offset;
        if (stack.empty())
            offset = array.length;
        else
            offset = stack.peek();
        output[j][i] += offset - j - 1;
        stack.push(j);
    }
}

for (int i = 0; i < array.length; i++)
for (int j = 0; j < array[0].length; j++)
    output[i][j] += 1;

for (int[] a: output)
    System.out.println(Arrays.toString(a));

Live demo.

【讨论】:

  • 无法验证 1 2 2, 2 2 1, 2 1 2 输出应为 1 1 2, 1 2 1, 2 1 1
  • @GP007 已修复。那应该是1 1 2, 1 3 1, 2 1 1,不是吗? (由于中间元素可以访问自己,1下1右)
  • 它将是 2,因为我们必须在两个方向上找到两个可能值的最大值。我们只能朝一个方向前进。所以无论是右还是下都为自己加 1 和 1。
  • @GP007 问题示例中的中间元素不应该也是2吗?
  • 你是对的。我的错误是 1 1 2, 1 3 1, 2 1 1
【解决方案2】:

我认为优化代码的一种方法是利用缓存,这里是算法的一个小实现。

    int visited[3][3];
    memset(visited, -1, sizeof(visited));

    int calculateMaxVisitedNode(int x, int y, int visit_count, int r, int c, int valx, int valy)
    {
        if(x>r || y>c)
        {
            return visit_count;
        }
        if(visited[x][y] != -1)
        {
            return visited[x][y];
        }

        int right = 0;
        int down = 0;

        if(A[valx][valy] > A[x][y+1])
        {
            right = f(x,y+1,visit_count+1,r,c,valx,valy);
        }

        if(A[valx][valy] > A[x+1][y])
        {
            down = f(x+1,y,visit_count+1,r,c,valx,valy);
        }

        visited[x][y] = max(right, down);
        return visited[x][y];
    }

所以我在这里缓存已经访问过的单元格,所以不需要再次遍历它们。当行数和列数非常多时,这可以显着降低您的时间复杂度。

【讨论】:

  • 我觉得不对,你犯了和第一条评论一样的错误
  • 我明白你的意思,你是说如果将 (0,2) 传递给我的方法,它将返回 2 而不是正确的 3,所以这就是这个算法的优点......通过在 visit_count = 1 而不是 0 中,看看魔法
  • 或者如果您知道当前单元格没有被考虑在内,那么在此方法返回的结果中添加 +1
  • 但是您没有考虑到下一个值必须与第一个值而不是当前值进行比较
  • 仍然不好,因为您正在缓存的值是针对特定 valx 和 valy 的,结果取决于它们
猜你喜欢
  • 2015-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 2019-04-14
相关资源
最近更新 更多