从圈子中找到一小群朋友?

时间:2019-01-24 23:56:21

标签: java algorithm data-structures hashmap

我正在解决以下问题:

  

在与人共处的房间中,我们将定义两个人,如果他们是朋友   是直接或间接的朋友。如果A是B的朋友,而B是   是C的朋友,那么A也是C的朋友。一群朋友是一个   该组中的任何两个人都是朋友的一组人。给定   直接是朋友的人的名单,找到最小的一群   的朋友。

示例: 输入:

1<->6 
2<->7
3<->8
4<->9
2<->6
3<->5

组:

1-6-2-7
3-8-5
4-9

最小组中的人数为2,即4-9,因此我们应该返回2。

我想出了以下代码,但是现在我不明白如何使用此holder映射来获取所需的输出。我有点困惑。解决此问题的最佳方法是什么?

  private static int findGroups(final List<List<Integer>> inputs) {
    if (inputs == null || inputs.isEmpty()) {
      return 0;
    }
    int count = Integer.MAX_VALUE;

    Map<Integer, List<Integer>> holder = new HashMap<>();
    for (List<Integer> input : inputs) {
      // storing it in bidirectional way in the map
      List<Integer> l =
          holder.containsKey(input.get(0)) ? holder.get(input.get(0)) : new ArrayList<Integer>();
      l.add(input.get(1));
      holder.put(input.get(0), l);

      List<Integer> l1 =
          holder.containsKey(input.get(1)) ? holder.get(input.get(1)) : new ArrayList<Integer>();
      l1.add(input.get(0));
      holder.put(input.get(1), l1);
    }
    System.out.println(holder);

    // use holder map to get the smaller group here?

    return count;
  }

好像我需要在这里使用递归来获得较小的组?

2 个答案:

答案 0 :(得分:8)

  

有没有更好的方法来解决这个问题?

更好的方法是使用disjoint-set data structure

  • 首先,将“朋友组”计算为不相交的数据结构:
    • 初始化一个不相交的数据结构,其中的元素将是房间中的人。
    • 对于房间中的每个人 p
      • 调用 MakeSet p )初始化仅包含该人的“朋友组”。
    • 对于每个直接友谊 p 1 p 2
      • 致电 Union p 1 p 2 )以统一包含 p 1 的“一群朋友”和包含 p 2 的朋友。
  • 接下来,以地图的形式计算“朋友组”的大小:
    • 初始化一张地图,其中的钥匙将是房间中的一些人(即,他们各自的“朋友组”的代表),值将是数字(即,各个“朋友组”的大小“)。
    • 对于房间中的每个人 p 1
      • 致电 Find p 1 )查找代表 p 2 该人的“朋友组”中的一个。
      • 如果地图尚未包含键 p 2 的值,请为该键插入值0。
      • 增加键 p 2 的值。
  • 最后,计算结果:
    • 将结果初始化为较大的值,例如房间里的人数。
    • 对于地图中的每个值(=“一组朋友”的大小):
      • 如果该值小于结果,则将结果设置为等于该值。
    • 返回结果。

顺便说一句,您正在执行的操作的技术名称是 transitive closure :“是朋友”关系是“是直接朋友”关系的传递闭包。 (但是,维基百科文章中描述的算法并不是针对您的问题的最佳算法,因为它们没有利用您的关系为symmetric的事实。)

答案 1 :(得分:0)

这是一些代码,出于对您问题的好奇,我已经写了。我对图了解不多,但是它像您所要求的那样使用递归。

基本上,您会检查输入内容,并为每个人创建一个ArrayList<Integer>。在那个阵列中是那个人的直接朋友的人。例如,对于1: {6}, for 2: {7, 6}, for 3: {8, 5}。然后,要获得人2的所有所有朋友,请通过将人7和6的数组(不包括重复项)聚集在一起来创建一个ArrayList<Integer>数组。因此,可以以某种方式使用递归,即函数getAllFriends(Integer person)也必须为该人的直接朋友返回getAllFriends(Integer person2)

因此,代码看起来像这样:

public class Test  {
        public static void main(String[] args) throws Exception {
            String input = "1<->6\n" +
            "2<->7\n" +
            "3<->8\n" +
            "4<->9\n" +
            "2<->6\n" +
            "3<->5";

            HashMap<Integer, ArrayList<Integer>> friends = processInput(input);  //getting data from the input string and storing it in a structured way
            System.out.println(getAllFriends(1, friends, new ArrayList<Integer>(){{add(1);}}));  //output: [1, 6, 2, 7]. Double brackets create an anonymous inner class, you add to the result the id of a person whose friends you're collecting
            }

        public static HashMap<Integer, ArrayList<Integer>> processInput(String input) throws Exception  {
            HashMap<Integer, ArrayList<Integer>> result = new HashMap<>();

            BufferedReader bufReader = new BufferedReader(new StringReader(input));
            String line=null;
            while( (line=bufReader.readLine()) != null )
            {
                Integer personLeft =  Integer.valueOf(line.substring(0, line.indexOf("<")));
                Integer personRight =Integer.valueOf(line.substring(line.indexOf(">")+1, line.length()));

                System.out.println(personLeft + ": " + personRight);

                if (!result.containsKey(personLeft))  {
                    result.put(personLeft, new ArrayList<Integer>());
                }

                result.get(personLeft).add(personRight);

                if (!result.containsKey(personRight))  {
                    result.put(personRight, new ArrayList<Integer>());
                }

                result.get(personRight).add(personLeft);
            }


            return result;

        }

        public static ArrayList<Integer>  getAllFriends(Integer person, HashMap<Integer, ArrayList<Integer>> friends, ArrayList<Integer> result)  {
            for (Integer personFriend: friends.get(person))  {
                    if (!result.contains(personFriend))  {
                        result.add(personFriend);  //add a person, if it wasn't added before
                        getAllFriends(personFriend, friends, result);  //check out that person's friends
                    }
            }

            return result;
        }
}