单词转换通过一次更改1个字母的bug

时间:2015-02-25 13:14:06

标签: java breadth-first-search

我编写了一个程序,通过一次更改单个字符来显示单词是否可以转换为另一个单词,而中间单词也是有效单词。

例如CAT-> COT-> DOT-> DOC

当我使用LinkedHashSet来表示顶点时,程序可以正常工作 但是当我使用HashSet时,它会进入一个无限循环或错误的答案。

我想知道问题是什么,如果有更好的方法可以解决问题,请告诉我。

以下是代码:拆分为3个文件: Graph.java

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

public class Graph {

    private Set<GraphNode> vertices;

    public Graph() {
        //the code runs when I use LinkedHashSet
        vertices = new LinkedHashSet<>();
        //the code goes into infinite loop or wrong answer when I use HashSet to represent the vertices
        //************

        //vertices = new HashSet<>();

        //*************
        //^^^^^ strange behaviour
    }

    /**
     * adds all the words from the given dictonary to the graph
     * @param dictonary
     * @return
     */
    public boolean addAll(Set<String> dictonary){
        boolean result= false;

        for (String word : dictonary){
            addNode(word);
        }
        return result;
    }

    /**
     * add a single node into the graph
     * @param data
     * @return
     */
    public GraphNode addNode(String data){
        GraphNode node = new GraphNode();
        node.setValue(data);
        vertices.add(node);
        return node;
    }

    /**
     * add a neighbour to the "source" node
     * @param source
     * @param neighbour
     * @return
     */
    public boolean addNeighbour(GraphNode source, GraphNode neighbour) {
        boolean result = false;
        source.getNeighbours().add(neighbour);
        return result;
    }

    /**
     * This method assigns the neighbours of nodes depending on whether they are one edit
     * away or not
     */
    public void assignNeighbours(){

        ArrayList<GraphNode> listOfNodes = getAllVertices();

        Set<String> usedWords = new HashSet<>();
        for ( int i=0 ;i <listOfNodes.size() ;i++){
            String currentWord = listOfNodes.get(i).value;
            for (int j=0 ; j < listOfNodes.size() ;j++ ){
                if (currentWord.equals(listOfNodes.get(j).value)==false){
                    if (oneEditAway(currentWord, listOfNodes.get(j).value) && usedWords.contains(listOfNodes.get(j).value)==false){
                        listOfNodes.get(i).neighbours.add(listOfNodes.get(j));
                        //reflective 
                        listOfNodes.get(j).neighbours.add(listOfNodes.get(i));
                        usedWords.add(listOfNodes.get(j).value);
                    }
                }
            }
        }
    }

    public ArrayList<GraphNode> getAllVertices(){
        return new ArrayList<>(vertices);
    }

    /**
     * This method determines whether 2 strings are one edit away or not
     * @param first
     * @param second
     * @return
     */
    public  boolean oneEditAway(String first, String second) {
        // TODO Auto-generated method stub
        if (first == null || second == null)
            return false;
        if (Math.abs(first.length() - second.length())>1){
            return false;
        }else{
            int firstLength = first.length();
            int secondLength = second.length();
            int mismatchCount = 0;
            for (int i=0 ;i < firstLength && i < secondLength ; ++i){
                if (first.charAt(i) != second.charAt(i)){
                    mismatchCount++;
                }
            }
            if (mismatchCount > 1 || Math.abs(firstLength - secondLength) == 1){
                return false;
            }
            return true;
        }
    }

    /**
     * This method prints the graph and the connections
     */
    public void printGraph() {
        // TODO Auto-generated method stub
        for (GraphNode node :vertices){
            System.out.println("Node is :"+node.value);
            System.out.println("Neighbours are :");
            for (GraphNode graphNode : node.getNeighbours()){
                System.out.print(graphNode.value+ " ");
            }
            System.out.println();
        }
    }

    /**
     * This function determines whether a word can be transformed into an another or not
     * @param source
     * @param dest
     * @return
     */
    public boolean canTransform(String source, String dest) {
        boolean result = false;


        Set<GraphNode> visited = new HashSet<>();

        //BFS is the way to go
        Queue<GraphNode> allNodes = new LinkedList<>();
        GraphNode root=null;
        //find the source node in the graph
        for (GraphNode node : vertices){
            if (node.value.equals(source)){
                root = node;
            }
        }
        allNodes.add(root);
        System.out.println("***************");
        while(!allNodes.isEmpty()){

            GraphNode currentNode = allNodes.poll();

            System.out.println(currentNode.value);
            visited.add(currentNode);
            if (currentNode.value.equals(dest)){
                result = true;
                break;
            }
            for (GraphNode node: currentNode.getNeighbours()){
                if (visited.contains(node) == false){
                    allNodes.add(node);
                }
            }
        }
        return result;
    }

    @Override
    public String toString() {
        return "Graph  is as follows :\nvertices=" + vertices + "";
    }

    public Set<GraphNode> getVertices() {
        return vertices;
    }
    public void setVertices(Set<GraphNode> vertices) {
        this.vertices = vertices;
    }
    }

这是GraphNode.java

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

public class GraphNode {

    String value;

    Set<GraphNode> neighbours =  new HashSet<GraphNode>();

    public GraphNode() {
        // TODO Auto-generated constructor stub
    }

    public GraphNode(String value) {
        super();
        this.value = value;
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        GraphNode other = (GraphNode) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "GraphNode [value=" + value + ", neighbours=" + neighbours + "]";
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Set<GraphNode> getNeighbours() {
        return neighbours;
    }

    public void setNeighbours(Set<GraphNode> neighbours) {
        this.neighbours = neighbours;
    }

}

这是驱动程序类:

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

public class GraphMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Graph graph = new Graph();
        Set<String> dict = new HashSet<>();
        dict.add("CAT");
        dict.add("COT");
        dict.add("DOT");
        dict.add("DOG");
        dict.add("DOC");
        graph.addAll(dict);
        graph.assignNeighbours();
        graph.printGraph();
        String source="CAT",dest = "DOC";
        System.out.println("can transform from "+source+" to "+dest+" ??"+graph.canTransform(source,dest));
    }
}

1 个答案:

答案 0 :(得分:0)

确定单词邻居的方法不正确,因为Set usedWords的使用不正确。关系neighbour(w1,w2)必须独立于确定邻居的顺序,因此使用某种状态来判断一个单词是否是另一个单词的邻居是不正确的。

public void assignNeighbours(){
    for ( GraphNode w1: vertices ){
        for ( GraphNode w2: vertices ){
            if (! w1.equals(w2) ){
                if (oneEditAway(w1.getValue(), w2.getValue())){
                    w1.neighbours.add(w2);
                    //reflective 
                    w2.neighbours.add(w1);
                }
            }
        }
    }
}