力扣207.课程表、208.实现Trie(前缀树)

207.课程表

思路:

主要是要求构成有向无环图,详细的思路如参考链接的方法二所示,我把我理解了的代码都标注在了注释里,因为确实有点看不太懂,还要再消化一下。

复杂度分析:

  • 时间复杂度 O(N+M): 遍历一个图需要访问所有节点和所有临边,N 和 M 分别为节点数量和临边数量;
  • 空间复杂度 O(N+M): 为建立邻接表所需额外空间,adjacency 长度为 N ,并存储 M 条临边的数据。

参考:

https://leetcode.cn/problems/course-schedule/solutions/18806/course-schedule-tuo-bu-pai-xu-bfsdfsliang-chong-fa

代码:

python 复制代码
class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        # 参数:第i门课程;每门课程的所有前置课程构成邻接矩阵;标志位,用于记录该门课程是(1)否(0)被当前节点访问过以及是否被其他节点访问过(-1)
        def dfs(i, adjacency, flags):
            
            if flags[i] == -1: return True  # 说明当前访问节点已被其他节点启动的 DFS 访问,无需再重复搜索,直接返回 True
            if flags[i] == 1: return False  # 说明在本轮 DFS 搜索中节点 i 被第 2 次访问,即 课程安排图有环 ,直接返回 False
            
            flags[i] = 1  # 该轮此节点标为已访问
            
            # 对该节点的每一个邻接节点(前置课程)都验证是否满足无环的条件
            for j in adjacency[i]:
                if not dfs(j, adjacency, flags): return False
            
            # 都验证完确实无环之后,将标志设置为本轮该节点已访问,不影响之后判断
            flags[i] = -1
            return True

        # 初始化邻接矩阵和标志
        adjacency = [[] for _ in range(numCourses)]
        flags = [0 for _ in range(numCourses)]

        # cur为当前课程,pre为其前置课程,对应加入
        for cur, pre in prerequisites:
            adjacency[cur].append(pre)

        for i in range(numCourses):
            if not dfs(i, adjacency, flags): return False

        return True

208.实现Trie(前缀树)

思路:

1、由于一系列处理都是基于字符串的,所以可以把数据结构想象为一个26叉树,每一分支表示一个字母,各个节点有自己的子节点和是否字符串结束两个标志用以记录

2、搜索字符串和字符串前缀可用一个find函数来返回不同数值进行判断,其余的操作和二叉树类似,每处理完要向子节点移动等等,更具体的可以看代码注释

复杂度分析:

  • 时间复杂度:初始化为 O(1),insert 为 O(n∣Σ∣),其余为 O(n),其中 n 是 word 的长度,∣Σ∣=26 是字符集合的大小。注意创建一个节点需要 O(∣Σ∣) 的时间(如果用的是数组)。
  • 空间复杂度:O(qn∣Σ∣)。其中 q 是 insert 的调用次数。

参考:

https://leetcode.cn/problems/implement-trie-prefix-tree/solutions/2993894/cong-er-cha-shu-dao-er-shi-liu-cha-shu-p-xsj4

代码:

python 复制代码
class Node:
    __slots__ = 'son', 'end'  # 声明该类的实例将拥有的属性

    def __init__(self):
        self.son = {}  # 字典,存储该节点的子节点
        self.end = False  # 表示该节点是否是一个单词的结尾

# 当成一个26叉树来处理
class Trie:

    def __init__(self):
        self.root = Node()

    def insert(self, word: str) -> None:
        cur = self.root
        for c in word:
            # 若字符不在子节点中,就创建一个新节点
            if c not in cur.son:
                cur.son[c] = Node()
            cur = cur.son[c]  # 相当于往下一层遍历移动一个节点

        cur.end = True

    def find(self, word):
        cur = self.root
        for c in word:
            # 若字符不在子结点中,直接返回0值
            if c not in cur.son:
                return 0
            cur = cur.son[c]
        # 在原有的树中找到了和word相同的路径(2=完全匹配,1=前缀匹配)
        return 2 if cur.end else 1

    def search(self, word: str) -> bool:
        return self.find(word) == 2

    def startsWith(self, prefix: str) -> bool:
        return self.find(prefix) != 0
相关推荐
骇城迷影1 小时前
从零复现GPT-2 124M
人工智能·pytorch·python·gpt·深度学习
kronos.荒2 小时前
滑动窗口:寻找字符串中的字母异位词
开发语言·python
Full Stack Developme2 小时前
spring #{} 与 ${} 区别
windows·python·spring
马腾化云东2 小时前
Agent开发应知应会(Langfuse):Langfuse Session概念详解和实战应用
人工智能·python·llm
松涛和鸣2 小时前
75、 IMX6ULL LM75温度传感器I2C驱动开发
java·linux·数据库·驱动开发·python
甄心爱学习2 小时前
【python】list的底层实现
开发语言·python
熬了夜的程序员2 小时前
【LeetCode】119. 杨辉三角 II
算法·leetcode·职场和发展
edisao2 小时前
第三章 合规的自愿
jvm·数据仓库·python·神经网络·决策树·编辑器·动态规划
菜鸡儿齐2 小时前
leetcode-最长连续序列
数据结构·算法·leetcode