Рекурсивно разобрать слово - PullRequest
3 голосов
/ 11 марта 2011

Мне дали следующее:

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

и в настоящий момент я совершенно не понимаю, как начать, если кто-то может помочь.

Вывод должен выглядеть следующим образом:

 Enter a string: ABCD

 ABCD
 A BCD
 A B CD
 A B C D
 A BC D
 AB CD
 AB C D
 ABC D

Ответы [ 5 ]

5 голосов
/ 11 марта 2011

Я дам вам подсказки, чтобы помочь:

Подумайте, как решить эту проблему рекурсивно. По сути, это можно решить с помощью варианта «разделяй и властвуй». Для данной строки длиной n есть n-1 мест, где вы можете вставить разделители.

Таким образом, если у вас есть строка длины 2, у вас есть одно место для вставки разделителя и два варианта: либо вы вставляете разделитель, либо нет.

Если у вас есть строка длины 3, у вас есть 2 варианта в 2 местах. Таким образом, функция может создать строку с пробелом, вставленным в первую очередь, и рекурсивно вызвать себя с необработанным хвостом строки, чтобы получить все варианты для этой подстроки. Затем создайте другую строку префикса, в которой нет места, вставленного в первую очередь, и снова вызовите себя с остальной частью строки.

Для каждого рекурсивного вызова он должен передать себе уже сгенерированный префикс строки и оставшийся необработанный хвост строки.

5 голосов
/ 11 марта 2011

Есть шаблон для вывода, который вы дали (например, в порядке, в котором эти результаты были произведены).Рассмотрим, что общего между выходами 2-5:

A BCD
A B CD
A B C D
A BC D

Итак, похоже, что ваша функция собирается напечатать свой ввод (ABCD), а затем в качестве префикса она примет первую букву (A) и рекурсивно найти все комбинации оставшихся букв (BCD).Это намекает на то, что фактическое определение для функции принимает два параметра - префикс, который уже раскрыт, и набор оставшихся букв для перечисления комбинаций для.

Сделав это с одной буквой, мы затем переместимеще одна буква в этом префиксе (AB) и снова рекурсивно найти все комбинации для оставшихся букв (CD), чтобы получить следующий набор выходных данных:

AB CD
AB C D
2 голосов
/ 11 марта 2011

Спасибо за то, что вы честны, потому что это домашнее задание.Хитрость в написании рекурсивной функции Foo(n) состоит в том, чтобы предположить, что Foo(n-1) уже работает как надо.В этом случае вам поручено написать функцию GenerateSpaceVariationsOfString(string s), которая принимает строку s в качестве параметра и должна возвращать массив, содержащий все возможные варианты строки.(Будет проще создать рекурсивную функцию, которая будет возвращать свой результат, а не ту, которая печатает результаты - тогда вы можете просто напечатать массив, полученный из функции.) Допустим, s имеет длину n.Теперь предположим, что у вас есть функция, которая может взять s минус ее первую букву и вернуть массив всех возможных пробелов этой подстроки - другими словами, предположим, что GenerateSpaceVariationsOfString(s.substring(1)) даст {"BCD", "BCD", "BC D", "BC D", ...}, если sABCD.Как вы могли бы использовать это, чтобы написать GenerateSpaceVariationsOfString?

(В рекурсии вам также нужен базовый случай, так что же должно GenerateSpaceVariationsOfString(s) возвращать, если длина s равна 0 или 1?)

1 голос
/ 11 марта 2011

Простой рекурсивный алгоритм может быть реализован, если вы понимаете, что сегментация строки s равна набору, содержащему s, и объединению наборов каждой подстроки X из s с сегментациейs\X.Кроме того, поскольку у вас всегда будет n-1 возможных подстрок, и вы можете сегментировать или не сегментировать в каждой из этих точек, у вас всегда будет 2^(n-1) сегментов.

Это проще понять на примере сегментации строки ABC:

  1. {'ABC'} // сама 'ABC'
  2. {'A', 'B,' C '} // подстрока' A 'объединение 1-я сегментация' BC '= {' B, 'C'}
  3. {'A', 'BC '} // подстрока' A ', объединение 2-й сегментации' BC '= {' BC '}
  4. {' AB ',' C '} // подстрока' AB ', объединение 1-й и только сегментация'C '= {' C '}
  5. Объединение 1, 2, 3 и 4, дает все сегментации строки ABC.

Это переводит почтинепосредственно к следующей реализации:

public static Set<Set<String>> segment(String s) {
    // `s` itself.
    Set<Set<String>> result = new LinkedHashSet<Set<String>>();
    Set<String> root = new LinkedHashSet<String>();
    root.add(s);
    result.add(root);   

    // set union of each substring `X` (prefix) of `s` with `s\X` (rest).
    for (int i = 1; i < s.length(); i++) {   
        String prefix = s.substring(0, i);
        String rest = s.substring(i);
        for (Set<String> segments : segment(rest)) {
            Set<String> segment = new LinkedHashSet<String>();
            segment.add(prefix);
            segment.addAll(segments);
            result.add(segment);
        }
    }
    return result;
}

Пример выходных данных:

System.out.println(segment("ABC"));
// [[ABC], [AB, C], [A, B, C], [BC, A]]
System.out.println(segment("ABCD"));
// [[D, AB, C], [BCD, A], [D, ABC], [D, A, B, C], [AB, CD], [ABCD], [D, BC, A], [A, B, CD]]
0 голосов
/ 11 марта 2011

Думайте о соединении двух букв как одного бита. Если бит равен 1, тогда вы вставляете пробел, а если 0, то нет. Поэтому, если длина строки равна n, вы создаете битовую последовательность длиной n-1. Затем вы обрабатываете битовую последовательность как целое число без знака и просматриваете все возможные значения: 000, 001, 010 и т. Д.

Конечно, это не рекурсивно, поэтому вы не получите за это кредит.

...