【问题标题】:Longest Increasing Sequence 2D matrix recursion最长递增序列二维矩阵递归
【发布时间】:2011-07-02 18:06:01
【问题描述】:

我收到了一项新的家庭作业,至少可以说有点令人沮丧。基本上,我创建了一个二维整数数组,如下所示:

97 47 56 36 60 31 57 54 12 55 
35 57 41 13 82 80 71 93 31 62 
89 36 98 75 91 46 95 53 37 99 
25 45 26 17 15 82 80 73 96 17 
75 22 63 96 96 36 64 31 99 86 
12 80 42 74 54 14 93 17 14 55 
14 15 20 71 34 50 22 60 32 41 
90 69 44 52 54 73 20 12 55 52 
39 33 25 31 76 45 44 84 90 52 
94 35 55 24 41 63 87 93 79 24

我要写一个递归方法,或者你会的函数,来计算最长的递增子序列。在这个例子中,最长的递增子序列如下:

(5,0)   with value 12
(6,0)   with value 14
(6,1)   with value 15
(6,2)   with value 20
(7,2)   with value 44
(7,3)   with value 52
(7,4)   with value 54
(6,3)   with value 71
(5,3)   with value 74
(4,3)   with value 96

所以,我不仅要检查 N、S、E、W 的值是否严格更大,而且我还必须考虑对角线。我已经对如何递归解决这个问题进行了广泛的研究,但是我运气不佳,递归是我最薄弱的主题(是的,我知道它在某些情况下有多强大)。我看到过类似的帖子,有人提到了亚克力图,但这不是我要找的。​​p>

到目前为止,我基本上已经用 0 填充了我的 2D 数组,这样我就不必担心边界问题,并且我正在使用嵌套的 for 循环来遍历 2D 数组。在这些循环中,我基本上是在检查 N、NE、E、SE、S、SW、W、NW 是否具有比当前元素更大的值。对不起,如果我让你们中的一些人不高兴,这是我第一次尝试发帖。如果您需要我发布一些代码,我会这样做。非常感谢您的宝贵时间!

【问题讨论】:

  • 我不明白,the longest increasing sub sequence 是什么意思?
  • 好的,在我上面发布的示例中,12,14,15,20,44,52,54,71,74,96 是一个递增的子序列。注意数字是如何严格按递增顺序排列的。希望这会有所帮助。
  • 现在,我明白了,似乎需要做很多工作
  • 这是一个相当艰难的过程。我假设您正在寻找与搜索方向无关的最长子序列?
  • @Perception 是正确的。 @templatetypedef 不幸的是,我们还没有在我们的数据结构类中介绍图表,尽管我从很多人那里听说使用图表更容易解决这个问题。

标签: java algorithm recursion


【解决方案1】:

更新

我最近学习了动态规划,我找到了一个更好的算法来解决这个问题。

算法很简单:找到每个点的最长长度,并将结果记录在一个二维数组中,这样我们就不需要再计算一些点的最长长度了。

int original[m][n] = {...};
int longest[m][n] = {0};

int find() {
    int max = 0;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            int current = findfor(i, j);
            if (current > max) { max = current; }
        }
    }
    return max;
}

int findfor(int i, int j) {
    if (longest[i][j] == 0) {
        int max = 0;
        for (int k = -1; k <= 1; k++) {
            for (int l = -1; l <= 1; l++) {
                if (!(k == 0 && l == 0) &&
                    i + k >= 0 && i + k < m &&
                    j + l >= 0 && j + l < n &&
                    original[i + k][j + l] > original[i][j]
                   )
                    int current = findfor(i + k, j + l);
                    if (current > max) { max = current; }
                }
            }
        }
        longest[i][j] = max + 1;
    }
    return longest[i][j];
}    

递归

1) 从一个点开始(所有必要的点都必须执行此步骤)

2)如果没有更大的周围点,那么这条路径就结束了; else 选择一个更大的周围点继续路径,然后转到 2)。

2.1) 如果(结束的)路径比记录的最长路径长,则将自己替换为最长的。


提示

(更少的计算,但更多的编码)

对于最长的路径,起点为局部极小点,终点为局部极大点。

局部最小值,小于(或等于)所有(最多)8 个周围点。

局部最大值,大于(或等于)所有(最多)8 个周围点。

证明

如果路径不是以局部最小值开始的,那么起点必须大于至少一个周围点,因此可以扩展路径。拒绝!因此,路径必须以局部最小值开始。以局部最大值结束的原因类似。


伪代码

对于所有局部最小值 做一个递归搜索 recursive_search(点) 如果点是局部最大值 结束,并比较(必要时替换)最长 别的 对于所有更大的周围点 做一个递归搜索

【讨论】:

  • Dante,非常感谢您的深入解释,我将尝试以这种方式实现。如果我有困难,我会回来的。谢谢
【解决方案2】:

另一种方法:按矩阵条目中的值对矩阵条目进行排序。从最大到最小迭代。对于每个条目,在恒定时间内计算最长路径:最长路径是 1 + 最大邻居的最长路径(已经计算过)。

总时间:O(mn log(mn)) 对矩阵条目进行排序,加上 O(mn) 来找到最长的路径。

【讨论】:

    【解决方案3】:

    java完整解决方案 它将路径返回到控制台,并返回最长的序列,但是你可以稍微修改这段代码,你也会得到最长的路径

    public class HedgehogProblemSolver {
    
    private int rowCount;
    private int columnCount;
    private int[][] fieldArray;
    private int maxApplesCount = 0;
    
    public HedgehogProblemSolver(int inputArray[][]) {
        this.fieldArray = inputArray;
        rowCount = inputArray.length;
        columnCount = inputArray[0].length;
    }
    
    public int solveProblem() {
        findPathRecursive(0, 0, "", 0);
        System.out.println("Max apple count: " + maxApplesCount);
        return maxApplesCount;
    }
    
    private void findPathRecursive(int row, int column, String path, int applesCount) {
        if (row == rowCount - 1) {
            //last row
            for (int i = column; i < columnCount; i++) {
                //just go right until last column
                path += "-[" + fieldArray[row][i]  + "](" + row + ", " + i + ")";
                applesCount += fieldArray[row][i];
            }
            pathResult(path, applesCount);
            return;
        }
        if (column == columnCount - 1) {
            //last column
            for (int i = row; i <= rowCount - 1; i++) {
                //just go down until last row
                path += "-[" + fieldArray[i][column] + "](" + i + ", " + column + ")";
                applesCount += fieldArray[i][column];
            }
            pathResult(path, applesCount);
            return;
        }
    
        path = path + "-[" + fieldArray[row][column] + "](" + row + ", " + column + ")";
        applesCount += fieldArray[row][column];
    
        //go down
        findPathRecursive(row + 1, column, path, applesCount);
        //go right
        findPathRecursive(row, column + 1, path, applesCount);
    }
    
    private void pathResult(String path, int applesCount) {
        System.out.println("Path: " + path + "; apples: " + applesCount);
        if (applesCount > maxApplesCount) {
            maxApplesCount = applesCount;
        }
    }
    
    }
    

    【讨论】:

      【解决方案4】:

      我知道这是一个非常古老的问题,但是,我正在阅读 Lubomir Stanchev 的书《通过游戏学习 Java》,第 14 章项目就是精确的二维整数数组。任务是找到最长的递增序列,但只在两个方向,南和东,没有对角线或任何东西。我仍然花了几个小时才弄清楚逻辑,也不习惯递归。 我通过创建辅助方法来简化问题,这些方法检查下一个索引在那个方向上是否有效(即,没有超出范围并且大于当前值)。然后我将基本情况放在方法的开头,也就是没有下一个可能的索引的时候。棘手的部分是字符串变量的赋值,因此每次方法使用递归时,索引都保存在字符串中。当有多个可能的路径时,我通过使用 String.length() 方法来比较每个序列的长度来解决它。 有了基本逻辑,为了扩展方法,只需要在需要的方向上创建更多的辅助方法,并将这些方向添加到逻辑中。

      public static boolean isRightLegal(int[][] array, int row, int column) {
          //if we are at the last column
          if (column >= array[row].length - 1) {
              return false;
          }
          //if we are not at the one before last
          if ((column + 1) < array[row].length) {
              //if the current number is greater than the next
              if (array[row][column] > array[row][column + 1]) {
                  return false;
              }
          }
          return true;
      }
      
      public static boolean isDownLegal(int[][] array, int row, int column) {
          //if we are at the last row
          if (row >= array.length - 1) {
              return false;
          }
          //if we are not at the one before last
          if ((row + 1) < array.length) {
              //if the current number is greater than the next
              if (array[row][column] > array[row + 1][column]) {
                  return false;
              }
          }   
          return true;
      }
      
      public static String recursiveSequence(int[][] array, int row, int column, String path) {
          //base case: when we reach the end of the sequence
          if (! isDownLegal(array, row, column) && ! isRightLegal(array, row, column)) {
              return "(" + row + "," + column + ") ";
          }
          path = "(" + row + "," + column + ") ";
          //if both paths are valid
          if (isDownLegal(array, row, column) && isRightLegal(array, row, column)) {
              //calculate each sequence and pick the longest one
              if (recursiveSequence(array, (row + 1), column, path).length() > recursiveSequence(array, row, (column + 1), path).length()) {
                  path += recursiveSequence(array, (row + 1), column, path);
              } else {
                  path += recursiveSequence(array, row, (column + 1), path);
              }
              return path;
          }
          //if only the down path is valid
          if (isDownLegal(array, row, column)) {
              path += recursiveSequence(array, (row + 1), column, path);
          }
          //if only the right path is valid
          if (isRightLegal(array, row, column)) {
              path += recursiveSequence(array, row, (column + 1), path);
          }
          return path;
      }
      

      }

      【讨论】:

        猜你喜欢
        • 2016-05-04
        • 2020-03-06
        • 2017-07-10
        • 2012-11-26
        • 2018-03-26
        • 2019-11-13
        • 2014-04-22
        • 2019-03-25
        • 2015-10-28
        相关资源
        最近更新 更多