Java程序因某些测试用例超时而失败

时间:2019-10-20 08:55:51

标签: java performance collections java-8

我正在用Hackerrank练习。好吧,这个问题非常简单,我在此处通过示例输入将其附加。当我使用自定义输入运行到本地计算机时,其工作正常。但是,当我在其在线平台上运行时,有时2个,有时3个测试用例因超时异常而失败。代码在下面,任何人都可以提出需要改进的地方?

enter image description here

这是解决方案

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

3 个答案:

答案 0 :(得分:1)

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

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

    list.sort(Collections.reverseOrder());
    
  • 代码中涉及昂贵的方法调用,通常是 O(n 2 操作,即

    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();
}

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

当我仅按以下方式更改方法时,它就起作用了。

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;   
}