Leetcode 721 账户合并

news2025/1/16 11:00:43

Leetcode 721 账户合并

给定一个列表 accounts,每个元素 accounts[i] 是一个字符串列表,其中第一个元素 accounts[i][0]名称 (name),其余元素是 *emails * 表示该账户的邮箱地址。

现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称。

合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是 按字符 ASCII 顺序排列 的邮箱地址。账户本身可以以 任意顺序 返回。

示例 1:


输入:accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]]
输出:[["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'],  ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]]
解释:
第一个和第三个 John 是同一个人,因为他们有共同的邮箱地址 "johnsmith@mail.com"。 
第二个 John 和 Mary 是不同的人,因为他们的邮箱地址没有被其他帐户使用。
可以以任何顺序返回这些列表,例如答案 [['Mary','mary@mail.com'],['John','johnnybravo@mail.com'],
['John','john00@mail.com','john_newyork@mail.com','johnsmith@mail.com']] 也是正确的。

示例 2:


输入:accounts = [["Gabe","Gabe0@m.co","Gabe3@m.co","Gabe1@m.co"],["Kevin","Kevin3@m.co","Kevin5@m.co","Kevin0@m.co"],["Ethan","Ethan5@m.co","Ethan4@m.co","Ethan0@m.co"],["Hanzo","Hanzo3@m.co","Hanzo1@m.co","Hanzo0@m.co"],["Fern","Fern5@m.co","Fern1@m.co","Fern0@m.co"]]
输出:[["Ethan","Ethan0@m.co","Ethan4@m.co","Ethan5@m.co"],["Gabe","Gabe0@m.co","Gabe1@m.co","Gabe3@m.co"],["Hanzo","Hanzo0@m.co","Hanzo1@m.co","Hanzo3@m.co"],["Kevin","Kevin0@m.co","Kevin3@m.co","Kevin5@m.co"],["Fern","Fern0@m.co","Fern1@m.co","Fern5@m.co"]]

提示:

  • 1 <= accounts.length <= 1000
  • 2 <= accounts[i].length <= 10
  • 1 <= accounts[i][j].length <= 30
  • accounts[i][0] 由英文字母组成
  • accounts[i][j] (for j > 0) 是有效的邮箱地址

Solution

对于这题,我的第一反应不就是key-val转为val-key吗?所以果断的写下如下代码。

class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        email_name_map = {}
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_name_map:
                    email_name_map[email] = name
        # 最后根据name重新分组
        result = {}
        for email,name in email_name_map.items():
            if name not in result:
                result[name] = [name]
            result[name].append(email)
      
        res = []
        for k,v in result.items():
            res.append(v)
        return res
      

结果自然是全部报错:

× @test([["John","johnsmith@mail.com","john_newyork@mail.com"],["John","johnsmith@mail.com","john00@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]])

result:

[["John","johnsmith@mail.com","john_newyork@mail.com","john00@mail.com","johnnybravo@mail.com"],["Mary","mary@mail.com"]] ,

expect:

[["John","john00@mail.com","john_newyork@mail.com","johnsmith@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]]


可以发现,我们的结果将John的所有的邮箱合并在了一起。但是我们忽略了一种情况,即,同一个名字可能是两个不同的人啊。

所以说,我们应该转变思维,合并的依据不是有共同的名字,而是有共同的邮箱。

这个时候我们就需要知道每两个账户之间是否有重合账户,有的话即标记为1,否则标记为0。是否有重合账户我们可以用集合的交集来判断。这样的话我们可以用如下方法解决:


class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        name_emails = []
        for account in accounts:
            name = account[0]
            name_emails = [[name,set(account[1:])]]
      
        n = len(name_emails)
      
        connections = [[0 for i in range(n)] for j in range(n)]
        for i in range(n):
            for j in range(n):
                if len(name_emails[i]&name_emails[j]) > 0:
                    connections[i][j] = 1
      
      

注意构造集合的时候,名字不能构造进去,不然同名同姓的两个人也会有交集的。

然后开始合并。

class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        name_emails = []
        for account in accounts:
            name = account[0]
            name_emails = [[name,set(account[1:])]]
    
        n = len(name_emails)
    
        connections = [[0 for i in range(n)] for j in range(n)]
        for i in range(n):
            for j in range(n):
                if len(name_emails[i][1]&name_emails[j][1]) > 0:
                    connections[i][j] = 1
    
        res = []
        visited = []
        for i in range(n):
            if i in visited:
                continue
            res.append(name_emails[i])
            visited.append(i)
            for j in range(i,n):
                if connections[i][j] == 1:
                    visited.append(j)
                    res[-1][1] = res[-1][1] | name_emails[j][1]
    
        res = [[res[i][0]].extend(list(res[i][1])) for i in range(len(res))]
        return res

@test([["John","johnsmith@mail.com","john_newyork@mail.com"],["John","johnsmith@mail.com","john00@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]])

result: [["John","johnsmith@mail.com","john00@mail.com","john_newyork@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]] ,

expect: [["John","john00@mail.com","john_newyork@mail.com","johnsmith@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]]

的确是解决了一部分问题,但是可能会漏掉一些应该合并的账户。例如,如果账户A和B有交集,B和C有交集,但A和C没有直接交集,代码可能不会将A、B、C全部合并。如果想要合并就需要多次迭代直到完全合并为止。

这种情况应该如何解决呢?带有间接的情况本质上就是各个账户之间形成了一个关系图,应该使用dfs和bfs了。直接从二维矩阵中进行dfs和bfs是比较麻烦的,这个时候我们就需要构造一个真正的图。

首先构建节点:

class Node:
    def __init__(self,id:int,account) -> None:
        self.id = id
        self.name = account[0]
        self.emails = set(account[1])
        self.linked_nodes = []
      
    def add_link(self,node):
        if node not in self.linked_nodes:
            self.linked_nodes.append(node)
            node.linked_nodes.append(self)

根据图的思路重新解决问题:


class Node:
    def __init__(self,id:int,account) -> None:
        self.id = id
        self.name = account[0]
        self.emails = set(account[1:])
        self.linked_nodes = []
      
    def add_link(self,node):
        if node not in self.linked_nodes:
            self.linked_nodes.append(node)
            node.linked_nodes.append(self)


class DFSNodes:
    def __init__(self,nodes:List[Node],visited:list) -> None:
        self.nodes = nodes
        self.visited = visited
        self.result = []
  
    def dfs(self,node:Node):
        if node is None: return 
        if node in self.visited: return 
        self.visited.append(node)
        self.result.extend(list(node.emails))
        for node_ in node.linked_nodes:
            self.dfs(node_)


class Solution:  
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        n = len(accounts)
        nodes = [Node(i,account) for i,account in enumerate(accounts)]
      
        # 建立节点之间的直接关联,形成图
        for i in range(n):
            for j in range(i+1,n):
                if len(nodes[i].emails & nodes[j].emails) > 0:
                    nodes[i].add_link(nodes[j])
                    nodes[j].add_link(nodes[i])
        # dfs 遍历
        merged_accounts = []
        visited = []
      
        for node in nodes:
            if node in visited: continue
            dfs_tool = DFSNodes(nodes,visited)
            dfs_tool.dfs(node)
            visited.extend(dfs_tool.visited)
            merged_accounts.append([node.name,set()])
            merged_accounts[-1][1] = merged_accounts[-1][1] | set(dfs_tool.result)
      
        result = []
        for item in merged_accounts:
            name = item[0]
            emails = list(item[1])
            result.append([name])
            result[-1].extend(emails)
      
        return result
      
          
@test([["Gabe","Gabe0@m.co","Gabe3@m.co","Gabe1@m.co"],["Kevin","Kevin3@m.co","Kevin5@m.co","Kevin0@m.co"],["Ethan","Ethan5@m.co","Ethan4@m.co","Ethan0@m.co"],["Hanzo","Hanzo3@m.co","Hanzo1@m.co","Hanzo0@m.co"],["Fern","Fern5@m.co","Fern1@m.co","Fern0@m.co"]])  
result: [["Gabe","Gabe0@m.co","Gabe1@m.co","Gabe3@m.co"],["Kevin","Kevin0@m.co","Kevin5@m.co","Kevin3@m.co"],["Ethan","Ethan0@m.co","Ethan4@m.co","Ethan5@m.co"],["Hanzo","Hanzo0@m.co","Hanzo1@m.co","Hanzo3@m.co"],["Fern","Fern5@m.co","Fern1@m.co","Fern0@m.co"]] ,
expect: [["Ethan","Ethan0@m.co","Ethan4@m.co","Ethan5@m.co"],["Gabe","Gabe0@m.co","Gabe1@m.co","Gabe3@m.co"],["Hanzo","Hanzo0@m.co","Hanzo1@m.co","Hanzo3@m.co"],["Kevin","Kevin0@m.co","Kevin3@m.co","Kevin5@m.co"],["Fern","Fern0@m.co","Fern1@m.co","Fern5@m.co"]]

看来是解决问题了。但是提交之后:

× @test([["John","johnsmith@mail.com","john_newyork@mail.com"],["John","johnsmith@mail.com","john00@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]])  
result: [["John","johnsmith@mail.com","john_newyork@mail.com","john00@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]] ,
expect: [["John","john00@mail.com","john_newyork@mail.com","johnsmith@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]]

看起来没问题,就是顺序不一样。

我们回头仔细审题,发现“合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是 按字符 ASCII 顺序排列 的邮箱地址。账户本身可以以 任意顺序 返回”

所以,我们需要再排个序。

class Node:
    def __init__(self,id:int,account) -> None:
        self.id = id
        self.name = account[0]
        self.emails = set(account[1:])
        self.linked_nodes = []
    
    def add_link(self,node):
        if node not in self.linked_nodes:
            self.linked_nodes.append(node)
            node.linked_nodes.append(self)


class DFSNodes:
    def __init__(self,nodes:List[Node],visited:list) -> None:
        self.nodes = nodes
        self.visited = visited
        self.result = []
  
    def dfs(self,node:Node):
        if node is None: return 
        if node in self.visited: return 
        self.visited.append(node)
        self.result.extend(list(node.emails))
        for node_ in node.linked_nodes:
            self.dfs(node_)


class Solution:  

    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        n = len(accounts)
        nodes = [Node(i,account) for i,account in enumerate(accounts)]
    
        # 建立节点之间的直接关联,形成图
        for i in range(n):
            for j in range(i+1,n):
                if len(nodes[i].emails & nodes[j].emails) > 0:
                    nodes[i].add_link(nodes[j])
                    nodes[j].add_link(nodes[i])
        # dfs 遍历
        merged_accounts = []
        visited = []
    
        for node in nodes:
            if node in visited: continue
            dfs_tool = DFSNodes(nodes,visited)
            dfs_tool.dfs(node)
            visited.extend(dfs_tool.visited)
            merged_accounts.append([node.name,set()])
            merged_accounts[-1][1] = merged_accounts[-1][1] | set(dfs_tool.result)
    
        result = []
        for item in merged_accounts:
            name = item[0]
            emails = list(item[1])
            emails.sort()
            result.append([name])
            result[-1].extend(emails)
    
        return result

现在是接受了。

但是,觉不觉得这个解法太复杂了。根据实测,时间复杂度和空间复杂度也是极高的,基本上是擦边过。其中最耗费时间和空间的就是dfs操作和构建关联的时候两次遍历。那么,有没有一种办法,可以根据数据只查询一次、不用像图一样需要经过复杂的遍历得到结果呢?

这个时候我们就要引入并查集。

并查集

并查集(Union-Find)是一种非常有用的数据结构,并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。它具有一些独特的特性,使其在特定场景下非常高效。让我介绍一下并查集的主要特性和典型应用场景:

并查集的特性:

  • 快速合并(Union)操作:

可以快速将两个集合合并为一个。

  • 快速查找(Find)操作:

可以快速确定一个元素属于哪个集合。

  • 路径压缩:

在查找过程中,可以压缩查找路径,使得后续操作更快。

  • 近乎常数时间复杂度:

经过优化后(如路径压缩和按秩合并),大多数操作的平均时间复杂度接近 O(1)。

  1. 空间效率高:

只需要一个数组就可以表示复杂的集合关系。

  1. 动态维护集合:

可以动态地添加新元素和合并集合。

  1. 不支持分割操作:

一旦元素被合并到一个集合中,就不能再分割。

在这里插入图片描述

并查集的实现
class UnionFind:
    def __init__(self, n):
        # 初始化父节点数组和秩数组
        self.parent = list(range(n))
        self.rank = [0] * n
        # 记录集合的数量
        self.count = n

    def find(self, x):
        # 路径压缩:在查找的同时,将 x 到根节点路径上的所有节点直接连接到根节点
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        root_x, root_y = self.find(x), self.find(y)
      
        # 如果 x 和 y 已经在同一个集合中,无需合并
        if root_x == root_y:
            return False

        # 按秩合并:将秩较小的树连接到秩较大的树上
        if self.rank[root_x] < self.rank[root_y]:
            self.parent[root_x] = root_y
        elif self.rank[root_x] > self.rank[root_y]:
            self.parent[root_y] = root_x
        else:
            self.parent[root_y] = root_x
            self.rank[root_x] += 1

        # 合并成功,集合数量减少
        self.count -= 1
        return True

    def connected(self, x, y):
        # 判断 x 和 y 是否在同一个集合中
        return self.find(x) == self.find(y)

    def get_count(self):
        # 获取当前的集合数量
        return self.count

估计还是晕晕乎乎的。无妨,我们直接用它来解决问题。


这个问题可以用并查集来解决,主要基于以下几个原因:

  1. 分组问题:

本质上,这是一个分组或聚类问题。我们需要将属于同一个人的账户合并在一起。并查集非常适合处理这种需要动态合并集合的问题。

  • 传递关系:

如果账户A和B有共同邮箱,B和C有共同邮箱,那么A、B、C都应该被合并。这种传递关系正是并查集所擅长处理的。

  • 高效的合并操作:

在处理大量账户时,我们需要频繁地判断和合并账户。并查集提供了近乎常数时间的合并和查找操作,非常高效。

  1. 动态性:

账户的合并是一个动态的过程,我们在遍历账户时逐步发现需要合并的关系。并查集可以很好地处理这种动态添加关系的场景。

  1. 不需要拆分:

一旦确定两个账户属于同一个人,它们就应该永久合并。并查集正好不支持分割操作,符合这个特性。

那么,我们来重写代码,首先,每个集合里面的内容是姓名和邮箱,那么我们就需要为邮箱分配一个唯一ID:

class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
    
        email_id_map = {}
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_id_map:
                    email_id_map[email] = len(email_id_map)

姓名信息也不能丢。

class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
    
        email_id_map = {}
        email_name_map = {}
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_id_map:
                    email_id_map[email] = len(email_id_map)
                email_name_map[email] = name
      

好了,下面我们需要按照并查集的思路构建了。首先,先将所有的节点(邮箱)都认为是父节点,代表每个节点都是一个集合。

class UnionFind:
    def __init__(self,n) -> None:
        self.parent = [i for i in range(n)]


class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
    
        email_id_map = {}
        email_name_map = {}
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_id_map:
                    email_id_map[email] = len(email_id_map)
                email_name_map[email] = name
         # 创建并查集
        n = len(email_id_map)
        uf_tool = UnionFind(n)

之后,再根据accounts中提供的信息,利用并查集的数据结构,动态的调整集合,调整到最后,剩余的父节点数量就是集合数量了。


  • 遍历账户,根据账户提供的信息调整集合。

具体调整什么呢?就是将同一账号下的邮箱放到同一个集合下面。具体来说,就是将每个邮箱和第一个邮箱进行合并。

class UnionFind:
    def __init__(self,n) -> None:
        self.parent = [i for i in range(n)]
    
    def union(self,email1:str,email2:str):
        """
		"""


class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
    
        email_id_map = {}
        email_name_map = {}
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_id_map:
                    email_id_map[email] = len(email_id_map)
                email_name_map[email] = name
    
        # 创建并查集
        n = len(email_id_map)
        uf_tool = UnionFind(n)
    
        for account in accounts:
            for email in account[2:]:
                uf_tool.union(email_id_map[account[1]],email_id_map[email])

合并的时候具体怎么合并呢?对于传入的两个id,我们找找到它对应集合的根元素,第一次调用的时候,每个集合都只有一个根元素,就是它自身。对于有多个元素的集合,我们就要根据self.parent中的内容,依次向上查找,直到无法向上继续找(即,找到的向上的id还是它自身)。然后将其中一个根作为另一个根的父节点。这样,两棵树就变成一棵树了。

在这里插入图片描述

具体来说如下:


class UnionFind:
    def __init__(self,n) -> None:
        self.parent = [i for i in range(n)]
  
    def find(self,email_id):
        """
        查找x元素的根节点
        """
        while not self.parent[email_id] == email_id:  
            # 验证self.parent一直往上查,碰到自回环节点,说明到了初始设置的节点,这个节点就是根节点
            email_id = self.parent[email_id]
        return self.parent[email_id]

  
    def union(self,email_id1,email_id2):
        """
        将两个集合合并。
        """
        root_x, root_y = self.find(email_id1), self.find(email_id2)
        if root_x != root_y:
            self.parent[root_x] = root_y
    


class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
    
        email_id_map = {}
        email_name_map = {}
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_id_map:
                    email_id_map[email] = len(email_id_map)
                email_name_map[email] = name
    
        # 创建并查集
        n = len(email_id_map)
        uf_tool = UnionFind(n)
    
        for account in accounts:
            for email in account[2:]:
                uf_tool.union(email_id_map[account[1]],email_id_map[email])

这样遍历一遍,集合自然而然就会被重组组织。这就是并查集的厉害之处。

下面将集合的结果进行重新组织:


class UnionFind:
    def __init__(self,n) -> None:
        self.parent = [i for i in range(n)]
  
    def find(self,email_id):
        """
        查找x元素的根节点
        """
        while not self.parent[email_id] == email_id:  
            # 验证self.parent一直往上查,碰到自回环节点,说明到了初始设置的节点,这个节点就是根节点
            email_id = self.parent[email_id]
        return self.parent[email_id]

  
    def union(self,email_id1,email_id2):
        """
        将两个集合合并。
        """
        root_x, root_y = self.find(email_id1), self.find(email_id2)
        if root_x != root_y:
            self.parent[root_x] = root_y
    


class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
    
        email_id_map = {}
        email_name_map = {}
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_id_map:
                    email_id_map[email] = len(email_id_map)
                email_name_map[email] = name
    
        # 创建并查集
        n = len(email_id_map)
        uf_tool = UnionFind(n)
    
        for account in accounts:
            for email in account[2:]:
                uf_tool.union(email_id_map[account[1]],email_id_map[email])
    
        # 将各个集合的结果重新组织。根据根节点重新划分
        id_email_map = {}
        for email,id in email_id_map.items():
            root = uf_tool.find(id)
            if root not in id_email_map:
                id_email_map[root] = []
            id_email_map[root].append(email)
    
		# 补充name
        result = []
        for emails in id_email_map.values():
            name = email_name_map[emails[0]]
            result.append([name]+sorted(emails))

        return result

到这里的性能就可以看了。当然,如果还想进一步优化,find函数还可以进行路径压缩。

在这里插入图片描述

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
  
    def find(self,email_id):
        """
        查找x元素的根节点
        """
        if self.parent[email_id] != email_id:
            # 如果不是根节点,则递归找到根节点并将当前节点直接置于根节点之下
            self.parent[email_id] = self.find(self.parent[email_id])
        return self.parent[email_id]
    def union(self, x, y):
        root_x, root_y = self.find(x), self.find(y)
        if root_x != root_y:
            self.parent[root_x] = root_y

class Solution:
    def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
        email_to_id = {}
        email_to_name = {}
      
        # 为每个邮箱分配一个唯一的ID
        for account in accounts:
            name = account[0]
            for email in account[1:]:
                if email not in email_to_id:
                    email_to_id[email] = len(email_to_id)
                email_to_name[email] = name
      
        # 创建并查集
        uf = UnionFind(len(email_to_id))
      
        # 合并同一账户下的所有邮箱
        for account in accounts:
            for email in account[2:]:
                uf.union(email_to_id[account[1]], email_to_id[email])
      
        # 根据并查集结果重新组织邮箱
        id_to_emails = {}
        for email, id in email_to_id.items():
            root = uf.find(id)
            if root not in id_to_emails:
                id_to_emails[root] = []
            id_to_emails[root].append(email)
      
        # 构建最终结果
        result = []
        for emails in id_to_emails.values():
            name = email_to_name[emails[0]]
            result.append([name] + sorted(emails))
      
        return result

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2214676.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jmeter在beanshell中使用props.put()方法的注意事项

在jmeter中&#xff0c;通常使用beanshell去处理一些属性的设置和获取的操作&#xff0c;而这些操作也是有一定的规则的。 1. 设置属性时&#xff0c;在属性名上要加双引号&#xff0c;这代表它不是一个需要用var去声明的变量 这种设置属性的方式才是有效可行的&#xff0c;在…

[权威出刊|稳定检索]2024年云计算、大数据与计算机应用技术国际会议(CCBDCAT 2024)

2024年云计算、大数据与计算机应用技术国际会议 2024 International Conference on Cloud Computing, Big Data, and Computer Application Technology 【1】大会信息 会议名称&#xff1a;2024年云计算、大数据与计算机应用技术国际会议 会议简称&#xff1a;CCBDCAT 2024 大…

【算法设计与分析】第2关:背包问题

任务描述 设有编号为0、1、2、…、n-1的n个物品&#xff0c;它们的重量分别为w0、w1、…、wn-1&#xff0c;价值分别为p0、p1、…、pn-1&#xff0c;其中wi、pi&#xff08;0≤i≤n-1&#xff09;均为正数。  有一个背包可以携带的最大重量不超过W。求解目标&#xff1a;在不…

C++类和对象——第三关

在阅读此篇文章之前&#xff0c;请先阅读博主之前的文章&#xff1a; C类和对象第一关-CSDN博客 C类和对象——第二关-CSDN博客 以便更好的理解本文章。 目录 运算符重载 &#xff08;一&#xff09;运算符重载 &#xff08;二&#xff09;赋值类运算符函数的重载&#x…

基于EBAZ4205矿板的图像处理:16基于小波变换的图像分解及其重建

基于EBAZ4205矿板的图像处理&#xff1a;17基于小波变换的图像分解及其重建 特别说明 这个项目的代码不会开源&#xff0c;因为这个项目的一大部分是在实习的公司做的&#xff0c;所以仅提供思路和展示&#xff0c;展示一下我的能力。 先看效果 这次让小牛和小绿做模特 经过…

C++模板初阶,只需稍微学习;直接起飞;泛型编程

&#x1f913;泛型编程 假设像以前交换两个函数需要&#xff0c;函数写很多个或者要重载很多个&#xff1b;那么有什么办法实现一个通用的函数呢&#xff1f; void Swap(int& x, int& y) {int tmp x;x y;y tmp; } void Swap(double& x, double& y) {doubl…

胤娲科技:AI短视频——创意无界,即梦启航

在这个快节奏的时代&#xff0c;你是否曾梦想过用几秒钟的短视频&#xff0c;捕捉生活中的每一个精彩瞬间&#xff1f;是否曾幻想过&#xff0c;即使没有专业的摄影和剪辑技能&#xff0c;也能创作出令人惊艳的作品&#xff1f; 现在&#xff0c;这一切都不再是遥不可及的梦想。…

微前端学习以及分享

微前端学习以及分享 注&#xff1a;本次分享demo的源码github地址&#xff1a;https://github.com/rondout/micro-frontend 什么是微前端 微前端的概念是由ThoughtWorks在2016年提出的&#xff0c;它借鉴了微服务的架构理念&#xff0c;核心在于将一个庞大的前端应用拆分成多…

从MySQL到OceanBase离线数据迁移的实践

本文作者&#xff1a;玉璁&#xff0c;OceanBase 生态产品技术专家。工作十余年&#xff0c;一直在基础架构与中间件领域从事研发工作。现负责OceanBase离线导数产品工具的研发工作&#xff0c;致力于为 OceanBase 建设一套完善的生态工具体系。 背景介绍 在互联网与云数据库技…

LEAP 瞬移工具场景试点游戏关卡

你是否厌倦了在Unity编辑器中浪费时间浏览大型游戏关卡&#xff1f;不要看得比Leap更远&#xff01;这个功能强大的编辑器脚本允许您只需单击一下即可即时传输到场景中的任何位置。告别繁琐的手动导航&#xff0c;迎接闪电般快速的关卡设计。有了Leap&#xff0c;你就可以专注于…

Gin框架官方文档详解04:HTTP/2 推送,JSON相关

官方文档&#xff1a;https://gin-gonic.com/zh-cn/docs/ 注&#xff1a;强烈建议没用过Gin的读者先阅读第一节&#xff1a;第一个Gin应用。 目录 一、HTTP/2 推送二、JSONP三、PureJSON四、SecureJSON五、总结 一、HTTP/2 推送 首先&#xff0c;以“04HTTP2server推送”为根目…

linux 时区问题

一、修改系统时间和时区 查看当前下系统时间和时区 timedatectl设置系统时区 ​sudo timedatectl set-timezone <时区>​&#xff0c;例如&#xff1a; sudo timedatectl set-timezone Asia/Shanghai执行成功则没有输出。 更推荐使用 tzselect​ ​命令&#xff0c;…

通信工程学习:什么是VHDL超高速集成电路硬件描述语言

VHDL&#xff1a;超高速集成电路硬件描述语言 VHDL&#xff0c;全称为Very-High-Speed Integrated Circuit Hardware Description Language&#xff0c;即超高速集成电路硬件描述语言&#xff0c;是一种用于电路设计的高级语言。以下是关于VHDL的详细介绍&#xff1a; 一、起源…

ThingsBoard规则链节点:Split Array Msg节点详解

引言 拆分数组消息节点简介 用法 含义 应用场景 实际项目运用示例 智能仓储管理系统 智能电网监控系统 车联网平台 结论 引言 ThingsBoard是一个功能强大的物联网平台&#xff0c;它提供了设备管理、数据收集与处理以及实时监控等核心功能。其规则引擎允许用户定义复杂…

时序图分析(IIC通信为例)

一、时序图分析&#xff08;IIC通信为例&#xff09; 时序图-->编程 解析&#xff1a;时序概念&#xff1a;一般指可编程器件的编程方法&#xff0c;在单片机编程时&#xff0c;需要根据被控芯片的时序去写程序&#xff0c;把芯片上的时序用代码来实现&#xff0c;方可实…

数据结构4——栈

1. 栈的概念及结构 栈的概念&#xff1a; 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则…

<Linux> 线程池

一、线程池 1. 池化技术 池化技术是一种在计算机科学中广泛应用的优化技术&#xff0c;它的核心思想是&#xff1a;预先创建并维护一组资源&#xff08;例如线程、连接、对象&#xff09;&#xff0c;供多个任务共享使用&#xff0c;以减少创建和销毁资源的开销&#xff0c;提…

贪吃蛇游戏(代码篇)

我们并不是为了满足别人的期待而活着。 前言 这是我自己做的第五个小项目---贪吃蛇游戏&#xff08;代码篇&#xff09;。后期我会继续制作其他小项目并开源至博客上。 上一小项目是贪吃蛇游戏&#xff08;必备知识篇&#xff09;&#xff0c;没看过的同学可以去看看&#xf…

使用Java API访问Apache Kafka

简介 Kafka是由Apache软件基金会开发的一个开源流处理平台,Kafka是一个功能强大且灵活的平台。 基本情况 软件名称:Apache Kafka 软件平台:跨平台 软件语言:Scala、Java 开发商:Apache软件基金会 软件授权:Apache License 2.0 最近更新时间:2024年7月23日 核心概念 -…

Ubuntu:用户不在sudoers文件中

1、问题 执行sudo xxx命令时&#xff0c;显示&#xff1a; user 不在sudoers文件中 需要查看系统版本进入恢复模式修复。 2、重启进入恢复模式 查看系统命令&#xff1a;uname -r 可能显示为&#xff1a;6.8.0-45-generic 重启Ubuntu系统&#xff0c;在开机时按ESC进入模…