递归单词搜索算法

发布于 2024-12-12 16:18:20 字数 2260 浏览 1 评论 0原文

现在是我为你祖母编写她的第一个 Java 单词搜索程序的时候了。但不是让她通过在字母网格中查找单词来完成所有工作,而是由递归函数 4WaySearch 为她完成所有工作!

唯一的问题是:

我发现很难概念化一种递归算法,该算法在从网格中的某个位置开始时构建每个可能的字母组合。

这是我已经编写的代码,我认为这是迈出的一大步正确的方向:

/* 
* This is the method that calls itself repeatedly to wander it's way
* through the grid using a 4 way pattern,
* creating every possibly letter combination and checking it against a
* dictionary. If the word is found in the dictionary, it gets added to a
* collection of found words.
* 
* Here an example of a 3x3 grid with the valid words of RATZ and BRATZ, but
* the word CATZ isn't valid. (the C is not tangent to the A).
* 
* CXY
* RAT
* BCZ
*
* @param row Current row position of cursor
* @param col Current column position of cursor
*/
private void 4WaySearch(int row, int col) {

    // is cursor outside grid boundaries?
    if (row < 0 || row > ROWS - 1 || col < 0 || col > COLS - 1)
        return; 

    GridEntry<Character> entry = getGridEntry(row, col);

    // has it been visited?
    if (entry.hasBreadCrumb())
        return; 

    // build current word
    currentWord += entry.getElement(); // returns character

    // if dictionay has the word add to found words list
    if (dictionary.contains(currentWord))
        foundWords.add(currentWord);

    // add a mark to know we visited
    entry.toggleCrumb();

    // THIS CANT BE RIGHT
    4WaySearch(row, col + 1);   // check right
    4WaySearch(row + 1, col);   // check bottom
    4WaySearch(row, col - 1);   // check left
    4WaySearch(row - 1, col);   // check top

    // unmark visited
    entry.toggleCrumb();

    // strip last character
    if (currentWord.length() != 0)
        currentWord = currentWord.substring(
        0, 
        (currentWord.length() > 1) ? 
            currentWord.length() - 1 : 
            currentWord.length()
        );
}

在我的脑海中,我将搜索算法可视化为递归树遍历算法,但每个节点(本例中的条目)都有 4 个子节点(切线条目),并且叶节点是网格的边界。

另外,初次进入函数时光标的位置是由此处伪编码的简单 for 循环确定的:

for (int r = 0; r < ROWS; r++)
  for (int c = 0; r < COLS; c++)
    4WaySearch(r,c);
  end for;
end for;

我已经考虑这个问题有一段时间了,并尝试不同的方法......但我似乎仍然无法集中精力围绕它并使其发挥作用。有人可以给我看光吗? (为了我和你的祖母!:D)

It's time for me to write your grandmother her first Java word search program. But instead of having her do all the work by looking for words within the letter grid, a recursive function 4WaySearch does it for her!

The only problem is:

I am finding it hard to conceptualize a recursive algorithm that builds every possible letter combination when starting at once place in the grid.

Here's code I already have written that I deem a big step in the right direction:

/* 
* This is the method that calls itself repeatedly to wander it's way
* through the grid using a 4 way pattern,
* creating every possibly letter combination and checking it against a
* dictionary. If the word is found in the dictionary, it gets added to a
* collection of found words.
* 
* Here an example of a 3x3 grid with the valid words of RATZ and BRATZ, but
* the word CATZ isn't valid. (the C is not tangent to the A).
* 
* CXY
* RAT
* BCZ
*
* @param row Current row position of cursor
* @param col Current column position of cursor
*/
private void 4WaySearch(int row, int col) {

    // is cursor outside grid boundaries?
    if (row < 0 || row > ROWS - 1 || col < 0 || col > COLS - 1)
        return; 

    GridEntry<Character> entry = getGridEntry(row, col);

    // has it been visited?
    if (entry.hasBreadCrumb())
        return; 

    // build current word
    currentWord += entry.getElement(); // returns character

    // if dictionay has the word add to found words list
    if (dictionary.contains(currentWord))
        foundWords.add(currentWord);

    // add a mark to know we visited
    entry.toggleCrumb();

    // THIS CANT BE RIGHT
    4WaySearch(row, col + 1);   // check right
    4WaySearch(row + 1, col);   // check bottom
    4WaySearch(row, col - 1);   // check left
    4WaySearch(row - 1, col);   // check top

    // unmark visited
    entry.toggleCrumb();

    // strip last character
    if (currentWord.length() != 0)
        currentWord = currentWord.substring(
        0, 
        (currentWord.length() > 1) ? 
            currentWord.length() - 1 : 
            currentWord.length()
        );
}

In my head, I visualize the search algorithm just like a recursive tree traveral algorithm, but each node (entry in this case) has 4 children (tangent entrys), and the leaf nodes are the boundaries of the grid.

Also, the location of the cursor upon initial entry into the function is determined by a simple for loop psuedocoded here:

for (int r = 0; r < ROWS; r++)
  for (int c = 0; r < COLS; c++)
    4WaySearch(r,c);
  end for;
end for;

I have been thinking about this for a while now, and trying different approaches... but I still cant seem to wrap my mind around it and make it work. Can someone show me the light? (For the sake of me and your grandmother! :D)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

岁月静好 2024-12-19 16:18:21

我要做的是建立一个树结构。节点的定义如下

public class Node {
    private String data;
    private int row,col;
    private Node parent;
    public Node(Node parent,int row,int col) {
        this.parent = parent;
        this.col = col;
        this.row = row;
    }
    public boolean hasParent(int row, int col) {
        Node current = this;
        while((current=current.parent)!=null) {
            if(current.row == row && current.col==col)
                return true;
        }
        return false;
    }

    public String toString() {
        Node current = this;
        StringBuffer sb = new StringBuffer();
        do {
            sb.append(current.data);
        }while((current = current.parent)!=null);
        return sb.reverse().toString();
    }
}

每次当你有一个新的起始位置时,你想要为树创建一个新的根节点

for (int r = 0; r < ROWS; r++)
  for (int c = 0; r < COLS; c++)
    4WaySearch(new Node(null,r,c);   //it is the root and has no parent
  end for;
end for;

然后你想要构建树

private void FourWaySearch(Node c) {
    if (c.row < 0 || c.row > ROWS - 1 || c.col < 0 || c.col > COLS - 1 || c.hasParent(c.row,c.col))
        return; 
    else {  

        c.data = grid[c.row][c.col];  //get the string value from the word search grid
        if(dictionary.contains(c.toString()))
            foundWords.add(c.toString());
        FourWaySearch(new Node(c,c.row-1,c.col));
        FourWaySearch(new Node(c,c.row,c.col-1));
        FourWaySearch(new Node(c,c.row+1,c.col));
        FourWaySearch(new Node(c,c.row,c.col+1));
    }
}

这可能不是最好的方法,但对我来说它看起来简单易懂。

What I would do is build a Tree structure. Where a Node is defined like so

public class Node {
    private String data;
    private int row,col;
    private Node parent;
    public Node(Node parent,int row,int col) {
        this.parent = parent;
        this.col = col;
        this.row = row;
    }
    public boolean hasParent(int row, int col) {
        Node current = this;
        while((current=current.parent)!=null) {
            if(current.row == row && current.col==col)
                return true;
        }
        return false;
    }

    public String toString() {
        Node current = this;
        StringBuffer sb = new StringBuffer();
        do {
            sb.append(current.data);
        }while((current = current.parent)!=null);
        return sb.reverse().toString();
    }
}

Each time you have a new starting place you want to create a new root node for the tree

for (int r = 0; r < ROWS; r++)
  for (int c = 0; r < COLS; c++)
    4WaySearch(new Node(null,r,c);   //it is the root and has no parent
  end for;
end for;

And then you want to build the tree as you go

private void FourWaySearch(Node c) {
    if (c.row < 0 || c.row > ROWS - 1 || c.col < 0 || c.col > COLS - 1 || c.hasParent(c.row,c.col))
        return; 
    else {  

        c.data = grid[c.row][c.col];  //get the string value from the word search grid
        if(dictionary.contains(c.toString()))
            foundWords.add(c.toString());
        FourWaySearch(new Node(c,c.row-1,c.col));
        FourWaySearch(new Node(c,c.row,c.col-1));
        FourWaySearch(new Node(c,c.row+1,c.col));
        FourWaySearch(new Node(c,c.row,c.col+1));
    }
}

This might not be the best way to do it but to me it seems simple and easy to follow.

桃气十足 2024-12-19 16:18:21

所以你需要做的就是首先建立网格。在本例中,您选择了 3x3 。您需要的是一种跟踪网格上所有有效点的方法,我可以推荐一个名为 Point 的对象,它采用两个 int 作为其构造函数。接下来您需要一个由 Pointchar 组成的类,这将使我们能够查看每个 Point 处可用的字母代码> .

现在我们已经有了数据结构,我们需要跟踪游戏的有效动作。例如,如果我位于位置 3,3(右下角,或者 2,2,如果你是零基础),我需要意识到我唯一有效的移动是向上或向左。确定这一点的方法是保留一个 SetPoint 来告诉我所有我访问过的地方,这将使递归算法终止。

一些可能有帮助的递归伪代码

if(!validMovesRemaining)  
     return
else  
    removeValidPosition(pointToRemove);  
    captureLetter(composedObject);
    recurse(pointsRemaining);

So what you need to do is first establish the grid. In this instance you have elected for 3x3 . What you need is a way to keep track of all the valid points on the grid, might I recommend an object called Point that takes two ints as its constructor. The next thing you need is a class that is composed of a Point and a char, this will enable us to see what letter is available at each Point .

Now that we have our data structure in place we need to keep track of valid moves for the game. For instance if I am at position 3,3 (the bottom right corner, or 2,2 if you are zero based) I would need to realize that the only valid moves I have are up or left. The way to determine this is to keep a Set of Points that tell me all the places I have visited, this will enable the recursive algorithm to terminate.

Some pseudocode for the recursion that may help

if(!validMovesRemaining)  
     return
else  
    removeValidPosition(pointToRemove);  
    captureLetter(composedObject);
    recurse(pointsRemaining);
狼亦尘 2024-12-19 16:18:21

我认为树是可行的方法,但与其他答案似乎使用它的方式不同。
我要做的是建立一个你正在寻找的单词的解析树(从字典中)——每个字母都是一个节点,有 26 个可能的子节点,每个字母对应一个字母表(检查 null 子元素递归之前),以及一个表示它是否是完整单词的标志。检查每个方向,看看你是否可以朝那个方向移动,并相应地移动。

我想说最困难的部分是构建树,它不应该递归地完成,但我只是有另一个想法。构建树的最佳方法也是递归。

这显然只是一个概述,但希望足以给您一个开始。如果您再次陷入困境,请发表评论,我会看看是否可以将您推向正确的方向。

I think a tree is the way to go, but not in the way other answers seem to be using it.
What I would do would be to build a parse tree of the words you're looking for (from the dictionary) -- each letter is a node, with 26 possible children, one for each letter of the alphabet (check for null children before recursing), and a flag saying whether it's a complete word. Check each direction, see if you can move in that direction, and move accordingly.

I was going to say that the hard part would be building the tree and it shouldn't be done recursively, but I just had another thought. The best way to build the tree is also recursive.

This is obviously just an overview, but hopefully enough to give you a start. If you get stuck again, comment and I'll see if I can push you more in the right direction.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文