用于比较同一列表中的元素的高效算法

时间:2017-11-14 04:02:18

标签: java algorithm

我有一个BaseBallGame对象列表,包含开始和结束时间。我需要确保每个游戏都在一个单独的时间发生,以便用户可以观看所有游戏的直播。

我的算法为O(n^2)。我需要至少让它成为nlog(n)。 有人能指点我们如何改善我的实现性能吗?

public class GameTime {

    public static Boolean canViewAll(Collection<BaseBallGame> baseBallGames) {

        List<BaseBallGame> games_list = (List<BaseBallGame>) baseBallGames;
        boolean isOverlap = false;

        for (int i = 0; i < games_list(); i++) {

            for (int j = i + 1; j < games_list(); j++) {

                Date startA = games_list(i).getStart();
                Date endA = games_list(i).getEnd();
                Date startB = games_list(j).getStart();
                Date endB = games_list(j).getEnd();

                boolean isStartABeforeEndB = (startA.compareTo(endB)) < 0;
                boolean isEndAAfterStartB = (endA.compareTo(startB)) > 0;

                boolean isCurrentPairOverlap = false;

                isCurrentPairOverlap = isStartABeforeEndB && isEndAAfterStartB;

                if (isCurrentPairOverlap) {
                    isOverlap = true;
                }
            }
        }
        return !isOverlap;
    }

    boolean overlap(Date start1, Date end1, Date start2, Date end2){
        return start1.getTime() <= end2.getTime() && start2.getTime() <= end1.getTime();
    }

    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("y-M-d H:m");

        ArrayList<BaseBallGame> baseBallGames = new ArrayList<BaseBallGame>();
        baseBallGames.add(new BaseBallGame(sdf.parse("2015-01-01 20:00"), sdf.parse("2015-01-01 21:30")));
        baseBallGames.add(new BaseBallGame(sdf.parse("2015-01-01 21:30"), sdf.parse("2015-01-01 23:00")));
        baseBallGames.add(new BaseBallGame(sdf.parse("2015-01-01 23:10"), sdf.parse("2015-01-01 23:30")));

        System.out.println(GameTime.canViewAll(baseBallGames));
    }
}

class BaseBallGame {
    private Date start, end;

    public BaseBallGame(Date start, Date end) {
        this.start = start;
        this.end = end;
    }

    public Date getStart() {
        return this.start;
    }

    public Date getEnd() {
        return this.end;
    } 

}

5 个答案:

答案 0 :(得分:5)

您正在描述Activity Selection Problem

  1. 根据完成时间对列表进行排序。
  2. 迭代列表并检查A[i+1]的开始时间是否大于A[i]的结束时间。
  3. 由于它涉及排序,因此它有一个O(n log n)

答案 1 :(得分:1)

如果您使用Comparator对列表进行排序,然后在列表中迭代一次并查看是否有任何重叠,该怎么办?

  

Java Array Sorting Algorithm:java.util.Arrays对实现Comparable或使用Comparator的对象使用mergesort。

Merge sort算法是平均/最佳/最差情况nlog(n)。然后,一次迭代可以忽略不计。

答案 2 :(得分:0)

有许多排序算法,您可以在代码中实现它们。网站上的以下排序算法已经实施,并且还显示了时间复杂度。

https://www.toptal.com/developers/sorting-algorithms

Quicksort和Quicksort 3路分区是nlogn算法。

答案 3 :(得分:0)

如果您只是想检查是否存在冲突,那么您可以尝试

Set<BaseBallGame> baseBallGameSet = new HashSet<BaseBallGame>(games_list);
if(baseBallGameSet.size < games_list.size)
  // Clash exists.

您可以在@thebenman建议之前将其视为优化。

答案 4 :(得分:0)

适应此问题的最有效算法是区间搜索树。你有开始时间和结束时间,意味着你有一个间隔。一旦你的游戏开始,如果它没有与其他游戏的时间重叠,那么把它放在树上。当你开始一个新游戏,然后把游戏时间放在一起,如果它与前一个游戏的时间重叠,那么树将报告,因为它有一个间隔。

树看起来像这样: enter image description here

不是每次都检查新游戏,而是将所有间隔放在树中,如果它与另一个间隔相交,那么树数据结构将自动检测并报告它。这种插入和删除算法的时间复杂度是~logN,这是非常有效的。如果您有R个交叉点,那么复杂性将是~RlogN,其中R是交叉点的数量。

您还可以关注robert sedgewick here的视频。