如何在数组中找到最长的单调减少子序列?

时间:2011-10-05 01:32:56

标签: arrays language-agnostic

好的,这是我的问题:


给定一个数组,例如{9,4,3,2,5,4,3,2},其最长的单调减少子序列是{9,5,4,3,2},其中每个元素都在与原始数组中的顺序相同。为简单起见,我们假设子序列中的元素都是不同的。


我已经考虑了一整天而无法找到解决方案......如果您有一些好的建议,请与我分享。谢谢!

4 个答案:

答案 0 :(得分:2)

这是一个动态编程问题。我们的想法是评估每个可能的子序列组合并将子问题结果存储在一个数组中,这样您就不需要计算它们两次了。

public class LDS {

    /*
      For each item in the array, get the longest
      decreasing subsequence to that item.

      return the max subsequence to that item, adding
      1 for the item itself.

      In both calculate and longestToN, subproblem results  are stored and reused to 
      avoid duplicate computation.
    */
    public int calculate(int []arr) {
        int []table = new int[arr.length];

        for (int i = 0; i < arr.length; ++i) {
            table[i] = -1;
        }

        int m = 0;

        for (int n = 0; n < arr.length; ++n) {

            if (table[n] == -1) {//Memoize
                table[n] = longestToN(n, arr, table);
            }

            m = Math.max(m, longestToN(n, arr, table));
        }
        return m + 1;
    }

    /*
      Recursively finds the longest decreasing subsequence in array up until arr[n] inclusive.
    */
    private int longestToN(int n, int []arr, int []table) {
        int m = 0;
        for (int i = n; i >= 0; --i) {
            if (arr[i] > arr[n]) {

                if (table[i] == -1) {//Memoize
                    table[i] = longestToN(i, arr, table);
                }

                m = Math.max(m, 1 + table[i]);
            }
        }
        return m;
    }
}

运行代码:

    LDS lds = new LDS();

    int []arr = {9, 4, 3, 2, 5, 4, 3, 2};
    int ret = lds.calculate(arr);

    System.out.println("Longest decreasing subsequence is " + ret);

在示例输入上运行代码计算5.我推荐一本名为算法设计手册的书籍,以便更好地理解动态编程。作者是一名教授,并在线发布了他的算法讲座@ http://www.cs.sunysb.edu/~skiena/373/

答案 1 :(得分:0)

一种解决方案是将序列重新排列成一系列树木;原始序列中的每个项目成为其中一个树中的节点。其父级被定义为第一个更大的前一项。然后,最长的子序列是最长的树分支,您可以通过遍历所有树(或在构建它们时保持跟踪)轻松计算。我不认为有一种更有效的方式,但这只是一种预感。

答案 2 :(得分:0)

  1. 制作数组的副本,并按降序排序
  2. 使用动态编程技术
  3. 找到两个数组中最长的公共子序列

答案 3 :(得分:0)

解决问题的递归

L(j) = max(1+ L(i)) where i A[j]
L(j) : Longest Decreasing Subsequence until jth index of the array

您可以使用动态编程来降低解决方案的时间复杂度。