Hackerrank朋友圈查询算法

时间:2019-03-09 13:44:00

标签: java algorithm linked-list

我在HackerRank上遇到这个问题。 https://www.hackerrank.com/challenges/friend-circle-queries/problem 我尝试使用自定义链接列表-NodeList解决它。它具有三个字段-节点优先,节点当前,整数大小。 “ add”是重载的方法。它可以添加一个值或另一个NodeList。 我已经在注释中放入了NodeList的代码,因为这没关系。

字段:-

static HashMap<Integer, Integer> personToIndex = new HashMap<>();
static int largestCircleSize = 0;
static ArrayList<NodeList> groups = new ArrayList<>();

这是我的业务逻辑方法。 当只有一个人成为朋友圈的一部分时,我会将另一个人添加到圈子中。当两个握手的人已经属于其他圈子时,我合并了圈子。

static void updateFriendCircles(int friend1, int friend2) {
        int friend1Index, friend2Index;
        NodeList toUpdate;
        friend1Index = personToIndex.getOrDefault(friend1, -1);
        friend2Index = personToIndex.getOrDefault(friend2, -1);
        if (friend1Index != -1) {
            NodeList list = groups.get(friend1Index);
            if (friend2Index != -1) {
                NodeList list2 = groups.get(friend2Index);
                if (list.first == groups.get(friend2Index).first)
                    return;
                toUpdate = list.add(list2);
                groups.set(friend2Index, list);
            }
            else {
                toUpdate = list.add(friend2);
                personToIndex.put(friend2, friend1Index);
            }
        }
        else if (friend2Index != -1) {
            toUpdate = groups.get(friend2Index).add(friend1);
            personToIndex.put(friend1, friend2Index);
        }
        else {
            int index = groups.size();
            personToIndex.put(friend1, index);
            personToIndex.put(friend2, index);
            toUpdate = new NodeList(friend1).add(friend2);
            groups.add(toUpdate);
        }
        if (toUpdate.size > largestCircleSize)
            largestCircleSize = toUpdate.size;
 }

我也尝试过使用HashSet,但是它也有相同的问题,因此我认为问题不在数据结构中。

1 个答案:

答案 0 :(得分:1)

由于尚不清楚解决方案到底有什么问题(OP并未指定)-答案错误或某些测试用例的超时,我将解释如何解决。

我们可以使用disjoint set数据结构来表示朋友圈集。

基本思想是,在每个圆中,我们分配一个用于表示给定圆的成员。我们可以称其为根。在圈子中找到许多成员总是委派给存储其大小的根。

每个非root成员都指向其root成员或指向其可以成为root的成员。将来,当前的根也可能会失去其社区的根身份,但是它将指向新的根,因此始终可以通过链式调用来获得它。

2个圈子合并时,将从先前的2个成员中选择一个新的根成员。可以在其中设置新的尺寸,因为先前的根已经包含了两个圆的尺寸。但是如何选择新的根?如果圆1的大小不小于圆2的大小,则将其选作新的根。

因此,对于这个问题,首先我们应该为circlessizes定义占位符:

Map<Integer, Integer> people;
Map<Integer, Integer> sizes;

对于people中的非root成员,key是一个人的ID,value是他跟随的朋友(root或可以使他成为root的父母)。根成员在地图上不会有条目。

然后,我们需要一个将我们带到任何成员的根的方法:

int findCommunityRoot(int x) {
    if (people.containsKey(x)) {
        return findCommunityRoot(people.get(x));
    }
    return x;
}

最后,我们需要一种为2给定朋友的社区建立一个方法:

int mergeCommunities(int x, int y) {
    //find a root of x
    x = findCommunityRoot(x);
    //find a root of y
    y = findCommunityRoot(y);

    // one-man circle has a size of 1
    if (!sizes.containsKey(x)) {
        sizes.put(x, 1);
    }
    // one-man circle has a size of 1
    if (!sizes.containsKey(y)) {
        sizes.put(y, 1);
    }

    // friends in the same circle so just return its size
    if (x == y) {
        return sizes.get(x);
    }

    sizeX = sizes.get(x);
    sizeY = sizes.get(y);
    if (sizeX >= sizeY) { 
        people.put(y, x);
        sizes.put(x, sizeY + sizeX); 
        return sizes.get(x);
    } else {
        people.put(x, y);
        sizes.put(y, sizeY + sizeX); 
        return sizes.get(y);
    }
}

因此,我们拥有在每次迭代中保存最大圆的大小所需的一切:

List<Integer> maxCircle(int[][] queries) {
    List<Integer> maxCircles = new ArrayList<>();

    int maxSize = 1;
    for (int i = 0; i < queries.length; i++) {
        int size = mergeCommunities(queries[i][0], queries[i][1]);
        maxSize = Math.max(maxSize, size);
        maxCircles.add(maxSize);
    }

    return maxCircles;
}