Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 列出拼图中所有单词的最快算法_Algorithm_Search - Fatal编程技术网

Algorithm 列出拼图中所有单词的最快算法

Algorithm 列出拼图中所有单词的最快算法,algorithm,search,Algorithm,Search,我在一次采访中被问到这个问题,我对最佳答案很好奇。问题是这样的:给你一个n x n的板,上面写满了字母。一个游戏算法想要找到并列出这个棋盘上所有可能的单词,其中“单词”被定义为至少由3个字母组成的字符串,水平或垂直。最省时的方法是什么 这个问题中的“单词”不需要是字典中的真实单词。关键是尽可能快地找到所有长度可接受的字符串。我想不出任何其他的方法,除了野蛮的强制方法,它遍历电路板上的所有空间,并在该空间中找到所有以字母开头的字符串,这需要O(n^3)时间。你们会怎么做 我看到这个问题被否决了,因

我在一次采访中被问到这个问题,我对最佳答案很好奇。问题是这样的:给你一个n x n的板,上面写满了字母。一个游戏算法想要找到并列出这个棋盘上所有可能的单词,其中“单词”被定义为至少由3个字母组成的字符串,水平或垂直。最省时的方法是什么

这个问题中的“单词”不需要是字典中的真实单词。关键是尽可能快地找到所有长度可接受的字符串。我想不出任何其他的方法,除了野蛮的强制方法,它遍历电路板上的所有空间,并在该空间中找到所有以字母开头的字符串,这需要O(n^3)时间。你们会怎么做

我看到这个问题被否决了,因为人们认为没有更好的解决方案。然而,这是一个微软的面试问题,我的面试官明确地告诉我,我的答案不是最优的。

m(x)=max{0,x}
。如果我们使用基于0的索引,则

s(x,y) = m(x-1) + m(n-x-2) + m(y-1) + m(n-y-2)
2*n*(n-1)*(n-2)
从位置
(x,y)
开始的单词。在水平方向上,左边是以列
0,1,…,y-2结尾的,右边是以列
x+2,x+3,…,n-1结尾的。垂直词也类似

因此,在每个位置上,从
2*(n-3)
2*(n-2)
单词(包括)之间开始

更准确地说,在位置
(x,y)
,当且仅当
y=0
y=n-1
,否则
n-3
字开始出现
n-2
水平字。这使得
2*(n-2)+(n-2)*(n-3)=(n-1)*(n-2)
每行水平单词。每列的垂直字数是相同的,因此总共有

s(x,y) = m(x-1) + m(n-x-2) + m(y-1) + m(n-y-2)
2*n*(n-1)*(n-2)
网格中不一定有不同的单词。假设字母表不太小,重复的比例平均不太大,因此不可能有一个复杂度低于
O(n³)
的算法

如果不考虑重复,就这样,只剩下遍历数组的低级变化


如果应该删除重复项,并且目标是尽可能高效地列出所有不同的单词,那么问题是什么样的数据结构允许尽可能高效地删除重复项。我不能回答这个问题,但我认为trie在这方面相当有效。

这里有两个问题-一个:原始的解决方案暴力不是
O(n^3)
,而是
O(n^4)

假设您将每个子字符串复制到列表中的一个新条目。你有
O(n^3)
单词。但是,每个子字符串本身都是
O(n)
(平均而言),因此将所有这些子字符串复制到列表实际上是
O(n^4)

二:
更有效的解决方案是维护数据结构,并使用类似DFS的遍历从矩阵中的每个索引(从右到下)填充数据结构

这将产生
O(n^3)
解决方案,用
O(n^3)
单词填充trie。

你为什么说
O(n^3)
?电路板是正方形的,正方形是
O(n^2)

代码如下:

for(int col=0; col<n-2; ++col) {
    for(int row=0; row<n-2; ++row) {
        // for given (row,col)
        // yield word to right
        // yield word down
        // yield word down-right
    }
}
输出

LWIDM OWWGR APVOM GKECL TXCPD 0: LWI 1: LOA 2: LWV 3: WID 4: WWP 5: WWO 6: IDM 7: IWV 8: IGM 9: OWW 10: OAG 11: OPE 12: WWG 13: WPK 14: WVC 15: WGR 16: WVE 17: WOL 18: APV 19: AGT 20: AKC 21: PVO 22: PKX 23: PEP 24: VOM 25: VEC 26: VCD LWIDM OWWGR 阿普沃姆 GKECL TXCPD 0:LWI 1:LOA 2:LWV 3:WID 第4章:世界自然保护计划 5:WWO 6:IDM 7:IWV 8:IGM 9:OWW 10:OAG 11:OPE 12:WWG 13:WPK 14:WVC 15:WGR 16:WVE 17:WOL 18:APV 19:AGT 20:AKC 21:PVO 22:PKX 23:PEP 24:VOM 25:VEC 26:VCD
结果数为27=3*(5-2)^2

以下是我分阶段解决问题的方法:

  • 尝试在拼图中查找给定的单词:您可以使用DFS在拼图中查找单词。这将是O(n^2),因为我们必须遍历每一行和每一列字符

  • 在一个拼图中找出所有给定的单词:如果有x个给定的单词,你可以对每个单词使用上面的算法。复杂度为O(x*n^2)

  • 如果有相同前缀的单词,那么我们将重复搜索前缀所做的工作。这可以通过为给定的单词构建一个Trie结构并将Trie的DFS与拼图的DFS相结合来避免

  • 下面是C++中第一步的大致实现:

    bool FindWordInPuzzle(int i, int j, char nextChar, int nextCharId, string word, int m, int n, bool **mark, char **maze)
    {
        int move[8][2] = { 0, -1, -1, -1, -1, 0, -1, 1, 0, 1, 1, 1, 1, 0, 1, -1 };
        mark[i][j] = 1;
    
        for (int r = 0; r < 8; r++) {
            int g = i + move[r][0];
            int h = j + move[r][1];
    
            if (g > 0 && g < m + 2 && h > 0 && h < m + 2 && mark[g][h] == 0 && maze[g][h] == nextChar) {
                nextCharId++;
    
                if (nextCharId >= word.length()) {
                    return true;
                }
    
                if (FindWordInPuzzle(g, h, word[nextCharId], nextCharId, word, m, n, mark, maze)) {
                    return true;
                }
            }
        }
    
        return false;
    }
    
    bool FindWord(char **maze, bool **mark, int m, int n, string word) {
        char currentChar = word[0];
        int currentCharId = 0;
        for (int row = 1; row < m + 2; row++) {
            for (int col = 1; col < n+2; col++) {
                if (maze[row][col] == currentChar && mark[row][col] == 0) {
                    currentCharId++;
                    if (currentCharId >= word.length()) {
                        return true;
                    }
    
                    if (FindWordInPuzzle(row, col, word[currentCharId], currentCharId, word, m, n, mark, maze)) {
                        return true;
                    }
                }
    
                currentCharId = 0;
                currentChar = word[0];
            }
        }
    
        return false;
    }
    
    int main() {
        string word;
        int m, n;
    
        cin >> word;
        if (word.length() <= 0) return 0;
    
        cin >> m >> n;
        char** maze;
        bool **mark;
    
        // declare arrays
        maze = new char*[m + 2];
        mark = new bool*[m + 2];
        for (int i = 0; i < m + 2; i++) {
            maze[i] = new char[n + 2];
            mark[i] = new bool[n + 2];
        }
    
        // boundaries
        for (int i = 0; i < m + 2; i++) {
            maze[0][i] = ' ';
                maze[i][0] = ' ';
            maze[0][m + 1] = ' ';
            maze[i][m + 1] = ' ';
    
            mark[0][i] = 1;
            mark[i][0] = 1;
            mark[0][m + 1] = 1;
                mark[i][m + 1] = 1;
    
        }
    
        // get values
        for (int i = 1; i < m + 1; i++) {
            for (int j = 1; j < n + 1; j++) {
                cin >> maze[i][j];
                mark[i][j] = 0;
            }
        }
    
        bool val =  FindWord(maze, mark, m, n, word);
        cout << val;
        cin >> word;
    
        return 0;
    }
    
    bool FindWordInPuzzle(int i,int j,char nextChar,int nextCharId,string word,int m,int n,bool**mark,char**maze)
    {
    int move[8][2]={0,-1,-1,-1,0,-1,1,0,1,1,1,1,0,1,-1};
    标记[i][j]=1;
    对于(int r=0;r<8;r++){
    int g=i+move[r][0];
    int h=j+move[r][1];
    如果(g>0&&g0&&h=word.length()){
    返回true;
    }
    if(FindWordInPuzzle(g,h,word[nextCharId],nextCharId,word,m,n,mark,maze)){
    返回true;
    }
    }
    }
    返回false;
    }
    布尔FindWord(字符**迷宫,布尔**标记,整数m,整数n,字符串字){
    char currentChar=字[0];
    int currentCharId=0;
    对于(int行=1;行=word.length()){
    返回true;
    }
    if(FindWordInPuzzle(行、列、字[currentCharId]、currentCharId、字、m、n、标记、迷宫)){
    返回true;
    }
    }
    currentCharId=0;
    currentChar=字[0];
    }
    }
    返回false;
    }
    int main(){
    字符串字;
    int m,n;
    cin>>单词;
    if(word.length()>m>>n;
    字符**迷宫;
    布尔**马克;
    //声明数组
    迷宫=新字符*[m+2];
    马克=新布尔值*[m+2];
    对于(int i=0;i