判断具有多个属性的行的连通性

问题描述:

线上遇到的一个问题,这里做一个变形。有若干行数据(2000w)左右,每行有若干个属性,比如姓名、邮箱、地址等等;如果两行数据有至少一个属性值相同,就认为这两个行是连通的;并且连通性有转移,比如A与B连通,B与C连通,就可以认为A与C连通。那么这两千万行数据哪些是连通的?

nameaddresstel
Aabc135
Abcd136
Bcde136

如上第一行与第二行name相同,可认为行1连通行2;
第二行与第三行第三个属性相同,可认为行2连通行3;
于是1 2 3可认为是一个组。

暴力解法:对每个属性遍历,对每行数据遍历,时间复杂度最少为 mn2 m ∗ n 2 (n为行数)
思路1:看到连通性立马可以想到并查集,但是并查集是已经知道哪些行数据是连通的,然后再根据并查集构造的数判断哪些属于一个组,这是整体思路。对并查集不清楚可参考 https://blog.csdn.net/u011730199/article/details/80909373

https://blog.csdn.net/dm_vincent/article/details/7655764

接下来,如何判断行与行之间的连通性呢?

遍历做法直接舍弃。考虑到一行有若干属性,可以联想到树的层级结构。对每行数据,如果对应的属性值已经存在,则连通。判断属性值是否已经存在最快的是使用HashMap的key来判断。
每行数据有m个属性,初始化m个 HashMap<String,Integer> H a s h M a p < S t r i n g , I n t e g e r > String为属性值,int为行号。对每行数据判断对应层级的map,是否存在,若存在
uf.union(m1,m2);若不存在map.put(string,m);
时间复杂度为 mn m ∗ n m为属性个数,n为行数
如果想要判断哪些连通,需要使用BFS或者DFS。这里略过。
代码如下:

public class Vert {
    private static ArrayList<HashMap<String,Integer>> list = new ArrayList<HashMap<String,Integer>>();
    public static void main(String[] args) {
        String[][] line = {{"136","11@qq.com","22@c.com"},{"137","11@qq.com","23@c.com"},
                {"138","110@qq.com","23@c.com"},{"139","1100@qq.com","24@c.com"}};
        Union_Find u = new Union_Find(line.length);
        for(int i = 0;i<line.length;i++) {
            for(int j = 0;j<line[i].length;j++) {
                if(i == 0) {
                    HashMap<String,Integer> t = new HashMap<String,Integer>();
                    arr[i] = 1;
                    t.put(line[i][j], i);
                    list.add(t);
                }else {
                HashMap<String,Integer> temp = list.get(j);
                if(temp.containsKey(line[i][j]))
                    u.union(temp.get(line[i][j]), i);
                else
                    list.get(j).put(line[i][j], i);
                }
            }
        }
        System.out.println(u.isConnected(1, 2));
    }
}

Union_Find是一个并查集实现,这里略过。如果有更好的解法或者bug。欢迎留言+交流,vx:LEILE111,邮箱hcy_xy@qq.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值