Получить список индекса в соответствии подпоследовательности - PullRequest
1 голос
/ 22 июня 2010

У меня есть 2 последовательности, например, s = aaba и ss = aa, и я хочу, чтобы ss был в s.В этом примере: [0,1], [0,3] и [1,3] Мой код ниже.Работает нормально, за исключением очень длинных s с несколькими ss.В этом случае у меня есть

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded (я уже использую java с -Xmx в максимально возможной степени…)

public static ArrayList<ArrayList<Integer>> getListIndex(String[] s, String[] ss, int is, int iss) {
    ArrayList<ArrayList<Integer>> listOfListIndex = new ArrayList<ArrayList<Integer>>();
    ArrayList<ArrayList<Integer>> listRec = new ArrayList<ArrayList<Integer>>();
            ArrayList<Integer> listI = new ArrayList<Integer>();

    if (iss<0||is<iss){
        return listOfListIndex;
    }

    if (ss[iss].compareTo(s[is])==0){

        //ss[iss] matches, search ss[0..iss-1] in s[0..is-1]
        listRec = getListIndex(s,ss,is-1,iss-1);

        //empty lists (iss=0 for instance)
        if(listRec.size()==0){
            listI = new  ArrayList<Integer>();
            listI.add(is);
            listOfListIndex.add(listI);
        }
        else{
            //adding to what we have already found
            for (int i=0; i<listRec.size();i++){
                listI = listRec.get(i);
                    listI.add(is);
                    listOfListIndex.add(listI);
            }
        }
    }
    //In all cases
    //searching ss[0..iss] in s[0..is-1]
    listRec = getListIndex(s,ss,is-1,iss);
    for (int i=0; i<listRec.size();i++){
        listI = listRec.get(i);
            listOfListIndex.add(listI);
    }

    return listOfListIndex;
}   

Есть ли способ сделать это более эффективно?

Ответы [ 3 ]

0 голосов
/ 22 июня 2010

ArrayList<Integer> довольно неэффективно из-за накладных расходов класса-оболочки. Использование TIntArrayList из GNU Trove , вероятно, сократит использование вашей памяти в 3 раза (или даже больше, если вы используете 64-битную JVM).

0 голосов
/ 22 июня 2010

Я сомневаюсь, что проблема в рекурсии (подумайте, какова максимальная глубина рекурсии). Алгоритм может быть эффективно реализован путем сбора значений каждого символа s в ss в TreeSet с, а затем просто взятия .tailSet при необходимости «продвижения» в строке.

import java.util.*;


public class Test {

    public static Set<List<Integer>> solutions(List<TreeSet<Integer>> is, int n) {

        TreeSet<Integer> ts = is.get(0);
        Set<List<Integer>> sol = new HashSet<List<Integer>>();
        for (int i : ts.tailSet(n+1)) {
            if (is.size() == 1) {
                List<Integer> l = new ArrayList<Integer>();
                l.add(i);
                sol.add(l);
            } else 
                for (List<Integer> tail : solutions(is.subList(1, is.size()), i)) {
                    List<Integer> l = new ArrayList<Integer>();
                    l.add(i);
                    l.addAll(tail);
                    sol.add(l);
                }
        }
        return sol;
    }


    public static void main(String[] args) {
        String ss = "aaba";
        String s = "aa";

        List<TreeSet<Integer>> is = new ArrayList<TreeSet<Integer>>();

        // Compute all indecies of each character.
        for (int i = 0; i < s.length(); i++) {
            TreeSet<Integer> indecies = new TreeSet<Integer>();
            char c = s.charAt(i);
            for (int j = 0; j < ss.length(); j++) {
                if (ss.charAt(j) == c)
                    indecies.add(j);
            }
            is.add(indecies);
        }

        System.out.println(solutions(is, -1));
    }
}

Выход:

[[0, 1], [1, 3], [0, 3]]
0 голосов
/ 22 июня 2010

Ну, основная проблема в том, что ваш алгоритм рекурсивный. Java не выполняет оптимизацию хвостовых вызовов, поэтому каждый рекурсивный вызов просто добавляет в стек, пока вы не переполнитесь.

То, что вы хотите сделать, это реструктурировать ваш алгоритм, чтобы он был итеративным, чтобы вы не добавляли его в стек. Вместо этого подумайте о том, чтобы поместить цикл (с тестом завершения) как самый внешний элемент вашего метода.

Еще один способ взглянуть на эту проблему - разбить ее на два этапа:

  1. Захватите позиции всего данного символа («a» в вашем примере) в один набор.
  2. Все, что вам нужно здесь, это полный набор комбинаций между ними. Помните, что уравнение для числа комбинаций r вещей, выбранных из n разных вещей:

     C(n,r) = n!/[r!(n-r)!]
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...