在二维char数组上查找单词

时间:2011-05-10 19:06:06

标签: java algorithm string

在这样的拼图中找到给定单词的简单方法是什么样的方法?我正在使用Java。谢谢你的帮助。

enter image description here

4 个答案:

答案 0 :(得分:3)

有趣的问题。我首先通过水平,垂直和对角(两个方向)遍历拼图来建立一个“可能的单词持有者”列表(可能包含一个给定单词的字符序列)来解决这个问题。然后我会在每个获得的“可能的单词持有者”中看到给定的单词(或它们的反向)是否存在(在Java中使用contains()方法)。这是我用Java编写的代码。我没有正确测试它,但我猜它有效!

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class WordPuzzle {

    public Set<String> findWords(char[][] puzzle, Set<String> words) {
        Set<String> foundWords = new HashSet<String>();
        int minimumWordLength = findMinimumWordLength(words);
        Set<String> possibleWords = findPossibleWords(puzzle, minimumWordLength);
        for(String word : words) {
            for(String possibleWord : possibleWords) {
                if(possibleWord.contains(word) || possibleWord.contains(new StringBuffer(word).reverse())) {
                    foundWords.add(word);
                    break;
                }
            }
        }       
        return foundWords;
    }

    private int findMinimumWordLength(Set<String> words) {
        int minimumLength = Integer.MAX_VALUE;
        for(String word : words) {
            if(word.length() < minimumLength)
                minimumLength = word.length();
        }
        return minimumLength;
    }

    private Set<String> findPossibleWords(char[][] puzzle, int minimumWordLength) {
        Set<String> possibleWords = new LinkedHashSet<String>();
        int dimension = puzzle.length; //Assuming puzzle is square
        if(dimension >= minimumWordLength) {
            /* Every row in the puzzle is added as a possible word holder */
            for(int i = 0; i < dimension; i++) {
                if(puzzle[i].length >= minimumWordLength) {
                    possibleWords.add(new String(puzzle[i]));
                }
            }
            /* Every column in the puzzle is added as a possible word holder */
            for(int i = 0; i < dimension; i++) {
                StringBuffer temp = new StringBuffer();
                for(int j = 0; j < dimension; j++) {
                    temp = temp.append(puzzle[j][i]);
                }
                possibleWords.add(new String(temp));
            }
            /* Adding principle diagonal word holders */
            StringBuffer temp1 = new StringBuffer();
            StringBuffer temp2 = new StringBuffer();
            for(int i = 0; i < dimension; i++) {
                temp1 = temp1.append(puzzle[i][i]);
                temp2 = temp2.append(puzzle[i][dimension - i - 1]);
            }
            possibleWords.add(new String(temp1));
            possibleWords.add(new String(temp2));
            /* Adding non-principle diagonal word holders */
            for(int i = 1; i < dimension - minimumWordLength; i++) {
                temp1 = new StringBuffer();
                temp2 = new StringBuffer();
                StringBuffer temp3 = new StringBuffer();
                StringBuffer temp4 = new StringBuffer();
                for(int j = i, k = 0; j < dimension && k < dimension; j++, k++) {
                    temp1 = temp1.append(puzzle[j][k]);
                    temp2 = temp2.append(puzzle[k][j]);
                    temp3 = temp3.append(puzzle[dimension - j - 1][k]);
                    temp4 = temp4.append(puzzle[dimension - k - 1][j]);
                }
                possibleWords.add(new String(temp1));
                possibleWords.add(new String(temp2));
                possibleWords.add(new String(temp3));
                possibleWords.add(new String(temp4));
            }
        }
        return possibleWords;
    }

    public static void main(String args[]) {
        WordPuzzle program = new WordPuzzle();
        char[][] puzzle = { 
                            {'F','Y','Y','H','N','R','D'},
                            {'R','L','J','C','I','N','U'},
                            {'A','A','W','A','A','H','R'},
                            {'N','T','K','L','P','N','E'},
                            {'C','I','L','F','S','A','P'},
                            {'E','O','G','O','T','P','N'},
                            {'H','P','O','L','A','N','D'}
                          };
        Set<String> words = new HashSet<String>();
        words.add("FRANCE");
        words.add("POLAND");
        words.add("INDIA");
        words.add("JAPAN");
        words.add("USA");
        words.add("HOLLAND");
        Set<String> wordsFound = program.findWords(puzzle, words);
        for(String word : wordsFound) {
            System.out.println(word);
        }
    }
}

答案 1 :(得分:1)

总的来说,我说使用最天真的方法,除非你的谜题会很大。我不会优化任何小于0.1秒的东西,但那只是我。

foreach box
    for all directions
        grab the string of characters in that direction
        lookup a dictionary

我认为智能可以在你设计字典的方式上。在这种情况下,我会做一个多级哈希表,其中字符选择哪个哈希表来查看下一级别。

答案 2 :(得分:0)

我会将单词列表放入Trie,然后从各个方向的所有正方形进行搜索。

答案 3 :(得分:0)

最简单的方法(conceptualy)是简单地枚举数组中所有可能的单词,然后在一个字典中检查所有单词。一个字典恐惧地图,一串字符串......或从互联网上下载的真实字典。

这里的例子是水平查找所有可能的单词的代码...添加其他方向只是更多的工作:

import java.util.HashSet;
import java.util.Set;

public class WordFinder {

  public static void main(String[] args) {

    String[][] words = { { "F", "Y", "Y", "H", "N", "R", "D" }, 
                         { "R", "L", "J", "C", "I", "N", "U" },
                         ...};
    Set<String> dictionnary = new HashSet<String>();
    dictionnary.add(...);

    Set<String> wordsFound = findWords(words, dictionnary);
    ...
  }

  /**
   * Find all words in the specified array present in the dictionnary.
   * 
   */
  private static Set<String> findWords(String[][] words, Set<String> dictionnary) {
    Set<String> wordsFound = new HashSet<String>();

    // Find all possible words horizontally :
    int nbrRows = words.length;
    int nbrCol = words[0].length; // We suppose we have at least one row and all row have same lengh

    // Iterate through all rows
    for (int currentRow = 0; currentRow < nbrRows; currentRow++) {
      // Iterate through all possible starting position in the current row.
      for (int beginWordIndex = 0; beginWordIndex < nbrCol; beginWordIndex++) {
        // Iterate then through all possible ending positions in the current row, so to deal with word of any lengh.
        for (int endWordIndex = beginWordIndex; endWordIndex < nbrCol; endWordIndex++) {
          // Construct a word from the begin/end indexes :
          String currentWord = getWordInRow(words, currentRow, beginWordIndex, endWordIndex);

          // Check if the word candidate really exist, if yes, store it in the wordsFound variable.
          if (dictionnary.contains(currentWord)) {
            wordsFound.add(currentWord);
          }

          // The reverse
          String reverseWord = reverseString(currentWord);
          // Check if the reverse word really exist, if yes, store it in the wordsFound variable.
          if (dictionnary.contains(reverseWord)) {
            wordsFound.add(currentWord);
          }

        }
      }
    }

    // Don't forget vertically and in diagonals too... Same principe.

    return wordsFound;
  }

  /**
   * Return a word "candidate" in the specified row, starting at beginIndex and finishing at endIndex.
   */
  private static String getWordInRow(String[][] words, int row, int beginIndex, int endIndex) {
    String currentWord = "";
    int currentPosition = beginIndex;
    while (currentPosition <= endIndex) {
      currentWord += words[row][currentPosition];
    }
    return currentWord;
  }

  /**
   * Return the reverse of a String
   */
  private static String reverseString(String string) {
    String result = "";
    for (int i = string.length()-1; i >=0;i++) {
      result+= string.charAt(i);
    }
    return result;
  }

}

这不是最好,最有效的解决方案。但它在概念上很简单。

编辑:

逆序:查看已编辑的代码。只需编写一个可以反转单词的函数。因为我们已经按正常顺序排列了所有可能的单词,所以反转它们就足以让单词按相反的顺序排列。

对角线:如果你已经理解了我已经提到的代码,我相信你能做到。我不会做你的功课或代替你做你的测试。尝试用纸和笔来计算你将如何做到这一点。如果你不得不手工完成,你会怎么做?然后,写下你的解决方案;)