力扣题1202

力扣题1202

题目描述:
在这里插入图片描述
实现如下:

class Solution:
    def smallestStringWithSwaps(self, s: str, pairs: list[list[int]]) -> str:
        # 初步思路   因为s都是由小写字母组成的   要想最后的字符串最小
        # 就应该要比较小的字母往前排即可  从a开始  若字符串中存在a  就尽量使得a往前排(通过pairs可以知道最前可以往哪里排)
        # 然后排b  就这样循环  结束  (注意:前后置换的时候  要肯定前者大于后者   否则就停止)
        # 实质上就是图的遍历查询  从一个地方是否可以置换到另一个地方
        # 但是根据题中已知条件   内存不够   无法存储如此大的图结构

        # 进阶想法   a往最前面置换的时候  和他可以置换的其他字母  和他是一组的(可以经过相同的路线置换)
        # 所以  可以选择按组分类   只要元素之间可以相互交换   那么他们就是一组的
        # 这样先把组分号   然后组内排好序
        # 最后  按照原始的字符串顺序   从对应的所在组内选出最小值就可以了
        # (只要在同一组内  经过若干次置换  肯定可以将最小元素到达该位置  
        # 可用s = "cba", pairs = [[0,1],[1,2]]试验  可以得到任意一种顺序)
        # 这就是所谓的并查集!!!

        # 最终实现   根据上述思路   我只需要将pairs按是否可以相互置换合并成组
        # 然后取到组内对应元素   排序   在填回字符串
        # 执行完所有的分组即可

        if len(pairs) == 0:
            return s
        # 这样的合并方法居然超时了呀    难受
        # list_group = [[pairs[0][0], pairs[0][1]]]
        # for x in pairs[1::]:
        #     # 当前分组能否包含现有的数据
        #     flag1 = 0
        #     # 可能存在一组数据   使得两个分组合并的情况出现   设置判断
        #     # 最多使两个分组合并哟
        #     flag2 = -1
        #     for y in range(len(list_group)):
        #         if x[0] in list_group[y]:
        #             flag1 = 1
        #             if x[1] not in list_group[y]:
        #                 if flag2 == -1:
        #                     list_group[y].append(x[1])
        #                     flag2 = y
        #                 else:
        #                     list_group[flag2] = list(set(list_group[flag2] + list_group[y]))
        #                     list_group.pop(y)
        #                     break
        #         elif x[1] in list_group[y]:
        #             flag1 = 1
        #             if flag2 == -1:
        #                 list_group[y].append(x[0])
        #                 flag2 = y
        #             else:
        #                 list_group[flag2] = list(set(list_group[flag2] + list_group[y]))
        #                 list_group.pop(y)
        #                 break
        #     if flag1 == 0:
        #         list_group.append(x)
        # print(list_group)

        n = len(s)
        parent = {i: i for i in range(n)}

        # 并查集  递归到根节点
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]

        # 查找根节点
        for l, r in pairs:
            a, b = find(l), find(r)
            parent[b] = a
        
        # 获取根节点对应的连通块集合
        dic = collections.defaultdict(list)
        for i in range(n):
            root = find(i)
            dic[root].append(i)

        s = list(s)
        for x in dic.values():
            if len(x) > 1:
                x.sort()
                group = []
                for y in x:
                    group.append(s[y])
                group.sort()
                i = 0
                for y in x:
                    s[y] = group[i]
                    i += 1

        return ''.join(s)

这里涉及到一个新东西 新知识 并查集

刚开始想的时候 想到了这样的方法 但是并不知道这个叫并查集
看了评论才明白的

这里主要想表述一下 并查集和图的连通子图的区别吧
其实说白了 并查集的问题属于图的问题 但是 却不能用图的方法实现
原因就是 并查集对应的问题太过于庞大 用图进行解题的话 无法进行存储(内存放不下)
存储都是问题 其他的就免谈了 毕竟第一步是要先把图存到内存 才可以有接下来的操作

那么什么时候用图的知识解决呢?
第一 内存可以存储的下整张图
第二 题中给出的两点链接方式就是图的二维矩阵存储方法
如[[1,1,0],[1,1,0],[0,0,1]]

什么时候用并查集呢?
第一 结点个数太多 无法进行存储解决
第二 给出的是点对点的对应关系
如[[0,3],[1,2],[0,2]]
并查集的通用代码:`

		n = len(s)
        parent = {i: i for i in range(n)}

        # 并查集  递归到根节点
        def find(x):
            if x != parent[x]:
                parent[x] = find(parent[x])
            return parent[x]

        # 查找根节点
        for l, r in pairs:
            a, b = find(l), find(r)
            parent[b] = a
        
        # 获取根节点对应的连通块集合
        dic = collections.defaultdict(list)
        for i in range(n):
            root = find(i)
            dic[root].append(i)

那么最后dic.values()中就是存储所有的分组情况了

加油加油你最棒!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值