一道面试题
给定一个字符串的集合,格式如:{aaabbbccc},{bbbddd},{eeefff},{ggg},{dddhhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaabbbcccdddhhh},{eeefff},{ggg}。
(1)请描述你解决这个问题的思路;
(2)请给出主要的处理流程,算法,以及算法的复杂度
(3)请描述可能的改进。
回答:
集合使用hash_set来表示,这样合并时间复杂度比较低。
1、给每个集合编号为0,1,2,3...
2、创建一个hash_map,key为字符串,value为一个链表,链表节点为字符串所在集合的编号。遍历所有的集合,将字符串和对应的集合编号插入到hash_map中去。
3、创建一个长度等于集合个数的int数组,表示集合间的合并关系。例如,下标为5的元素值为3,表示将下标为5的集合合并到下标为3的集合中去。开始时将所有值都初始化为-1,表示集合间没有互相合并。在集合合并的过程中,我们将所有的字符串都合并到编号较小的集合中去。
遍历第二步中生成的hash_map,对于每个value中的链表,首先找到最小的集合编号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。
4、现在合并关系数组中值为-1的集合即为最终的集合,它的元素来源于所有直接或间接指向它的集合。
算法的复杂度为O(n),其中n为所有集合中的元素个数。
1 package test; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.FileNotFoundException; 6 import java.io.FileReader; 7 import java.io.IOException; 8 import java.util.HashSet; 9 import java.util.Iterator; 10 import java.util.TreeMap; 11 import java.util.Vector; 12 13 public class StringSet { 14 public static int findRoot(int [] arr,int index){ 15 while(arr[index]>=0){ 16 index=arr[index]; 17 } 18 return index; 19 } 20 public static HashSet<String> mergeSet(HashSet<String> hashSet1,HashSet<String> hashSet2){ 21 Iterator<String> iterator=hashSet2.iterator(); 22 while(iterator.hasNext()){ 23 String string=iterator.next(); 24 if(!hashSet1.contains(string)){ 25 hashSet1.add(string); 26 } 27 } 28 return hashSet1; 29 } 30 public static void printSet(HashSet<String> hashSet){ 31 Iterator<String> iterator=hashSet.iterator(); 32 System.out.print("[ "); 33 while(iterator.hasNext()){ 34 String string=iterator.next(); 35 System.out.print(string+" ,"); 36 } 37 System.out.println(" ]"); 38 } 39 public static void main(String[] args) throws FileNotFoundException { 40 TreeMap<Integer, HashSet<String>> hashMap=new TreeMap<Integer, HashSet<String>>(); 41 BufferedReader br=new BufferedReader(new FileReader(new File("E:\\input.txt"))); 42 HashSet<String> hashSet=null; 43 TreeMap<String, Vector<Integer>> hm=new TreeMap<String, Vector<Integer>>(); 44 String line=null; 45 int nindex=0; 46 try { 47 while((line=br.readLine())!=null){ 48 String[] str=line.split(" "); 49 hashSet=new HashSet<String>(); 50 for(int i=0;i<str.length;i++){ 51 System.out.print(str[i]+" "); 52 if(!hm.containsKey(str[i])){ 53 Vector<Integer> v=new Vector<Integer>(); 54 v.add(nindex); 55 hm.put(str[i], v); 56 }else{ 57 hm.get(str[i]).add(nindex); 58 } 59 hashSet.add(str[i]); 60 } 61 System.out.println(); 62 hashMap.put(nindex++, hashSet); 63 } 64 } catch (IOException e) { 65 e.printStackTrace(); 66 } 67 System.out.println("合并后--------------------------------------------------"); 68 int k=nindex; 69 int []flag=new int[k]; 70 for(int i=0;i<k;i++){ 71 flag[i]=-1; 72 } 73 Iterator<String> it=hm.keySet().iterator(); 74 while (it.hasNext()) { 75 String s=it.next(); 76 Vector<Integer> vv=hm.get(s); 77 if(vv.size()>1){ 78 int root=findRoot(flag, vv.get(0)); 79 for(int p=1;p<vv.size();p++){ 80 flag[vv.get(p)]=root; 81 } 82 } 83 } 84 int resSetNum=0; 85 for(int j=0;j<k;j++){ 86 if(flag[j]==-1){ 87 resSetNum++; 88 } 89 } 90 for(int j=0;j<k;j++){ 91 if(flag[j]!=-1){ 92 mergeSet(hashMap.get(flag[j]), hashMap.get(j)); 93 hashMap.remove(j); 94 } 95 } 96 Iterator<Integer> its=hashMap.keySet().iterator(); 97 while(its.hasNext()){ 98 int key=its.next(); 99 printSet(hashMap.get(key)); 100 } 101 } 102 103 }