给定单词词典确定字母顺序

时间:2015-03-17 22:43:43

标签: python dictionary directed-acyclic-graphs topological-sort

确切的问题陈述是这样的:给定根据一些未知的字母排序排序的单词字典,确定字母的总顺序。保证所提供的任何输入都具有总订单并且可以找到订单。

从我读到的关于这类问题的内容来看,解决这个问题的正确方法似乎是建立一个有向无环图,然后在图上进行拓扑排序。此外,有两种方法可以实现拓扑排序(我知道)。其中一个使用深度优先搜索,这就是我选择实现算法的方式。

我的程序适用于提供的少量测试用例(以及我能提出的任何测试用例),但是用于验证程序正确性的测试用例失败了。不幸的是,我无法访问这些测试用例,或者我可以更轻松地调试我的程序。

有人愿意建议对我的代码进行一些改进吗?有没有其他方法来解决这个问题?此外,是否有人知道生成良好测试用例的方法?我提出的测试用例不足以找到我的程序不正确的地方。一个理想的测试用例是一个单词词典,保证总排序存在并且可以获得。

我认为问题在于我构建有向无环图的方式。

from sets import Set
from copy import copy

#Hash table representation of directed acyclic graph.
DAG = {}
#Set of all vertices with no incoming edges
noIncomingEdges = Set()
#Any array (initially empty) which will contain the total order
#of the letters used to sort the dictionary
sortedLetters = []

class VertexList:
    def __init__(self):
        self.outgoing = Set()
    def addOutgoingEdge(self, edge):
        self.outgoing.add(edge)
    def removeOutgoingEdge(self, edge):
        self.outgoing.remove(edge)

def buildDAG(words):
    numWords = len(words)
    for i in range(numWords - 1):
        #Get two consecutive words from the dictionary
        w1 = words[i]
        w2 = words[i + 1]
        lenw1 = len(w1)
        lenw2 = len(w2)
        #If the first word is longer than the second, pad the first words
        #by taking the last letter in the first words and appending it   until
        #both words are of equal length.
        #As an example:
        #       a       -->     aa
        #       ab      -->     ab
        #The algorithm for building the DAG should now be able to see that
        #a comes before b.
        if lenw1 < lenw2:
            while len(w1) < lenw2:
                w1 = w1 + w1[lenw1 - 1]
        n = lenw2
        for j in range(n):
            #If the DAG doesn't have a vertex for a given letter, add it.
            #Also, add it to the list of nodes with no incoming edges.
            if not DAG.has_key(w1[j]):
                DAG[w1[j]] = VertexList()
                noIncomingEdges.add(w1[j])
            if not DAG.has_key(w2[j]):
                DAG[w2[j]] = VertexList()
                noIncomingEdges.add(w2[j])
            #Compare corresponding letters in the two consecutive words. If
            #The letter in the first word is different from the letter in the
            #second word, create an edge between the vertex represent the letter
            #from the first word and the vertex for the letter in the second
            #word.
            if w1[j] != w2[j] and w2[j] not in DAG[w1[j]].outgoing:
                DAG[w1[j]].addOutgoingEdge(w2[j])
                #Remove the vertex for the second letter from the list of
                #vertices with no incoming edges.
                if w2[j] in noIncomingEdges:
                    noIncomingEdges.remove(w2[j])
                break

def visit(v):
    visited = Set()
    if v not in visited:
        visited.add(v)
        vertices = copy.deepcopy(DAG[v])
        for vertex in vertices.outgoing:
            visit(vertex)
        sortedLetters.insert(0, v)

def topologicalSort():
    for vertex in noIncomingEdges:
        visit(vertex)

def answer(words):
    buildDAG(words)
    topologicalSort()
    return ''.join(sortedLetters)

1 个答案:

答案 0 :(得分:0)

我发现了问题。它在行

if word1[j] != word2[j] and word2[j] not in DAG[word1[j]].outgoing:

你需要分开这些子句,因为当两个字母不同时你必须突破循环,即使DAG中的第二个字母。否则,当你应该比较这些词时,你会继续下一对字母。

结果是你在这对单词中得到了一个虚假的DAG边缘。我用

开始了我的数据集
a
ab
bad

第一次比较很顺利,向DAG添加了a-> b。 在第二次比较中, ab vs bad ,我们在第一个字母上找到了第一个差异。但是,由于b已经在a的传出列表中,因此您的逻辑表示继续执行下一个字母对。这会从第二个字母添加边b-> a。

这为DAG引入了一个循环,杀死了算法。代码应该是

if word1[j] != word2[j]:
    if word2[j] not in DAG[word1[j]].outgoing:
        <add edge>
    break