Как получить все возможности строки, удалив хотя бы одну из определенных букв

1

Я немного новичок на Java, так что это может быть здравым смыслом для кого-то еще...

Я пытаюсь написать метод, который принимает строку ввода любой длины и возвращает список всех возможных вариантов строки с удалением хотя бы одного "i".

Например, вход может быть "кикикифики". Результатом будет список, содержащий слово с удалением 0 "i" ("kikikifiki"), каждое слово с одним удаленным "я" ("кикикифик", "кикикифки" и т.д.), Каждое слово с двумя "я", ("kikikifk", "kikikfik" и т.д.) и т.д. Выходной сигнал может иметь любое количество "i".

До сих пор я придумал что-то вроде этого:

String word = /*input goes here; has only a-zA-Z*/;
String hypo[] = new String[10000];
String wordOriginal = word;
String temp = word;
for (int g=0;g<(wordOriginal.replaceAll("[^i]","")).length();g++) {
    while (word.contains("i")) {
        for(int j=0; j<numI; j++) {
            //Test the current prefix with each following 'i' removed.
            temp = word.substring(0,temp.indexOf("i")+j) + temp.substring(word.indexOf("i")+j+1);
            hypo[index] = prefix + temp;
            for (int h=j; h>0; h--)
                temp = temp.substring(0,temp.indexOf("i")) + temp.substring(temp.indexOf("i")+1);
            index++;
        }
        word = word.substring(0,word.indexOf("i")) + word.substring(word.indexOf("i")+1);
        temp = word;
        numI = (word.replaceAll("[^i]","")).length();
    }
    word = wordOriginal;
    for (int ghj=0;ghj<g;ghj++)
        prefix = word.substring(0,word.indexOf("i")+1);
    word = word.substring(word.indexOf("i")+1);
    temp = word;
    numI = (word.replaceAll("[^i]","")).length();
}

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

Есть идеи?

-

EDIT: Кто-то предложил мне поставить желаемый результат с фактическим выходом. Я также добавил код ниже, чтобы соответствовать всему моему коду.

ВХОД:

Rifi

ЖЕЛАЕМЫЙ ВЫХОД: (необязательно в этом порядке)

ВЧ
понижение в должности
RFI
Rifi

АКТУАЛЬНЫЙ ВЫХОД:

ВЧ
RFI
понижение в должности
ВЧ
е

-

ВХОД:

kiraiki

ЖЕЛАЕМЫЙ ВЫХОД: (необязательно в этом порядке)

Крак
kirak
kraik
kraki
kiraik
Кираки
kraiki
kiraiki

АКТУАЛЬНЫЙ ВЫХОД:

Крак
kraiki
kiraiki
kiraiki
kraki
kraik
Крак
раки
Райк
Rak
Кираки
kiraik
kirak

-

Весь код:

package com;

/*public class KidishToEnglish {

    public static void main(String[] args) {
        //BruteForce brute = new BruteForce();
        //brute.bruteForce();
    }
}
*/

import java.util.Scanner;

public class KidishToEnglish
{
    public static void main(String[] args)
    {
        Scanner keyboard = new Scanner(System.in);
        while(true)
        {
            String word = "";

            //Get the word.
            System.out.print("Input:\n>> ");
            while (word.equals(""))
            {
                word = fixword(keyboard.nextLine().toLowerCase());
                if (word.equals("") || word.contains(" "))
                {
                    System.out.print("\nPlease input one single word.\n>> ");
                    word = "";
                }
                if (!legal(word))
                {
                    System.out.print("\nThis word contains illegal letters.\n>> ");
                    word = "";
                }
            }

            //Remove unnecessary letters.
            if (word.substring(word.length()-1).equals("u"))
                word = word.substring(0, word.length()-1);
            if (word.substring(word.length()-2).equals("es"))
                word = word.substring(0, word.length()-2);
            if (word.substring(word.length()-2).equals("in"))
                word = word.substring(0, word.length()-2);

            //Set up hypotheticals. For example, "rifi" would become an array containing "rf", "rfi", "rif", and "rifi".
            int numI = (word.replaceAll("[^i]","")).length();
            int index = 0;
            String wordOriginal = word;
            String prefix = "";
            String hypo[] = new String[10000];
            hypo[index] = word.replace("i","");
            index++;

            String temp = word;
            for (int g=0;g<(wordOriginal.replaceAll("[^i]","")).length();g++)
            {
                while (word.contains("i"))
                {
                    for(int j=0; j<numI; j++)
                    {
                        //Test the current prefix with each following 'i' removed.
                        temp = word.substring(0,temp.indexOf("i")+j) + temp.substring(word.indexOf("i")+j+1);
                        hypo[index] = prefix + temp;
                        for (int h=j; h>0; h--)
                            temp = temp.substring(0,temp.indexOf("i")) + temp.substring(temp.indexOf("i")+1);
                        index++;
                    }
                    word = word.substring(0,word.indexOf("i")) + word.substring(word.indexOf("i")+1);
                    temp = word;
                    numI = (word.replaceAll("[^i]","")).length();
                }
                word = wordOriginal;
                for (int ghj=0;ghj<g;ghj++)
                    prefix = word.substring(0,word.indexOf("i")+1);
                word = word.substring(word.indexOf("i")+1);
                temp = word;
                numI = (word.replaceAll("[^i]","")).length();
            }



            boolean test = true;
            int testnum = 0;
            while (test)
            {
                if(testnum >= index)
                    test = false;
                else
                    System.out.println(hypo[testnum]);
                    testnum++;
            }

        }
    }





    public static String fixword(String word)
    {
        word = word.replaceAll("[^a-zA-Z ]","");
        word = word.trim();
        return word;
    }

    public static boolean legal(String word)
    {
        return ((word.replaceAll("[abdefhikmrsuw]","")).equals(""));
    }
}
  • 0
    Это домашнее задание или что? Зачем вам нужно сделать этот IRL?
  • 0
    Я бы использовал его для генерации строк во время сеанса грубой силы, если бы знал, что определенные символы или комбинации символов не будут использоваться.
Показать ещё 10 комментариев
Теги:
string
combinations

3 ответа

1
Лучший ответ

Здесь очень наивная реализация, просто удаление одного символа за раз и повторение нового списка значений. Это не очень эффективно по производительности, так как многие узлы несколько раз пересматриваются.

Рассмотрим, например, когда у нас есть две строки kirk и krik и удалите один i из обоих, в результате krik одна i та же строка. Это смягчается в решении с помощью HashSet, который будет отфильтровывать любые дубликаты на этом пути.

import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
public class HelloWorld {
  public static void main(String[] args) {
    String word = "kiraiki";
    Set<String> process = new HashSet<String>();
    System.out.println("Initial word: " + word);
    process.add(word);
    for (int i = 1; i < 4; ++i) {
      System.out.println("Removing " + i);
      Set<String> next = new HashSet<String>();
      for (String current : process) {
        List<String> result = removeOne(current, "i");
        for (String r : result) {
          next.add(r);
        }
      }
      for (String r : next) {
        System.out.println(r);
      }
      process = next;
    }
  }

  public static List<String> removeOne(String word, String c) {
    List<String> oneRemoved = new ArrayList<String>();
    String[] parts = word.split(c, -1);
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < parts.length-1; ++i){
      for (int j = 0; j < parts.length; ++j){
        String part = parts[j];
        builder.append(part);
        if (i != j){
          builder.append('i');
        }
      }
      oneRemoved.add(builder.substring(0, builder.length() - 1).toString());
      builder.setLength(0);
    }
    return oneRemoved;
  }
}

Возможно, это может дать вам несколько новых идей для лучшего решения.

  • 0
    Я добавил int numI = word.replace("i","").length(); после инициализации word и изменил оператор for на for (int i = 1; i <= numI; i++) чтобы программа for (int i = 1; i <= numI; i++) поддерживать слова с числом слов больше или меньше чем четыре. После этого это сработало хорошо. Я понимаю это на 100%. Само собой я заменил System.out.println(r); с resultList.add(r); после запуска ArrayList в другом месте. Он работает несколько медленно, но экспоненциально быстрее, чем просто перебор. Пока я не пойму другой 100%, я обязательно буду использовать этот. Спасибо за помощь!
2

Вы можете почти рассматривать это как переход от 0 to N (где N - общее количество вхождений символа, который вы ищете) в двоичном формате, например, от 00000 to 11111. То есть (2 ^ N) - 1 комбинации, поэтому поиск и замена грубой силы не будут работать так хорошо.

Хорошо, мы можем использовать это в наших интересах. Сначала сделаем массив со всеми местоположениями char, которые мы хотели бы удалить.

static List<Integer> location = new ArrayList<Integer>();
static String word = "kiraiki";
static String remove = "i";
int index = word.indexOf(remove);
while (index >= 0) {
    location.add(index);
    index = word.indexOf(remove, index + 1);
}

Теперь у нас есть N т.е. location.size(); места remove которые нам нужно заменить. Пропустите все двоичные комбинации от 0 to N и замените соответствующее местоположение char в location.get(i).

public static void binaryReplace(int value){
    for (int i = 0; i < Math.pow(2, value); i++) {

        StringBuilder binary = new StringBuilder(Integer.toBinaryString(i));
        // Add Leading '0's
        for(int j = binary.length(); j < value; j++) {
            binary.insert( 0, '0' );
        }

        // Create a temp with the original word. 
        StringBuilder tmp = new StringBuilder(word);
        // Look for where all the '1 (trues) are in the binary number 
        for (int k = -1; (k = binary.indexOf("1", k + 1)) != -1; ) {
            // I'm using spaces here so has to not have indexing issues with '' chars.
            tmp.setCharAt(location.get(k), ' ');
        }
        // Now let just replace these spaces so we can get the print out we want. 
        System.out.println(tmp.toString().replaceAll("\\s", ""));
    }
} 

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

  • 0
    дискретно Googles "StringBuilder" Ну, я бы не подумал об использовании двоичного кода для этого, хотя это имеет смысл. Я начинаю понимать код, хотя, и это хорошо ... Код работает, но в нем есть дубликаты, которые вы предсказали. Как начинающий Java-программист, единственная идея, которую я имею, состоит в том, чтобы проверить каждый результат по сравнению с другими до сих пор, но я знаю, что это замедлит программу таким образом. Это может быть то, что я должен вернуться с немного большим знанием ... или когда это не 1:00 утра. Я посмотрю, что предложил другой парень ... но это работает, так что большое спасибо!
0

Как насчет получения набора мощности буквы, которую вы хотите удалить, затем "маскировки" результатов. т.е. найти позицию всех я в String, затем сгенерировать набор мощности.

Например, при вводе "кики" мощность набора позиции я будет: {} {1} {3} {1,3}

так что маскировка результатов даст. {} = kiki {1} = k # ki {3} = kik # {1,3} = k # k #

т.е. kiki kki kik kk

    import java.util.*;
    import java.lang.Integer;

    public class Stack {    

        private static String input = "kiraiki";    

        public static void main(String[] args) {
            char[] original = input.toCharArray();      
            SortedSet<Integer> iPos = findI(original);
            Set<Set<Integer>> powerOfI = power(iPos);
            getResults(original, powerOfI);     
        }

        private static void getResults(char[] original, Set<Set<Integer>> powerOfI) {
            StringBuilder sb;
            char[] copyOfOriginal;
            for (Set<Integer> combinationOfI : powerOfI) {          
                sb = new StringBuilder();
                copyOfOriginal = Arrays.copyOf(original, original.length);          
                for (int posOfI : combinationOfI) {
                    copyOfOriginal[posOfI] = '#';               
                }           
                for (int i = 0; i < original.length; i++) {

                    if (copyOfOriginal[i] != '#') {
                        sb.append(copyOfOriginal[i]);
                    }               
                }
                System.out.println(sb.toString());          
            }
        }

        private static Set<Set<Integer>> power(SortedSet<Integer> setOfI) {             
            List<Integer> list = new ArrayList<Integer>(setOfI);
            int n = list.size();    
            Set<Set<Integer>> allTheI = new HashSet<Set<Integer>>();    
            for( long i = 0; i < (1 << n); i++) {
                Set<Integer> itemI = new HashSet<Integer>();
                for( int j = 0; j < n; j++ )
                    if( (i >> j) % 2 == 1 ) itemI.add(list.get(j));
                allTheI.add(itemI);
            }   
            return allTheI;
        }

        private static SortedSet<Integer> findI(char[] original) {
            SortedSet<Integer> iPos = new TreeSet<Integer>();
            for (int i = 0; i < original.length; i++) {
                if (original[i] == 'i') {
                    iPos.add(i);
                }
            }
            return iPos;
        }
    }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню