269. Alien Dictionary

class Solution(object):
    def alienOrder(self, words):
        adj = { c:set() for w in words for c in w}

        prev = words[0]

        for i in range(1, len(words)):
            word1 = prev
            word2 = words[i]

            length = min(len(word1), len(word2))

            if len(word2) < len(word1) and word2[:length] == word1[:length]:
                return ""


            for j in range(length):
                if word1[j] != word2[j]:
                    adj[word1[j]].add(word2[j])
                    break

            prev = word2

        res = []
        visited = {}

        def dfs(src):
            if src in visited:
                return visited[src]

            visited[src] = True # inpath

            for node in adj[src]:
                if dfs(node):
                    return True
            
            visited[src] = False #visited
            res.append(src)

        for c in adj:
            if dfs(c): # if True, has loop
                return ""

        return "".join(reversed(res))