Algorithm 在矩阵中查找最大可访问节点

Algorithm 在矩阵中查找最大可访问节点,algorithm,matrix,data-structures,Algorithm,Matrix,Data Structures,我在一次编码测试中遇到了这个问题,没有找到有效的方法 给定矩阵a,移动规则如下: 只能从任何元素向右或向下移动 只能在我们最初开始的元素的同一行或同一列中移动 只有当元素的值小于起始元素的值时,才能访问或跨越该元素 如果从元素A(i,j)开始,其中i->row和 j->column 注意:必须为每个矩阵元素打印此输出 输入矩阵: 1 2 3 2 3 1 3 1 2 输出: 13 1 3 1 3.1.1 解释:从1(i=0,j=0)行方向,我们无法进一步遍历,因此可访问节点=1 而且,在列方面也是

我在一次编码测试中遇到了这个问题,没有找到有效的方法

给定矩阵a,移动规则如下:

  • 只能从任何元素向右或向下移动
  • 只能在我们最初开始的元素的同一行或同一列中移动
  • 只有当元素的值小于起始元素的值时,才能访问或跨越该元素 如果从元素A(i,j)开始,其中i->row和
    j->column

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

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

    输出:
    13
    1 3 1
    3.1.1

    解释:从1(i=0,j=0)行方向,我们无法进一步遍历,因此可访问节点=1
    而且,在列方面也是一样的。因此,对于(i=0,j=0),最大总节点数为1

    我的做法:

    尝试了一个普通的解决方案,其中我们从每个元素遍历右侧和向下的元素,并找到两个可访问元素计数的最大值。 但这是没有效率的。 有人能告诉我一个有效的方法吗。
    提前感谢。

    我认为优化代码的一种方法是使用缓存,下面是该算法的一个小实现

        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];
        }
    

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

    关键点是,我们永远不能超过大于当前元素的元素,而大元素下方或右侧较小元素的值是无关的(因为当我们越过大元素时,我们也能够根据问题陈述越过所有小元素)

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

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

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

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

      • 将该元素推到堆栈上

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

    • 在所有内容中添加1,以包括访问自己的单元格

    因为我们每个单元只做固定数量的工作,所以这里的复杂性是
    O(行*列)

    这方面的Java代码:

    int[][]数组={{{1,2,3},
    {2, 3, 1},
    {3, 1, 2}};
    Stack Stack=new Stack();//只存储索引
    int[][]输出=新的int[array.length][array[0.length];
    对于(int i=array.length-1;i>=0;i--)//方向不重要
    {
    stack.clear();
    对于(int j=array[0]。长度-1;j>=0;j--)
    {
    而(!stack.empty()&&array[i][stack.peek()]=0;i--)//方向不重要
    {
    stack.clear();
    对于(int j=array.length-1;j>=0;j--)
    {
    而(!stack.empty()&&array[stack.peek()][i]

    .

    这种方法有重复。例如,当您计算
    [0][2]
    元素(即3)时,您已经计算了
    [1][2]
    (即1)。尝试看看是否可以重用信息。@StutiRastogi:这里不是这样,因为您看到了第三条规则。对于[1][2],可访问元素计数只有1(本身)因为下一个向下[2][2]元素=2大于此值。但是对于[0][2],可访问计数为3,因为[1][2],[2][2]两者都较小并包含其自身。否则我可以使用DP。“在元素的行和列中移动,我们从初始位置开始”-这是什么意思?@n.m.这意味着在向右或向下移动时没有锯齿形图案。因此,对于任何节点,两条路径被视为向下(同一列增加行)和向右(同一行增加列)。我认为这将是“在同一行或列内移动”.那是不对的,我想,你犯了与第一条评论相同的错误。我明白你的意思,你说如果通过(0,2)对于我的方法,它将返回2而不是3,这就是该算法的优点…传入visit_count=1而不是0,然后查看magicor如果您知道当前单元格未被考虑,则将+1添加到该方法返回的结果中,但不考虑必须比较下一个值对于第一个值而不是当前值,仍然不好,因为缓存的值是针对特定的valx和valy的,结果取决于它们无法验证这一点,对于1 2,2 2 1,2 1 2输出应为1 1 2,1 2 1,2 1 11@GP007修正了。那应该是
    112131211
    ,不是吗?(因为中间元素可以访问自身,1向下和1向右)它将是2,因为我们必须在两个方向上找到两个可能值中的最大可能值。我们只能在一个方向上移动。因此,向右或向下为自身加1和1。@GP007