【问题标题】:Java Program getting failed with timeout for some test casesJava 程序因某些测试用例超时而失败
【发布时间】:2020-02-16 15:55:43
【问题描述】:

我在 Hackerrank 上练习。好吧,这个问题非常简单,我已将其附在此处并带有示例输入。当我使用自定义输入遇到本地机器时,它按预期工作。但是,当我在其在线平台上运行时,有时 2 有时 3 个测试用例因超时异常而失败。代码在下面,任何人都可以建议需要什么改进?

这就是解决办法

public static void main(String[] args) {
        int k = 3;
        List<Integer> marks = new ArrayList<Integer>();
        marks.add(20);
        marks.add(20);
        marks.add(40);
        marks.add(60);
        marks.add(20);
        marks.add(10);
        marks.add(0);
        marks.add(100);
        System.out.println(numofPrizes(k, marks));
    }
    public static int numofPrizes(int k, List<Integer> list) {
        // Write your code here
        Collections.sort(list, Collections.reverseOrder());
        List<Integer> str = new ArrayList<Integer>();
        AtomicInteger rank = new AtomicInteger(0);
        AtomicInteger count = new AtomicInteger(0);
        list.stream().forEach(x -> {
            if(!str.contains(x)){
                rank.getAndIncrement();
            }
            if(rank.get() <= k && x > 0){
                count.getAndIncrement();
            }
            str.add(x);
//          System.out.println("mark " + x + " rank " + rank.get() + " count " + count.get() );
        });
        return count.get();     
    }

输出:

mark 100 rank 1 count 1
mark 60 rank 2 count 2
mark 40 rank 3 count 3
mark 20 rank 4 count 3
mark 20 rank 4 count 3
mark 20 rank 4 count 3
mark 10 rank 5 count 3
mark 0 rank 6 count 3
3

【问题讨论】:

  • 也许我误解了问题,但结果不应该等于k或标记数(如果数组大小小于k)本身,不包括标记等于的人0?
  • 是的,纳曼,没错,见上面我已经更新了输出。
  • 好吧,我相信我确实误解了这个问题,而不是要截断的数字,我认为k 表示截断排名,然后评估将获得奖励的人数。在这种情况下,使用相同的输入,如果 k=4,结果将是 6。我说的对吗?
  • 是的,没错
  • 如答案中所述,您正在浪费时间进行不必要的排序,甚至更多的是缓慢的包含。我要补充一点,您正在滥用流来完成使用普通循环可以更快、更简单地完成的事情。

标签: java performance collections java-8


【解决方案1】:

您可以在可读性和性能方面改进的某些代码部分可能是:

  • 您可以使用List.sortList 的元素上精确使用API​​

    list.sort(Collections.reverseOrder());
    
  • 您的代码中有一个代价高昂的方法调用,通常是 O(n2) 操作,即

    if(!str.contains(x))
    

    此操作可能很有效,即在HashSet 上执行时O(n),但您也可以稍微优化额外的add 开销:

    Set<Integer> str = new HashSet<>();
    
    if (str.add(x)) {
        rank++; // or the use of getAndIncrement
    }
    
  • 在函数式编程构造中,您可以在以相反顺序对它们进行排序时考虑counting 的值,然后在执行相应计数的总和时限制输入中的排名截止

    private static int numofPrizes(int k, List<Integer> list) {
        Map<Integer, Integer> valueToCount = list.stream()
                .filter(mark -> mark != 0)
                .collect(Collectors.groupingBy(Function.identity(),
                        Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));
    
        return valueToCount.entrySet().stream()
                .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
                .limit(k)
                .mapToInt(Map.Entry::getValue)
                .sum();
    }
    

    请注意,groupingBy here is an O(n) operation 再次和这个完整的逻辑可以合并到一个管道中,如下所示:


private static long numOfPrizes(int k, List<Integer> list) {
    return list.stream()
            .filter(mark -> mark != 0)
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet().stream()
            .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
            .limit(k)
            .mapToLong(Map.Entry::getValue)
            .sum();
}

【讨论】:

  • 注意:不要只是尝试使用此处发布的最终代码。我还没有针对您一直使用的运行时测试它的效率。请注意,有一个建议可以优化当前代码中的内容。另一方面,首先要考虑是否有比当前方法更好的方法。
  • 感谢笔记和解释。
【解决方案2】:

从这个意义上也可以认为,如果输入在输入数组/列表的大小方面可以很大,我们应该尽可能避免对其进行排序。

在这里,由于标记只能有 100 个唯一值,我们可以利用这一事实,制作标记与出现次数的排序映射。这将花费 O(n) 时间。 或 O(n log n) 时间对地图进行排序(最多只有 100 个条目)

关键是避免对大型数据集进行排序并通过复制较大的数据集来创建新的大型数据集。

【讨论】:

  • 在您的巧妙解决方案中不需要地图,长度为 101 的数组可以用于此直方图。单次遍历输入以填充它,单次遍历直方图以获得答案。
  • 使用数组会更好。标记 56 的出现次数将存储在数组的第 57 个元素中(索引 = 56)。节省更多精力。
【解决方案3】:

当我像下面这样改变方法时,它起作用了。

public static void main(String[] args) {
    int k = 3;
    List<Integer> marks = new ArrayList<Integer>();
    marks.add(20);
    marks.add(20);
    marks.add(40);
    marks.add(60);
    marks.add(20);
    marks.add(10);
    marks.add(0);
    marks.add(100);
    System.out.println(numofPrizes(k, marks));
}
public static int numofPrizes(int k, List<Integer> list) {
              list.sort(Collections.reverseOrder());
      int number = 0,counter = 1;
      int[] mark = new int[list.size()],rank = new int[list.size()];
      Map<Integer,Integer> map  = new HashMap<Integer,Integer>();   
      for (int i = 0; i < list.size(); i++) {
              map.put(list.get(i), (map.get(list.get(i)) != null) ? map.get(list.get(i)) : counter);
              mark[i] = list.get(i);
              rank[i] = (int) map.get(list.get(i));
              counter++;
              if(mark[i] > 0 && k >= rank[i]){
                      number++;
              }
      }          
      return number;   
}

【讨论】:

    猜你喜欢
    • 2017-10-08
    • 1970-01-01
    • 2022-11-03
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    相关资源
    最近更新 更多