leetcode剑指offer II 114. 外星文字典 (构建有向图+有向图的拓扑排序)

题目描述:
现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。
给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。
请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 “” 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。
字符串 s 字典顺序小于 字符串 t 有两种情况:
1)在第一个不同字母处,如果 s 中的字母在这门外星语言的字母顺序中位于 t 中字母之前,那么 s 的字典顺序小于 t 。
2)如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 时,s 的字典顺序也小于 t 。
示例1:
输入:words = [“wrt”,“wrf”,“er”,“ett”,“rftt”]
输出:“wertf”
示例 2:
输入:words = [“z”,“x”]
输出:“zx”
示例 3:
输入:words = [“z”,“x”,“z”]
输出:“”
解释:不存在合法字母顺序,因此返回 “” 。
思路:
主要参照了官方题解
解本题的关键点:
1)分析怎样可以得到一个合法的顺序:对数组的单词每相邻的两个进行比较,第一个不一样的字母可以得到一个有效的顺序。
2)无法得到有效的顺序的两种情况:
a. 在输出所形成的有向图的时候有环,证明有关系是相互指的,无法得到一个整体的有效顺序。
b. 相邻两个单词满足后面的单词是前面的单词的前缀,且后面的单词的长度小于前面的单词的长度,例如words=[“ab",“a"]。
综上,本题的代码块大概可以分成两个部分,一个是利用数组中的单词生成有向图,一个是对有向图进行拓扑排序。
拓扑排序有深度优先和广度优先两种方式;
深度优先就是先遍历一条路径,为路径中的每一个结点标注一个状态,如果在路径中出现了重复的元素,则证明是有环的;
广度优先则是利用队列的方式,根据入度来进行排序输出,入度为0才可以输出,证明他之前的都已经输出,最终看得到的顺序长度是否与总长度相等,如果相等则得到一个有效的顺序。
下面是题解的截图:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

class Solution:
    def alienOrder(self, words: List[str]) -> str:
    	# 利用<字母,[]列表>来生成有向图
        g = {}
        for c in words[0]:
            g[c] = []
        for i in range(1, len(words)):
            s = words[i - 1]
            t = words[i]
            for c in t:
                g.setdefault(c, [])
            flag = False
            for u, v in zip(s, t):
                if u != v:
                    g[u].append(v)
                    flag = True
                    break
            if not flag:  # 一种无法得到合法的情况
                if len(s) > len(t):
                    return ""

        visiting, visited = 1, 2  # 用来标志状态
        states = {}
        stack = []
        def dfs(u: str)-> bool:
            states[u] = visiting
            for v in g[u]:
                if v not in states:
                    if not dfs(v):
                        return False
                elif states[v] == visiting:
                    return False
            states[u] = visited
            stack.append(u)
            return True
        res = []
        for q in g:
            if q not in states:  # 已经判断过的不能再执行了,否则会在stack中append两次
                res.append(dfs(q))
        return "".join(reversed(stack)) if all(res) else ""  # 这里reverse是因为在深度或者说递归的时候,后面的先加入进去了,是反的,所以输出的时候倒序输出

在这里插入图片描述
在这里插入图片描述

在这里插入代码片class Solution:
    def alienOrder(self, words: List[str]) -> str:
        g = {}
        number = {}  # 用来统计入度的数量
        for c in words[0]:
            g[c] = []
            number[c] = 0
        for i in range(1, len(words)):
            s = words[i-1]
            t = words[i]
            for c in t:
                g.setdefault(c, [])
                number.setdefault(c, 0)
            flag = False
            for u, v in zip(s, t):
                if u != v:
                    g[u].append(v)
                    number[v] += 1
                    flag = True
                    break
            if not flag:
                if len(s) > len(t):
                    return ""

        # 从入度的角度
        queue = []
        res = []
        for k in number:
            if number[k] == 0:
                queue.append(k)
        while queue:
            cur = queue.pop(0)
            res.append(cur)
            for q in g[cur]:
                number[q] -= 1
                if number[q] == 0:  # 只有入度为0才能加入到队列中,表明他之前的都已经输出了,如果有环的话是输出不来的
                    queue.append(q)
        if len(res) == len(g):
            return "".join(res)
        else:
            return ""
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值