逍遥小师叔

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

从业务上抽离出来的问题。

条件:

假设有一个已知的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个链头。

 

如有错误或者可以改进之处,欢迎大佬指出!

 

 

  

 

    

        

 

posted on 2019-03-05 17:26  逍遥小师叔  阅读(560)  评论(0)    收藏  举报