找到所有可能的最长增加子序列

时间:2012-03-04 10:48:26

标签: algorithm dynamic

我想找到给定字符串中所有可能的最长增加子序列。

例如:给定字符串为qapbso

这里,增长最长的子序列的长度是3。 我想找到长度为3的所有可能最长的子序列,即“abs”,“aps”,“abo”。

我正在使用动态编程,但我只获得一个LIS。我想列出所有这些。

4 个答案:

答案 0 :(得分:5)

因此典型的DP解决方案会生成一个数组,在这个数组中你知道从给定位置开始的最长可能的子序列我可以说你有和长度为n的数组,其中dp [i]存储长度为从索引为i的元素开始的最长的非递减子序列。

现在使用递归最简单地打印所有LNDSS(最长的非递减子序列)。首先通过选择dp中的greast值来查找LNDSS的实际长度。接下来从dp中的每个元素开始递归,该元素在dp中具有最大值(这些可能多于一个)。来自给定索引的递归应该打印从当前索引开始的所有序列,其长度等于值dp [i]:

int st[1000];
int st_index
void rec(int index) {
  if (dp[index] == 1) {
    cout << "Another sequence:\n";
    for (int i = 0; i < st_index; ++i) {
      cout << st[i] << endl;
    }
  }
  for (int j = index + 1; j < n; ++j) {
    if (dp[j] == dp[index] - 1 && a[j] >= a[index]) {
      st[st_index++] = a[j];
      rec(j);
      st_index--;
    }
  }
}

这是c ++中的示例代码(希望在其他语言中也可以理解)。我有一个名为stack的全局堆栈,它保留了我们已经添加的元素。它的大小为1000,假设你在LNDSS中永远不会有超过1000个元素,但这可以增加。该解决方案没有最好的设计,但我专注于使其简单而不是精心设计。

希望这有帮助。

答案 1 :(得分:2)

给定此图表,其中所有节点都连接到具有较高值的​​节点,并在输入字符串的字母序列中稍后出现:

graph

您想要找到从START到END的最长路径。如果所有段的负长度都为-1,则这相当于最短路径。

关于最长路径问题的参考:http://en.wikipedia.org/wiki/Longest_path_problem

答案 2 :(得分:2)

2000年,Sergei Bespamyatnikh和Michael Segal提出了一种算法,用于找到给定排列的所有最长增长的子序列。该算法使用Van Emde Boas tree,时间复杂度为 O(n + Kl(p)),空间复杂度为 O(n),其中 n 是排列的长度 p l(p)是其最长的增加子序列的长度, K 是这些子序列的数量。

请参阅ACM数字图书馆中的paper或在网上搜索“枚举最长的增长子序列和耐心排序”以获得免费的PDF。

答案 3 :(得分:-2)

您可以使用回溯列出所有子序列。

检查printLIS功能,希望它有所帮助。

public class LIS {

    private static int[] count;

    public int longestIncreaseSubsequence(char[] seq) {
        int n = seq.length;

        for (int i = 0; i < n; i++) {
            count[i] = 1;
        }

        for (int i = 1; i < n; i++) {
            int max = 0;
            for (int j = i-1; j >= 0; j--) {
                if (seq[j] < seq[i]) max = Math.max(max, count[j]);
            }
            count[i] = max + 1;
        }

        int max = Integer.MIN_VALUE;
        for (int i = 0; i < count.length; i++) {
            if (count[i] > max) max = count[i];
        }

        return max;
    }

    public void printLIS(int[] a, int k, int[] count, char[] arr, int max) {
        if (k == max) {
            for (int i = max; i >= 1; i--) {
                System.out.printf("%c ", arr[a[i]]);
            }
            System.out.println();
        } else {
            k++;

            int[] candidates = new int[arr.length];
            int ncandidate = 0;

            for (int i = a[k-1]; i >= 0; i--) {
                if (count[i] == max-k+1 && (arr[i] < arr[a[k-1]] || count[i] == max)) {
                    candidates[ncandidate] = i;
                    ncandidate++;
                }
            }

            for (int i = 0; i < ncandidate; i++) {
                a[k] = candidates[i];
                printLIS(a, k, count, arr, max);
            }
        }
    }

    public static void main(String[] args) {
        char[] input = {'q','a','p','b','s','o','a'};
        LIS lis = new LIS();

        count = new int[input.length];  

        int max = lis.longestIncreaseSubsequence(input);
        int[] a = new int[max+1];
        a[0] = input.length-1; 

        lis.printLIS(a, 0, count, input, max);
    }
}