Uma estrutura de dados para encontrar o pai: e verificar a coleção de explicações detalhadas, anexe o modelo python e exemplos de perguntas (a versão completa e a versão compactada estão disponíveis para encontrar o pai)

1. Conceito

O conjunto de consulta de união é uma estrutura de dados do tipo árvore usada para lidar com os problemas de fusão e consulta de alguns conjuntos disjuntos (os chamados união e consulta). Por exemplo, podemos usar a pesquisa de união para determinar quantas árvores existem em uma floresta, se um nó pertence a uma determinada árvore e assim por diante.

Composição principal: O
conjunto de pesquisa de união é composto principalmente de um array de inteiros pre [] e duas funções find () e join ().
O array pre [] registra quem é o nó predecessor de cada ponto (geralmente entendido como quem é o pai do ponto), a função find (x) é usada para encontrar a qual conjunto o nó especificado x pertence (pode ser entendido como encontrar o ancestral), a função join (x, y) é usada para mesclar dois nós xey (geralmente considere x como o pai de y).

Função:
a função principal do conjunto de pesquisa de união é encontrar o número de componentes conectados (se todos os pontos em um gráfico forem alcançáveis ​​(conectados direta ou indiretamente), então o número de componentes conectados do gráfico é 1; se o gráfico tiver dois subgráficos Se todos eles forem alcançáveis, o número de componentes conectados neste gráfico é 2 ...).

Exemplo:
por exemplo, um continente tem quatro seitas : Céu, Terra, Xuan e Huang, e cada seita tem vários discípulos de níveis diferentes. A matriz [] anterior registra o nome do chefe de cada discípulo e o método find () é para encontrar o chefe do discípulo O chefe do chefe ... é o chefe da seita, o método de união (A, B) é definir o discípulo A como o chefe do discípulo B.

Em segundo lugar, o python implementa a versão completa do código

A estrutura de dados da versão completa possui inicialização, localização, fusão e outros métodos, que visam principalmente facilitar o entendimento.Geralmente, a versão completa não é utilizada para resolver o problema, pois a quantidade de redundância de código aumenta a complexidade de tempo e espaço.

class UnionFind:
    def __init__(self):
        self.father = {
    
    }    ##记录每个节点的父节点
 
    def find(self, x):
        root = x
        while self.father[root] != root:    #寻找根节点
            root = self.father[root]
        while root != x:                    #路径压缩
            preFather = self.father[x]
            self.father[x] = root
            x = preFather
        return root
 
    def merge(self, x, y):              #合并节点
        root_x, root_y = self.find(x), self.find(y)
        if root_x != root_y:
            self.father[root_x] = root_y
 
    def is_connected(self, x, y):       #判断联通性
        return self.find(x) == self.find(y)
 
    def add(self, x):                   #增加节点
        if x not in self.father:
            self.father[x] = x

3. Colete e verifique a versão compactada do código Python (a maneira mais comumente usada de resolver problemas)

Na resolução de problemas, a fim de garantir a simplicidade do código e reduzir a complexidade do tempo e do espaço, geralmente apenas um array pai e um método find () são definidos.

Nota: O método find tem a função de atualizar continuamente o pai e geralmente é implementado de maneira recursiva.

dus ={
    
    。。。。。。}  # 先定义爸爸数组的形式及初始元素值

# 定义查找祖值方法(含更新祖值作用)
def find(i):
    if dus[i] != i:
        dus[i] = find(dus[i])
    return dus[i]

Quatro, e coletar exemplos típicos

(1) Banco de perguntas Likou: 947, os pares ou pedras mais removidas na mesma linha

Aplique a versão compactada e verifique o modelo

n pedras são colocadas em alguns pontos de coordenadas inteiras em um plano bidimensional. Pode haver no máximo uma pedra em cada ponto de coordenada.

Se houver outras pedras na mesma linha ou na mesma linha de uma pedra, a pedra pode ser removida.

Fornece uma matriz de pedras de comprimento n, onde as pedras [i] = [xi, yi] representam a posição da i-ésima pedra e retorna o número máximo de pedras que podem ser removidas.

Exemplo 1:

Entrada: pedras = [[0,0], [0,1], [1,0], [1,2], [2,1], [2,2]]
Saída: 5
Explicação: A remoção O método de 5 pedras é o seguinte:

  1. Remova a pedra [2,2] porque é o mesmo que [2,1].
  2. Remova a pedra [2,1] porque ela está na mesma coluna que [0,1].
  3. Remova a pedra [1,2] porque vai com [1,0].
  4. Remova a pedra [1,0] porque ela está na mesma coluna que [0,0].
  5. Remova a pedra [0,1] porque é igual a [0,0].

A pedra [0,0] não pode ser removida porque não está alinhada / coluna com outra pedra.

Exemplo 2:

Entrada: pedras = [[0,0], [0,2], [1,1], [2,0], [2,2]]
Saída: 3
Explicação: Um método para remover 3 pedras é mostrado a seguir :

  1. Remova a pedra [2,2] porque é o mesmo que [2,0].
  2. Remova a pedra [2,0] porque ela está na mesma coluna que [0,0].
  3. Remova a pedra [0,2] porque é igual a [0,0].

As pedras [0,0] e [1,1] não podem ser removidas porque não estão em linha / coluna com outra pedra.

Exemplo 3:

Entrada: pedras = [[0,0]]
Saída: 0
Explicação: [0,0] é a única pedra no plano, portanto não pode ser removida.

incitar:

1 <= pedras. Comprimento <= 1000
0 <= xi, yi <= 104
Não haverá duas pedras colocadas no mesmo ponto de coordenada

Ideias para resolução de problemas:

Depois de ler o tópico, o primeiro sentimento é descobrir quantos conjuntos de pedras conectadas.
E cada grupo de pedras conectadas precisa manter pelo menos uma pedra, então a resposta é o número de pedras - o número de grupos de pedras conectadas.

Depois de ler a solução oficial do problema, entendi um truque. Adicionar 10000 (o valor máximo das coordenadas) às ordenadas de todas as coordenadas. Podemos considerar as coordenadas como arestas.
Por exemplo, [[0,0], [1,1], [1,2]] => [[0,10000], [1,10001], [1,10002].
Aqui, 0, 10000, 1, 10001, 10002 representam 5 nós.
[0,10000] significa que o nó 0 e o nó 10000 estão conectados por uma borda.
[1,10001] indica que o nó 1 e o nó 10001 têm uma conexão de borda.
[1,10002] indica que o nó 1 e o nó 10002 têm uma conexão de borda.
Isso se transforma em um gráfico familiar e encontra o problema, atravesse todas as arestas, você pode encontrar todos os grupos conectados.

A complexidade de tempo é O (nlogm), onde n é o número de arestas e m é o número de nós.
A complexidade do espaço é O (m), e o dicionário é usado aqui para implementação e pesquisa. Claro, a lista também está OK.

Além disso, preste atenção para chamar find em todos os nós no final para atualizar o grupo conectado ao qual eles pertencem.

Código de solução do problema:

class Solution:
    def removeStones(self, stones: List[List[int]]) -> int:
    	# 以字典形式定义初始化的parent集
        dus ={
    
    s+i*10000:s+i*10000 for stone in stones for i, s in enumerate(stone)}
        print(dus)
		# 定义查找祖值方法(含更新祖值作用)
        def find(i):
            if dus[i] != i:
                dus[i] = find(dus[i])
            return dus[i]

		# 遍历全部石头,按顺序更新祖值
        for i, (s1, s2) in enumerate(stones):
            if s1 in dus and find(s1) != find(s2+10000):
                # union
                dus[find(s1)] = find(s2+10000)
                print(i, dus)
        # 防止按顺序更新的祖集中有重复未更新,再次更新
        for k in dus:
            print(k)
            find(k)
        # 最后用总数减去不重复的祖值数即可
        return len(stones) - len(set(dus.values()))

(2) Banco de perguntas Likou: 1202, troque elementos na string

Aplique a versão completa e verifique o modelo

Fornece uma string s e alguns pares de array de "pares de índices" na string, onde os pares [i] = [a, b] representam dois índices na string (a numeração começa em 0).

Você pode trocar os caracteres em qualquer par de índices em pares quantas vezes quiser.

Retorna a menor string lexicograficamente que s pode se tornar após várias trocas.

Exemplo 1:

Entrada: s = "dcab", pares = [[0,3], [1,2]]
Saída: "bacd"
Explicação:
troca s [0] es [3], s = "bcad"
troca s [1 ] E s [2], s = "bacd"

Exemplo 2:

Entrada: s = "dcab", pares = [[0,3], [1,2], [0,2]]
Saída: "abcd"
Explicação:
Troca s [0] es [3], s = " "bcad"
troca s [0] e s [2], s = "acbd"
troca s [1] e s [2], s = "abcd"

Exemplo 3:

Entrada: s = "cba", pares = [[0,1], [1,2]]
Saída: "abc"
Explicação:
troca s [0] es [1], s = "bca"
troca s [1 ] E s [2], s = "bac"
troca s [0] e s [1], s = "abc"

incitar:

1 <= s.length <= 10 ^ 5
0 <= pairs.length <= 10 ^ 5
0 <= pares [i] [0], pairs [i] [1] <s.length
s contém apenas letras minúsculas do inglês

Ideias para solução de problemas:

O principal é investigar e verificar a ideia da coleção e, após a coleção ser utilizada, descobrir os nós contidos em cada coleção separadamente, reordená-los e reatribuí-los.

Código python para solução de problemas (comentários detalhados):

# 定义一个并查集类,包含初始化祖先、查找祖先、合并祖先三种方法
class DSU:
    def __init__(self, nodecount):
        self.parent=[-1]*nodecount#初始化,每个节点的祖先都是自己,记住-1,这里node_count为节点总数
    def findboss(self, node):# 首先,是找到自己所在集合的最上面那一层的祖先,若值不为-1,说明当前自己的祖先并不是最终祖先,循环进行再去找他的祖先,直到找到最终祖先
        temp=node
        while self.parent[node]!=-1:
            node=self.parent[node]
        if temp!=node:#路径压缩,使得所有节点的祖先都是最终的祖先
            self.parent[temp]=node
        return node 
    def mergeboss(self, node1, node2):#查询相互连通的两个人的祖先是不是同一个人
        node1boss=self.findboss(node1)
        node2boss=self.findboss(node2)
        if node1boss!=node2boss:#如果不是,那就合并两个集合,从两人中选举一个新祖先
            self.parent[node1boss]=node2boss

class Solution:
    def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
        n=len(s)
        if n<2:
            return s
        dsu=DSU(n)#n个节点数,初始化并查集
        for node1,node2 in pairs:#先用并查集遍历一遍,使得每个节点都找到自己的祖先
            dsu.mergeboss(node1,node2)
        h={
    
    }
        for i in range(n):#再将所有公共祖先的子节点划分到一起,公共祖先自己也在该集合里
            if dsu.findboss(i) not in h:
                h[dsu.findboss(i)]=[i]
            else:
                h[dsu.findboss(i)].append(i)
        res=list(s)
        #print(dsu.parent)
        #print(h)
        for nodes in h.values():
            indices=sorted(nodes)#这里的每个节点都是相互连通的,即可以随意互相置换,直接按题意排序即可
            string=sorted(res[node] for node in nodes)#按最小字典序排列即从小到大
            # print(indices)
            # print(string)
            for index,letter in zip(indices,string):#按排好位置后,放回字母
                res[index]=letter
        return "".join(res)

Acho que você gosta

Origin blog.csdn.net/weixin_44414948/article/details/114002727
Recomendado
Clasificación