Я немного новичок на 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(""));
}
}
Здесь очень наивная реализация, просто удаление одного символа за раз и повторение нового списка значений. Это не очень эффективно по производительности, так как многие узлы несколько раз пересматриваются.
Рассмотрим, например, когда у нас есть две строки 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;
}
}
Возможно, это может дать вам несколько новых идей для лучшего решения.
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%, я обязательно буду использовать этот. Спасибо за помощь!
Вы можете почти рассматривать это как переход от 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 может быть значительно улучшена (вы можете удалить несколько двоичных комбинаций, которые дают один и тот же результат, там много поиска и т.д.), Но это должно вас начать.
Как насчет получения набора мощности буквы, которую вы хотите удалить, затем "маскировки" результатов. т.е. найти позицию всех я в 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;
}
}