/** * 2018/2019 Regional ICPC * Problem ? * Lost is Close to Lose * * @author M. K. Furon * @version 1.0 * @since 2018-10-29 */ import java.io.*; import java.util.*; class Wordrecord implements Comparable { // Class for the words in the corpus, sorted first by length, then // alphabetically. String word; int wordlength; Wordrecord (String inputword) { word = inputword; wordlength = inputword.length (); } public int compareTo (Wordrecord secondword) { if (this.wordlength != secondword.wordlength) return (this.wordlength - secondword.wordlength); else return ((this.word).compareTo (secondword.word)); } } class closetolose { static int difference, i; static boolean added; static char swap; static char checker[], eachletter[], letter[]; static String highstring, lineimage, lowstring; static StringBuffer sbdel; static String tokens[]; static Wordrecord highbound, lowbound, teststring, wordcheck; static TreeSet wordset; static NavigableSet samelength; static Map> results; static void addpair (String worda, String wordb) { // Add the words provided as arguments as words that are "close" to // each other. TreeSet resultset; resultset = results.get (worda); if (resultset == null) resultset = new TreeSet (); resultset.add (wordb); results.put (worda, resultset); resultset = results.get (wordb); if (resultset == null) resultset = new TreeSet (); resultset.add (worda); results.put (wordb, resultset); } public static void main (String args[]) throws IOException { BufferedReader stdin = new BufferedReader (new InputStreamReader (System.in)); // Crack each input line into its component words, stripping out // non-alphabetic characters and converting upper-case to lower- // case. wordset = new TreeSet (); while ((lineimage = stdin.readLine ()) != null) { tokens = (lineimage.trim ()).split ("\\s+"); for (String token: tokens) { token = (token.replaceAll ("[^a-zA-Z]", "")).toLowerCase (); if (token.length () > 0) // If valid word exists added = wordset.add (new Wordrecord (token)); } } // We now have a set of all the unique words in the text, sorted // first by length and then alphabetically. We can process this in // inverse order to check for character insertions and deletions-- // a deletion in inverse order is an insertion the other way. results = new TreeMap> (); Iterator iter = wordset.descendingIterator (); while (iter.hasNext ()) { wordcheck = iter.next (); // Transpositions. For a N-letter word, there will be N - 1 // possible transpositions. Look them up. for (i = 0; i < ((wordcheck.word).length () - 1); i++) { checker = (wordcheck.word).toCharArray (); if (checker[i] == checker[(i + 1)]) // If letters are the same continue; swap = checker[i]; checker[i] = checker[(i + 1)]; checker[(i + 1)] = swap; teststring = new Wordrecord (new String (checker)); if (wordset.contains (teststring)) addpair (wordcheck.word, teststring.word); } // Deletions. Since we are working backwards, this will also // take care of insertions for the word that is found. for (i = 0; i < (wordcheck.word).length (); i++) { sbdel = new StringBuffer (wordcheck.word); sbdel.deleteCharAt (i); teststring = new Wordrecord (sbdel.toString ()); if (wordset.contains (teststring)) addpair (wordcheck.word, teststring.word); } // Substitutions. Check words that are the same length to see // if they differ by exactly one character. // Start by extracting the words that are the same length as the // word in question. samelength = new TreeSet (); letter = new char[wordcheck.wordlength]; eachletter = new char[wordcheck.wordlength]; Arrays.fill (letter, 'a'); lowstring = new String (letter); Arrays.fill (letter, 'z'); highstring = new String (letter); lowbound = new Wordrecord (lowstring); highbound = new Wordrecord (highstring); samelength = wordset.subSet (lowbound, true, highbound, true); // Iterate over all the words of the same length to determine // if they differ by a single character. letter = (wordcheck.word).toCharArray (); for (Wordrecord eachword: samelength) { difference = 0; eachletter = (eachword.word).toCharArray (); for (i = 0; i < wordcheck.wordlength; i++) if (letter[i] != eachletter[i]) difference++; if (difference == 1) addpair (wordcheck.word, eachword.word); } } // The map has the results. Fetch the keys in alphabetical order, // then fetch the map contents in alphabetical order. for (Map.Entry> entry: results.entrySet ()) { System.out.print (entry.getKey ()); System.out.print (":"); for (String answerword: entry.getValue ()) { System.out.print (" "); System.out.print (answerword); } System.out.println (""); } if (results.isEmpty()) { System.out.println ("***"); } return; } }