DFS по сравнению со строкой (префикс)

Я написал следующий префикс:

class TrieNode {
    char letter;
    HashMap<Character,TrieNode> children;
    boolean fullWord;

    TrieNode(char letter) {
        this.letter = letter;
        children = new  HashMap<Character, TrieNode>();
        this.fullWord = false;
    }
}

class Tree{
    static TrieNode createTree() {
         return (new TrieNode('\0'));
    }

    static void insertWord(TrieNode root, String word) {
        int l = word.length();
        char[] letters = word.toCharArray();
        TrieNode curNode = root;
        for (int i = 0; i < l; i++) {
            if (!curNode.children.containsKey(letters[i]))
                curNode.children.put(letters[i], new TrieNode(letters[i]));
            curNode = curNode.children.get(letters[i]);
        }
        curNode.fullWord = true;
    }
}

Я хотел бы добавить метод DFS, чтобы найти первый узел, который имеет более 1 дочернего элемента (поэтому он покажет мне самый длинный общий префикс).

Я написал этот код:

static void DFS(TrieNode node) {
    for (TrieNode tn: node.children.values()){
       DFS(tn);
        if (node.children.size()>2)
        System.out.println("found the first vertex");
    }
}

Но это не работает. Что я делаю неправильно?


person Dejell    schedule 04.05.2013    source источник
comment
2 ребра или дети?   -  person amin k    schedule 05.05.2013
comment
2 и более детей. Таким образом, я буду знать, что до этого места это самый длинный общий префикс   -  person Dejell    schedule 05.05.2013
comment
Пожалуйста, уточните свой вопрос, вы ищете самый длинный общий префикс из всех записей, которые состоят из дерева префиксов? Если это так, children.size()›2 недостаточно. Или вы ищете самый длинный общий префикс для любых двух строк?   -  person Faraway    schedule 05.05.2013
comment
Да- из всех записей дерева   -  person Dejell    schedule 05.05.2013


Ответы (2)


Итак, сначала нам нужно уточнить, что наиболее длинный общий префикс здесь означает самый длинный общий префикс любых двух или более строк в дереве дерева.

Таким образом, ваш метод поиска в глубину не будет работать, потому что он просто обходит все дерево и выводит "найдена первая вершина" при посещении любого узла, у которого children.size() > 2 (это здесь должно быть >=2)

Здесь нам нужно найти только самый длинный общий префикс. Поэтому нам нужна дополнительная информация о том, какой из них самый длинный. Это легко увидеть в моем примере выше:

          root      --depth: 0
           |
           a        --depth: 1
           |
           b        --depth: 2
          / \
         c   f      --depth: 3
        /|\
       d g k        --depth: 4
            \
             k      --depth: 5 

Самый длинный общий узел префикса имеет children.size()>1 AND максимальную глубину. В данном случае это узел c

Итак, вот один из возможных правильных DFS:

static int max=-1;
static TrieNode maxNode=null;

static void dfs(TrieNode node, int depth){
    if(node.children.size()>1 && depth>max){
        max=depth;
        maxNode=node;
    }
    for (TrieNode tn: node.children.values())
        dfs(tn,depth+1);
}

public static void test(){
    TrieNode root = Tree.createTree();
    Tree.insertWord(root, "abcd");
    Tree.insertWord(root, "abcg");
    Tree.insertWord(root, "abckk");
    Tree.insertWord(root, "abf");
    dfs(root,0);
    System.out.println("Max node:"+maxNode.letter);
}

После запуска dfs maxNode будет содержать узел, на котором останавливается самый длинный общий префикс. в данном случае это узел c.

person Faraway    schedule 05.05.2013

Ваш код дерева префиксов кажется хорошим. По крайней мере, для меня это имеет смысл, но я не проверял все крайние случаи. Проблема в вашем методе DFS. Предполагая, что у нас есть следующие строки, которые состоят из вашего дерева префиксов:

- "abcd"
- "abcg"
- "abckk"
- "abf"

Итак, дерево префиксов должно выглядеть так:

              root
               |
               a
               |
               b
              / \
             c   f
            /|\
           d g k
                \
                 k

Я думаю, вы ожидаете, что мы сможем вывести "найдена первая вершина" в узле b (потому что, очевидно, "ab" является самым длинным общим префиксом вершины). над четырьмя строками), однако ваша DFS не работает таким образом. Он пойдет по пути

root->a->b->c->d then back to c, finding that c.children.size() >1 , then output.

Обратите внимание, что "2 или больше" – это >=2 или >1, что в вашей программе равно >2. Я подумал, что это опечатка. Чтобы исправить DFS, просто измените его, чтобы сначала проверить размер дочернего узла:

static boolean DFS(TrieNode node) {
    if (node.children.size()>1){
        System.out.println("found the first vertex on node:"+node.letter);
        return true;
    }
    for (TrieNode tn: node.children.values()){
        if(DFS(tn))
            return true;
    }
    return false;
}

Обратите внимание, чтобы программа остановилась при поиске нашего узла, я изменяю тип возвращаемого вами DFS. Кроме того, что касается поиска самого длинного общего префикса, DFS здесь может быть не лучшим выбором, следующий код лучше, чем DFS, с точки зрения сложности выполнения:

static void lcp(TrieNode node){
    TrieNode first = node;
    while(first.children.size()==1)
        first = first.children.values().iterator().next();
    System.out.println("found the first vertex on node:"+first.letter);
}
person Faraway    schedule 05.05.2013
comment
Привет, вы сказали, что нашли первую вершину в узле b (поскольку очевидно, что ab является самым длинным общим префиксом из приведенных выше четырех строк), но правда в том, что в приведенном выше случае abc является самым длинным префиксом. - person Dejell; 05.05.2013
comment
@Odelya Я что-то пропустил? Общий самый длинный общий префикс четырех строк в моем примере — ab. Обратите внимание на 4-ю строку abf, она начинается только с ab. Вы сказали, что ищете самый длинный общий префикс из всех записей, которые состоят из дерева префиксов. Это правильно? - person Faraway; 05.05.2013
comment
@Odelya Или вы можете дать мне свое определение самого длинного распространенного префикса, привести несколько примеров, и я смогу исправить ваш код. - person Faraway; 05.05.2013
comment
Самый длинный общий префикс не обязательно должен быть во ВСЕХ строках — может быть и в некоторых из них. Вот почему abc длиннее ab, хотя встречается только в 3 строках и не во всех. - person Dejell; 05.05.2013
comment
@Odelya Ну, я должен сказать, что это определение запрограммировано. В любом случае, вы хотите найти самый длинный общий префикс, если он встречается хотя бы в двух строках, верно? Я опубликую другой ответ. - person Faraway; 05.05.2013