Алгоритм для создания всех комбинаций строки
Я нашел ссылку онлайн, в которой показан алгоритм для создания всех комбинаций строки: http://www.mytechinterviews.com/combinations-of-a-string
Алгоритм копируется ниже.
void combine(String instr, StringBuffer outstr, int index)
{
for (int i = index; i < instr.length(); i++)
{
outstr.append(instr.charAt(i));
System.out.println(outstr);
combine(instr, outstr, i + 1);
outstr.deleteCharAt(outstr.length() - 1);
}
}
combine("abc", new StringBuffer(), 0);
То, что я не понимаю, это строка:
outstr.deleteCharAt(outstr.length() - 1);
Если я удалю эту строку, программа, очевидно, больше не работает, но почему это необходимо в первую очередь? Я понимаю рекурсивную идею, в которой мы меняем начальный символ и рекурсируем оставшиеся символы, но строка deleteChar, похоже, не вписывается в логически нигде. В чем причина добавления строки outstr.deleteCharAt?
Ответы
Ответ 1
Вызов outstr.deleteCharAt
вызывает эффект outstr.append
, удалив последний символ outstr
.
Каждая итерация цикла выполняется следующим образом:
- добавить символ
- распечатать результат
- выполнить рекурсивный вызов на уровне
i+1
- удалите символ, добавленный нами на шаге 1
Ответ 2
Самый простой способ вычисления возможных комбинаций строк здесь...
Математически найти R-комбинации в заданной партии N = NcR
Итак, что мы здесь находим, все возможные комбинации = Nc0 + Nc1.... + Ncn = 2 Pow N
Итак, вы получаете две комбинации Pow N для заданного слова длиной N символов.
Если вы представляете целые числа от 1 до (2 Pow N) в двоичном формате и размещаете ваш char в том месте, где присутствует 1, вы, наконец, получите решение.
Пример:
Вход: ABC
Решение:
Длина ABC равна 3. Возможны комбинации 2 Pow 3 = 8
Если 0 - 8, представленное в двоичном формате
000 =
001 = C
010 = B
011 = BC
100 = A
101 = AC
110 = AB
111 = ABC
все возможные комбинации показаны выше.
Ответ 3
Он уравновешивает первую строку тела цикла, восстанавливая outstr для того, что было в верхней части тела цикла (удалив символ из instr, который был добавлен).
Ответ 4
Это очень логично. Вы видите, что мы имеем здесь рекурсивный алгоритм. На каждом шаге в позиции i
мы помещаем букву строки, затем вызываем функцию рекурсивно, чтобы поместить другую букву в следующую позицию. Однако, когда мы возвращаемся из рекурсии, нам нужно удалить первоначально поставленный символ, чтобы мы могли заменить его следующим возможным в последовательности. Пример:
append a on pos 0 -> a
call recursion
append a on pos 1 -> aa
call recursion
append a on pos 2 -> aaa
return from recursion
remove a from pos 2 -> aa
append b on pos 2 -> aab
return from recursion
remove b from pos 2 -> aa
append c on pos 2 -> aac
etc.
Ответ 5
Ниже код должен генерировать перестановку и комбинацию строки, в основном концепция состоит в том, чтобы выбрать один символ за раз:
public class permutecombo
{
static void initiate(String s)
{
permute("", s);
System.out.println("----------------------------------------- ");
combo("", s);
System.out.println("----------------------------------------- ");
}
static void combo(String prefix, String s)
{
int N = s.length();
System.out.println(prefix);
for (int i = 0 ; i < N ; i++)
combo(prefix + s.charAt(i), s.substring(i+1));
}
static void permute(String prefix, String s)
{
int N = s.length();
if (N == 0)
System.out.println(" " + prefix);
for (int i = 0 ; i < N ; i++)
permute(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, N));
}
public static void main(String[] args)
{
String s = "1234";
initiate(s);
}
}
Ответ 6
Мы можем сгенерировать все подстроки строки, используя концепцию бит, о которой говорилось ранее. Вот код (на С++, но вы понимаете):
string s;
int n = s.size();
int num = 1<<n;
for(int i =1; i< num ; i++){ //Checks all the permutations.
int value = i;
int j, pos;
for (j=1, pos=1; j < num; j<<=1, pos++) //Finds the bits that are set
if (i & j)
cout<<s[pos-1]; //You can print s[n-pos] to print according to bit position
cout<<endl;
}
Например: - строка s = abc,
The size is 3 . So we check from 1 to 7 ( 1<<3).
for i = 1 ( 001 ) , the first bit is set, so a is printed.
for i = 2 ( 010 ) , the second bit is set, so b is printed.
for i = 3 ( 011 ) , the first and second bit are set, so ab is printed.
.
.
.
for i = 7 ( 111 ) , all three bits are set, so abc is printed.
Ответ 7
outstr.deleteCharAt(outstr.length() - 1);
означает, что у вас
n^(n-1)/2 pairs of combinations.
Итеративный цикл for не останавливается после вызова рекурсивной функции, поэтому вам нужно удалить последний char в выходном буфере, потому что вы не хотите получать
n^n/2 pairs of combinations.
В теории графов это будет короткое замыкание.
Ответ 8
Вот код С++ без сложного шага возврата в вопросе OP.
#include <iostream>
#include <string>
using namespace std;
static const string in("abc");
void combine(int i, string out)
{
if (i==in.size()) {
cout << out << endl;
return;
}
combine(i+1, out);
combine(i+1, out+in[i]);
}
int main()
{
combine(0, "");
return 0;
}
Я надеюсь, что это лучше отражает дух комбинаций.
Ответ 9
// IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!
import java.util.*;
public class Permutation {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
System.out.println("ENTER A STRING");
Set<String> se=find(in.nextLine());
System.out.println((se));
}
public static Set<String> find(String s)
{
Set<String> ss=new HashSet<String>();
if(s==null)
{
return null;
}
if(s.length()==0)
{
ss.add("");
}
else
{
char c=s.charAt(0);
String st=s.substring(1);
Set<String> qq=find(st);
for(String str:qq)
{
for(int i=0;i<=str.length();i++)
{
ss.add(comb(str,c,i));
}
}
}
return ss;
}
public static String comb(String s,char c,int i)
{
String start=s.substring(0,i);
String end=s.substring(i);
return start+c+end;
}
}
// IF YOU NEED REPEATITION USE ARRAYLIST INSTEAD OF SET!!
Ответ 10
import com.google.common.collect.Lists;
import java.util.List;
public class Combinations {
public static String[] getCombinations(final String input) {
final List<String> combinations = Lists.newArrayList();
getCombinations(input.toCharArray(), combinations, 0, "");
return combinations.toArray(new String[0]);
}
private static void getCombinations(final char[] input, final List<String> combinations, final int index, final String combination) {
if (index == input.length) {
combinations.add(combination);
return;
}
getCombinations(input, combinations, index + 1, combination + String.valueOf(input[index]));
getCombinations(input, combinations, index + 1, combination);
}
}
Соответствующие тесты:
import org.hamcrest.Matchers;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
public class CombinationsTest {
@Test
public void testCombinations() {
verify(Combinations.getCombinations(""), "");
verify(Combinations.getCombinations("a"), "a", "");
verify(Combinations.getCombinations("ab"), "ab", "a", "b", "");
verify(Combinations.getCombinations("abc"), "abc", "ab", "ac", "a", "bc", "b", "c", "");
verify(Combinations.getCombinations("abcd"),
"abcd", "abc", "abd", "ab", "acd", "ac", "ad", "a", "bcd", "bc", "bd", "b", "cd", "c", "d", "");
}
private void verify(final String[] actual, final String... expected) {
assertThat(actual, Matchers.equalTo(expected));
}
}