合并集列题与理解

题意

最近刷题刷到了一道关于字符串换位置的题目,采用的解法是合并集的方法,于是参考了CSDN上的一篇文章,发现很容易理解。

题目

给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。
你可以 任意多次交换 在 pairs 中任意一对索引处的字符。
返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。
输入:s = “dcab”, pairs = [[0,3],[1,2]]
输出:“bacd”
解释:
交换 s[0] 和 s[3], s = “bcad”
交换 s[1] 和 s[2], s = “bacd”

从题目中可以理解到首先需要将pairs中相互影响的,相互联系的数字凑成一个大的集合,然后在这个集合中升序排序字符,然后再在各个位置上放置相应的字符,这里把这个大集合想想成一个大的帮派,同时这个帮派在不断的扩容变大,pairs集合数组中就是建立友好的协议的证明。

于是首先初始化每个人一个帮派,接着通过pairs将相互想要建交的帮派融合,融合后选择后面位置的为新帮派的老大,可以通过合并集实现如下

for(int i = 0; i < len; ++i) root[i] = i;
        for(int i = 0; i < pairs.size(); ++i){
            if(find(pairs.get(i).get(0))!=find(pairs.get(i).get(1))){
                root[find(pairs.get(i).get(0))] = find(pairs.get(i).get(1));
            };
        }

其中find()函数为寻找自身老大的过程,

public int find(int son){
        int temp = son;
        while(son!=root[son]){
            son = root[son];
        }
        while(root[temp]!=son){
            root[temp] = son;
        }
        return son;
    }

通过不断的判断自己的当前上司是不是总上司,然后再让自己直接服务于总上司。

在字符排序的过程使用单调优先队列,由小顶堆实现底层,可以直接取堆顶元素来放置相应于的位置,总的代码如下

int []root;
    public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
        int len = s.length();
        root = new int[len];
        for(int i = 0; i < len; ++i) root[i] = i;
        for(int i = 0; i < pairs.size(); ++i){
            if(find(pairs.get(i).get(0))!=find(pairs.get(i).get(1))){
                root[find(pairs.get(i).get(0))] = find(pairs.get(i).get(1));
            };
        }

        Map<Integer, PriorityQueue<Character>> cache = new HashMap<>();
        for(int i = 0; i < len; ++i){
            cache.computeIfAbsent(find(i), k -> new PriorityQueue<Character>()).add(s.charAt(i));
        }
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < len; ++i){
            sb.append(cache.get(find(i)).poll());
        }
        return sb.toString();
    }

    public int find(int son){
        int temp = son;
        while(son!=root[son]){
            son = root[son];
        }
        while(root[temp]!=son){
            root[temp] = son;
        }
        return son;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值