从业务上抽离出来的问题。
条件:
假设有一个已知的list:
List<String> list= new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
……
假设每一个字母代表一个人,人与人之间有两种关系:相容与互斥。通过isFriendly(a,b)可以获得两人之间的关系。
一个朋友圈中所有人都必须相容,且无法再加入其他成员。
例如list有4个人A、B、C、D, AB互斥 其他均相容 ,则可以得到两个朋友圈{ACD} {BCD}
——————
求:如何得到所有不同的朋友圈?
思路1:将所有人两两组合,形成两人朋友圈,接着两人朋友圈尝试添加其他人,形成3人朋友圈……直至所有朋友圈无法加人:,剔除掉重复朋友圈后得到所有不同的朋友圈。
(思路1光想想就脑壳痛……而且当所有人相容的时候显得很傻比= =)
思路2: 设置核心人物,以核心人物为中心,找到包含该人物的所有朋友圈。
而与核心人物互斥的人,则形成另一个新的核心人物。
当不再产生新的核心人物,则可以得到所有的朋友圈。
如果还有其他思路欢迎大家指教。
思路2详解:
看到思路2的时候,也许会有疑问:此思路只能够找出核心人物的所有朋友圈,那如何保证非核心人物的所有朋友圈也已经找出呢?
我们假设核心为A,非核心人物B,AB相容组成一个朋友圈。此时,一个人物C有四种可能:1与A相容 2与A互斥 3与B相容 4与B互斥
于是有:
a、 当C与核心A相容,代表C也在核心A的朋友圈中,那么下一步很简单:与B相容, 那么形成ABC模式的3人朋友圈,与B互斥,那么形成AC朋友圈。
b、当C与核心A互斥,则代表C可以形成新的核心,以C为核心的朋友圈将会重新考虑与B的关系
由此可以看出,尽管以A为核心,B与C的关系也完全被考虑,加上D、E、F……等也是一样的
当核心人物与非核心人物都纳入考虑的时候,只要找出所有核心人物,即可找出所有朋友圈的关系。而这一点当然不难……在比较核心人物与所有非核心人物的时候,这个过程能自然而然的找出所有核心。
PS:一个核心只产生一个新的核心即可,因为第三个核心可以由第二个核心产生,这样可以一些减少重复的操作。
思路2实现:
1 public static void main(String[] args) { 2 3 List<String> list = new ArrayList<String>(); 4 list.add("A"); 5 list.add("B"); 6 list.add("C"); 7 list.add("D"); 8 list.add("E"); 9 10 11 List<String> linkList = new ArrayList<String>(); 12 int printIndex = 0; 13 14 //核心成员列表 15 List<String> coreItemList = new ArrayList<String>(); 16 //将第一个成员放入核心列表中 17 coreItemList.add(list.get(0)); 18 19 System.out.println("朋友圈寻链过程:"); 20 //循环核心列表 21 for(int i=0;i<coreItemList.size();i++){ 22 String coreItem = coreItemList.get(i); 23 24 //新核心是否已经产生 25 boolean isNewCoreCreat = false; 26 27 //链头列表 链头 = coreItem + 另一个其他成员 28 List<List<String>> itemLinkHeadList = new ArrayList<List<String>>(); 29 //还是链头列表,用于判断链头是否已经存在。String 链头 = coreItem,其他一个成员 30 List<String> itemLinkHeadValidateList = new ArrayList<String>(); 31 32 //将核心元素作为第一个链头 33 itemLinkHeadList.add(new ArrayList<String>(Arrays.asList(coreItem))); 34 itemLinkHeadValidateList.add(coreItem); 35 36 //循环链头 37 for(int j=0; j<itemLinkHeadList.size() ;j++){ 38 List<String> itemLinkHead = itemLinkHeadList.get(j); 39 40 //循环成员,用以检查 是否能够融入链中 41 for(String item:list){ 42 if(itemLinkHead.contains(item)){//不检验链头 43 continue; 44 } 45 46 //如果该成员能够融入链头中 47 if(isFriendly(itemLinkHead,item)){ 48 itemLinkHead.add(item); 49 }else{ 50 //检验能否与核心相容 51 if(isFriendly(coreItem,item)){//如果相容,则可以产生链头 52 //链头必须为新链头,避免重复计算 53 if(!itemLinkHeadValidateList.contains(coreItem+","+item)){ 54 itemLinkHeadValidateList.add(coreItem+","+item); 55 itemLinkHeadList.add(new ArrayList<String>(Arrays.asList(coreItem,item))); 56 } 57 }else{//无法与核心相容,该成员可形成新的核心 58 if(!isNewCoreCreat && !coreItemList.contains(item) && !isFriendly(coreItemList,item)){ 59 coreItemList.add(item); 60 isNewCoreCreat = true; 61 } 62 } 63 } 64 65 } 66 67 //链头itemLinkHead此刻已经完善为一条完整的朋友圈,可以放入结果集中 68 Collections.sort(itemLinkHead); 69 String itemLink = StringUtils.join(itemLinkHead, ","); 70 printIndex++; 71 System.out.println("第"+printIndex+"条:"+itemLink); 72 if(!linkList.contains(itemLink)){ 73 linkList.add(itemLink); 74 } 75 } 76 } 77 78 System.out.println("朋友圈已形成结果:"); 79 for(int i= 0,ilength = linkList.size();i<ilength;i++){ 80 System.out.println("第"+(i+1)+"条:"+linkList.get(i)); 81 } 82 83 } 84 85 /** 86 * 检验item是否能够融入链头itemLinkHead 87 * @param itemLinkHead 88 * @param item 89 * @return 90 */ 91 public boolean isFriendly(List<String> itemLinkHead,String item){ 92 for(String linkItem:itemLinkHead){ 93 if(!isFriendly(linkItem,item)){ 94 return false; 95 } 96 } 97 return true; 98 } 99 100 /** 101 * 检验a\b是否能够相容 102 * @param a 103 * @param b 104 * @return 105 */ 106 public boolean isFriendly(String a,String b){ 107 boolean flag = true; 108 if("A".equals(a) && "E".equals(b) || "A".equals(b) && "E".equals(a)){ 109 flag = false; 110 }else if("B".equals(a) && "C".equals(b) || "B".equals(b) && "C".equals(a)){ 111 flag = false; 112 }else if("B".equals(a) && "D".equals(b) || "B".equals(b) && "D".equals(a)){ 113 flag = false; 114 } 115 return flag; 116 } 117 118
代码中人物有A、B、C、D、E ;其中A、E互斥,B、C互斥,B、D互斥;其他相容。
运行结果如下:
朋友圈寻链过程:
第1条:A,B
第2条:A,C,D
第3条:A,C,D
第4条:A,B
第5条:B,E
第6条:C,D,E
第7条:C,D,E
第8条:B,E
朋友圈已形成结果:
第1条:A,B
第2条:A,C,D
第3条:B,E
第4条:C,D,E
可以看出,寻找的时候还是出现了重复的朋友圈。这是因为当AB组成链头去检查C、D的时候,由于C、D 均与B互斥,于是形成了 AC、AD两个新链头,最终两个链头都形成了ACD。这一点是无法避免的,所幸的是,在同一个核心里,最多产生list.size()-1个链头。
如有错误或者可以改进之处,欢迎大佬指出!
浙公网安备 33010602011771号