Grind75第13天 | 208.实现Trie、54.螺旋矩阵、721.账户合并

本文介绍了如何实现Trie树的数据结构,包括TrieNode和Trie类的创建与操作,以及如何解决LeetCode中的螺旋矩阵打印问题和账户合并问题,利用并查集进行邮箱关系的合并。
摘要由CSDN通过智能技术生成

208.实现Trie

题目链接:https://leetcode.com/problems/implement-trie-prefix-tree

解法:

这个题非常经典,背下来。

首先需要自己实现Node的类,属性为children和是否为单词的标记,再去初始化Trie的类。

在插入和查询的过程中,都要不断让指针指向children。

参考题解:实现Trie

边界条件:无

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_word = False

class Trie:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, word: str) -> None:
        node = self.root
        for c in word:
            if c not in node.children:
                node.children[c] = TrieNode()
            node = node.children[c]
        node.is_word = True

    def search_prefix(self, word):
        node = self.root
        for c in word:
            if c not in node.children:
                return None
            node = node.children[c]
        return node

    def search(self, word: str) -> bool:
        node = self.search_prefix(word)
        return node is not None and node.is_word

    def startsWith(self, prefix: str) -> bool:
        node = self.search_prefix(prefix)
        return node is not None


# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)

54.螺旋矩阵

题目链接:https://leetcode.com/problems/spiral-matrix

解法:

顺时针打印矩阵的顺序是 “从左向右、从上向下、从右向左、从下向上” 循环。代码实现就是去模拟这个过程。

思路很直观,但是要处理好最后(最内部)的一个元素、一行或者一列,还是比较有讲究。如果循环时的边界处理不当,那么最内部的元素、一行或一列可能需要单独处理,这样就麻烦了。

按照以下的遍历顺序去处理,注意到从左到右和其他的三个方向不一样,从左到右把一行的所有元素都遍历了,而其他方向的遍历则少一个元素。这样却比较好处理最后的元素。

把代码运行一遍就理解了。

参考题解:螺旋矩阵

边界条件:

时间复杂度:O(mn),其中 m和 n分别是输入矩阵的行数和列数

空间复杂度:O(1)

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix: return []
        l, r, t, b = 0, len(matrix[0])-1, 0, len(matrix)-1
        res = []
        while True:
            for i in range(l, r+1):
                res.append(matrix[t][i])
                # t要马上加1,因为下面的遍历是从下一行开始的
            t += 1
            if t > b: break

            for i in range(t, b+1):
                res.append(matrix[i][r])
            r -= 1
            if l > r: break

            for i in range(r, l-1, -1):
                res.append(matrix[b][i])
            b -= 1
            if t > b:break

            for i in range(b, t-1, -1):
                res.append(matrix[i][l])
            l += 1
            if l > r:
                break

        return res

721.账户合并

题目链接:https://leetcode.com/problems/accounts-merge

解法:

并查集基础:图论——并查集(详细版)_哔哩哔哩_bilibili

并查集的代码是作为模板直接用的,有三个部分:初始化,查找父节点(寻根),合并。功能一般是用于查询两个节点是不是有相同的根(相同的集合中)。

一个容易理解的例子是:给出若干个pair对(张三和张五,李四和李六),pair对表示这俩人是亲戚关系,那么可以构建亲戚图谱(合并操作)。再给出一个pair对(张三和李六),问他们俩是不是亲戚(查询是否有相同的根)。

对于并查集的优化有路径压缩和按秩合并。路径压缩实现简单,这里只用了路径压缩。

具体实现直接看代码比较直观。

参考题解:并查集

边界条件:

时间复杂度:O(nlogn),其中 n是不同邮箱地址的数量,logn 是路径压缩的复杂度。另外对邮箱排序的复杂度也是O(nlogn)

空间复杂度:O(n)

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))

    def find(self, idx):
        # 查找idx的根节点
        if self.parent[idx] != idx:
            self.parent[idx] = self.find(self.parent[idx])
        return self.parent[idx]

    def union(self, idx1, idx2):
        # 找到idx1和idx2的根节点,然后合并
        root1 = self.find(idx1)
        root2 = self.find(idx2)
        self.parent[root1] = root2

class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        email_index = {}
        email_name = {}

        # 把email转化为idx,以便直接使用并查集的模板
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_index:
                    email_index[email] = len(email_index)
                    email_name[email] = name

        # 使用并查集合并邮箱
        uf = UnionFind(len(email_index))
        for account in accounts:
            first_idx = email_index[account[1]]
            for email in account[2:]:
                next_idx = email_index[email]
                uf.union(first_idx, next_idx)
            
        # 把作为根节点的邮箱所连接的所有邮箱收集起来(包含本身)
        idx_emails = defaultdict(list)
        for email, idx in email_index.items():
            root = uf.find(idx)
            idx_emails[root].append(email)

        # 添加name,获取结果
        res = []
        for emails in idx_emails.values():
            res.append([email_name[emails[0]]] + sorted(emails))
        return res
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值