力扣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 小时前
PHP怎么使用Eloquent Attribute Synthesis属性合成_Laravel多源数据融合【指南】
jvm·数据库·python
m0_640309301 小时前
用Symfony构建AI驱动的Web应用实战
jvm·数据库·python
Warren981 小时前
Windows本地部署n8n完整教程(基于Docker,新手友好)
运维·windows·python·测试工具·docker·容器·可用性测试
星马梦缘1 小时前
强化学习实战-2——Keras-DoubleDQN解决Predator【图像输入】
人工智能·python·jupyter·cnn·keras·强化学习·dqn
石榴树下的七彩鱼1 小时前
身份证 OCR 识别 API 接入详解(Python / Java 示例)
java·开发语言·人工智能·后端·python·ocr·api
qq_206901391 小时前
CSS如何选择同级中的第一个元素_通过-first-child伪类实现
jvm·数据库·python
AI、少年郎1 小时前
MiniMind 第 4 篇:《数据工程|Tokenizer 训练 + 预训练 / SFT/DPO 全数据集处理》
人工智能·python·ai·大模型·微调·大模型训练·minimind
InfinteJustice2 小时前
mysql如何设计积分系统_mysql流水账与余额对账
jvm·数据库·python
NotFound4862 小时前
Golang怎么实现防重复提交_Golang如何用Token机制防止表单重复提交【技巧】
jvm·数据库·python
fly-iot2 小时前
TradingAgents 是一个模拟真实交易公司运作模式的多智能体交易框架,本地运行命令行工具,演示执行命令行模式,使用docker镜像打包
python·股票系统·tradingagents