【问题标题】:Recursive word search algorithm递归词搜索算法
【发布时间】:2011-10-27 05:54:41
【问题描述】:

现在是我为您祖母编写她的第一个 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)

【问题讨论】:

  • 为什么要递归做这个,作业?
  • 你说CATZ无效,为什么不能从最下面一行的C开始呢?那么它似乎是有效的。
  • @Kevin 是的,必须递归完成。
  • @MarkByers:我的错误,忽略底部的 C。将其替换为.... O
  • @ewok:是的,这是作业。不要误会我的意思...我不希望有人为我编写代码,我只是在寻找正确方向的推动力。

标签: java algorithm recursion wordsearch


【解决方案1】:

我要做的是构建一个树结构。像这样定义节点的地方

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));
    }
}

这可能不是最好的方法,但对我来说它似乎简单易行。

【讨论】:

  • 我实际上大部分程序都是这样实现的。但是,我们没有使用您的版本节点,而是提供了类似的东西,我们必须使用:Entry。入口不知道“孩子”(如果可能的话)入口就在他们旁边,他们只知道他们自己的性格。但是实现 4WaySearch 方法的类也有一个方法可以抓取网格上任意位置的条目:getGridEntry。我可以让所有这些东西正常工作......我只是不认为我们都以正确的方式递归地遍历网格(搜索顶部条目,然后搜索左、下、右)。
  • 这是遍历所有条目的正确方法。您必须遍历一棵树 (en.wikipedia.org/wiki/Tree_traversal#Sample_implementations),但每个条目都有 4 个孩子。
  • 是的。所以我原来的实现是正确的。我只是不确定它背后的概念。谢谢你帮我解决这个问题!
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    我认为一棵树是要走的路,但不是其他答案似乎使用它的方式。 我要做的是为您要查找的单词(来自字典)构建一个解析树——每个字母都是一个节点,有 26 个可能的子节点,每个字母对应一个(检查 null children before 递归),以及一个标志,说明它是否是一个完整的单词。检查每个方向,看看你是否可以朝那个方向移动,然后相应地移动。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-12
      • 2015-12-12
      • 2011-07-13
      • 1970-01-01
      • 1970-01-01
      • 2020-09-06
      • 1970-01-01
      相关资源
      最近更新 更多