从2D字符数组中打印所有可能的单词

时间:2012-12-03 09:34:34

标签: arrays algorithm data-structures

最近偶然发现了这个面试问题,

给定一个二维字符数组和一个可以在O(1)时间内搜索单词的字典。需要打印字典中存在的数组中的所有单词。 Word可以在任何方向形成,但必须在数组的任何边缘结束。(不用担心字典)

输入:

a f h u n
e t a i r
a e g g o
t r m l p

输出:

after
hate
hair
air
eat
tea

注意:这里“egg”不是字典单词,因为它不在数组的边缘结束。

我以前见过类似的问题,但从来没有想过一个好的算法来解决这些问题。任何有关如何解决这些问题的帮助(从字符数组中形成单词)都将非常有用。

(我能想到的唯一方法是找到2D数组中所有可能的字符排列,并检查它是否在数组的边缘结束,并检查排列是否是O中字典中的有效字。 (1)时间)

4 个答案:

答案 0 :(得分:3)

将数组转换为图形,以便每个单元格[i,j] 与其4个邻居[i+1,j], [i-1,j], [i,j+1], [i,j-1]中的每一个共享一条边。 然后在每个数组边缘单元格运行DFS,并继续检查字典是否 相反的词就在其中。

答案 1 :(得分:2)

你没有提到关于一个角色只能使用一次的事情 - 所以没有这个限制是“我们能生成k(或更多)不同的词吗?”的问题。是不可判断 1

(对每个元素的“访问次数”进行约束,存在有限数量的可能性,并且声明和证明当然不成立。)

<强>证明:
众所周知,没有算法A可以决定终止算法B是否为true或更多不同的输入返回k。 (如果需要,将在以后寻找此声明的引用,暂时相信我)。

我们将展示给定一个算法A,说明是否有k个或更多生成的字 - 我们可以决定是否有k个或更多不同的输入产生“真” :

  1. 让(终止)算法决定是否有k或 更多生成的单词为M

  2. 不失一般性 - 假设二进制字母表(我们可以用它代表一切)。

  3. 让:

     array = 0 1 
             0 1
    

    请注意,我们可以在此阵列上行走时生成任何二进制字。

  4. 算法A:
    输入:算法B,自然数n
    输出:当且仅当算法B对n个或更多不同输入回答“真”时才为真。
    算法
    (1)使用B(word)作为黑匣子字典 - 如果答案为真,则word在字典中。
    (2)使用array作为数组。
    (3)运行M on(array,dictionary,n),并按照它回答。

    请注意,如果M回答为真 - >有n个或更多可接受的单词 - &gt;对于B,有n个或更多不同的输入产生true(字典的定义,因为我们可以用数组生成每个输入) - &gt;这个问题的答案是真的。
    (如果算法回答错误,则证据类似)。

    <强> QED

    <强>结论:
    如果我们可以重复一次数组中的一个字符(或者更确切地说 - 无限次数) - 那么如果没有关于字典的任何信息,问题就无法解决。


    (1)一个不可抗拒的问题是没有算法可以在100%的情况下正确回答TRUE / FALSE的问题 - 对于每种算法,在某些情况下算法将被“卡住”在无限的情况下循环(或给出错误的答案)。最常见的“不可判断的”问题是Halting Problem - 其中说 - 没有算法A可以采用任何算法B并在B停止某些输入时回答w

答案 2 :(得分:0)

我的解决方案是:

我想我有一个M * N数组,搜索单词没有限制。例如,'rood'和'door'是两个不同的单词,彼此相反。

从第一个字母开始(左上角)。在这种情况下,它是'a'。如果字典中有任何单词,则检查邻接(假设有以'ae'和'af'开头的单词)检查它们是否已经是单词,最后一个字母的索引是0还是M-1或N-1 。如果没有,请将它们添加到队列中以便稍后查看。轮流检查所有排队的子串,并通过对队列中的所有值进行处理来完成此阶段。然后检查第二个字母并继续到数组的最后一个成员。像这样,你将能够检查所有可能的单词。

它适用于我的一个问题,但我不确定你是否也在寻找复杂性。

答案 3 :(得分:0)

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

 /**
 * Given a 2-dimensional array of characters and a
 * dictionary in which a word can be searched in O(1) time.
 * Need to print all the words from array which are present
 * in dictionary. Word can be formed in any direction but
 * has to end at any edge of array.
 * (Need not worry much about the dictionary)
 */
public class DictionaryWord {
private static char[][] matrix = new char[][]{
        {'a', 'f', 'h', 'u', 'n'},
        {'e', 't', 'a', 'i', 'r'},
        {'a', 'e', 'g', 'g', 'o'},
        {'t', 'r', 'm', 'l', 'p'}
};
private static int dim_x = matrix.length;
private static int dim_y = matrix[matrix.length -1].length;
private static Set<String> wordSet = new HashSet<String>();

public static void main(String[] args) {
    //dictionary
    wordSet.add("after");
    wordSet.add("hate");
    wordSet.add("hair");
    wordSet.add("air");
    wordSet.add("eat");
    wordSet.add("tea");

    for (int x = 0; x < dim_x; x++) {
        for (int y = 0; y < dim_y; y++) {
            checkAndPrint(matrix[x][y] + "");
            int[][] visitedMap = new int[dim_x][dim_y];
            visitedMap[x][y] = 1;
            recursion(matrix[x][y] + "", visitedMap, x, y);
        }
    }
}

private static void checkAndPrint(String word) {
    if (wordSet.contains(word)) {
        System.out.println(word);
    }
}

private static void recursion(String word, int[][] visitedMap, int x, int y) {
    for (int i = Math.max(x - 1, 0); i < Math.min(x + 2, dim_x); i++) {
        for (int j = Math.max(y - 1, 0); j < Math.min(y + 2, dim_y); j++) {
            if (visitedMap[i][j] == 1) {
                continue;
            } else {
                int[][] newVisitedMap = new int[dim_x][dim_y];
                for (int p = 0; p < dim_x; p++) {
                    for (int q = 0; q < dim_y; q++) {
                       newVisitedMap[p][q] = visitedMap[p][q];
                    }
                }
                newVisitedMap[i][j] = 1;
                checkAndPrint(word + matrix[i][j]);
                recursion(word + matrix[i][j], newVisitedMap, i, j);
            }
        }
    }
}

}