是什么可以使该代码更高效(针对Hackerrank问题)?

时间:2018-12-21 23:18:34

标签: java

请参阅我为解决hackerrank挑战而编写的这段代码。

https://www.hackerrank.com/challenges/frequency-queries/problem?h_l=interview&playlist_slugs%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D=dictionaries-hashmaps

基本上,到现在为止,我知道我的代码在算法上足够快,可以接受此挑战,因为我所做的完全是编辑部分中讨论的内容。但是,代码由于超时而终止。因此,我想知道我使用的数据结构是否存在明显的低效率,或者是否可能是内存问题或其他问题。另外,值得注意的是,社论是用C ++编写的,而我的代码是用Java编写的

我将描述发生的情况。查询是要执行的查询的列表。 countMap是一个HashMap,它将存储给定数字出现在数组中的次数。 freqMap是一个HashMap,用于存储数组中出现次数为x(键)次的数字实例数。因此,例如,如果将数字5加到数组中,则将1加到countMap中键5的值上。然后,如果countMap中键5的值现在为6,这意味着5在数组中出现6次,我将在freqMap中键6的值加1,因为数字在数组中出现6次。然后,如果查询碰巧检查数组中是否有确切数字出现过6次,则可以直接在freqMap中检查,如果键6上的值> 0,则将数字1添加到结果ArrayList中。否则,我在结果ArrayList中添加一个0。

static List<Integer> freqQuery(List<List<Integer>> queries) {

    HashMap<Integer,Integer> countMap = new HashMap();
    HashMap<Integer,Integer> freqMap = new HashMap();
    List<Integer> res = new ArrayList();
    for(int i = 0; i < queries.size(); i++){
        List<Integer> query = queries.get(i);
        Integer qType = query.get(0);
        Integer qVal = query.get(1);
        if(qType == 1){
            Integer countVal = countMap.get(qVal);
            if(countVal == null){
                countVal = new Integer(0);
            }
            countVal += 1;
            countMap.put(qVal,countVal);
            Integer freqVal = freqMap.get(countVal);
            if(freqVal == null){
                freqVal = new Integer(0);
            }
            freqVal += 1;
            freqMap.put(countVal,freqVal);
            if ((countVal - 1) > 0) {
                Integer prevFreqVal = freqMap.get(countVal - 1);
                prevFreqVal -= 1;
                freqMap.put((countVal -1),prevFreqVal);
            }
        }else if(qType == 2){
            Integer countVal = countMap.get(qVal);
            if(countVal != null && countVal != 0){
                countVal -= 1;
                countMap.put(qVal,countVal);
                Integer freqVal = freqMap.get(countVal);
                if(freqVal == null){
                    freqVal = new Integer(0);
                }
                freqVal += 1;
                freqMap.put(countVal,freqVal);
                Integer prevFreqVal = freqMap.get(countVal + 1);
                prevFreqVal -= 1;
                freqMap.put((countVal + 1),prevFreqVal);
            }
        }else if(qType == 3){
            Integer freqVal = freqMap.get(qVal);
            if(freqVal == null || freqVal < 1){
                res.add(0);
            }else{
                res.add(1);
            }
        }
    }
    return res;

}

所有结果都是正确的,但是出现超时错误,表明我的代码不够快。我不知道为什么会这样。

HashMap的获取和放置操作为O(1),一次遍历查询显然是O(q)。加到arraylist的末尾似乎是O(n),其中n是arraylist的长度。

2 个答案:

答案 0 :(得分:0)

愚蠢的我没有检查讨论部分,显然在查询中读取的样板代码太慢了,这主要是因为已经讨论过要使用List中的get()显然是O(n)复杂性。最重要的是,对于add()的结果,应该使用LinkedList而不是用于O(1)复杂度的ArrayList。

我所做的更改实际上是从List<List<Integer>>更改为List<int[]>,从而在恒定时间内访问查询和值。如果输入长度已知,我还可以通过简单地使用二维数组来获得更快的速度。

此外,在读取输入内容时,我会统计有多少查询需要我向结果列表中实际添加一个值,例如n,并将其传递给我的方法。有了这些知识,我就可以实例化一个数组int [n],然后也可以在恒定时间内将其添加到结果数组中。快得多

答案 1 :(得分:0)

更干净,更接近您的工作

static List<Integer> freqQuery(List<List<Integer>> queries) {
    Map<Integer, Integer> countMap = new HashMap<>();
    Map<Integer, Integer> freqMap = new HashMap<>();
    List<Integer> res = new LinkedList<>();
    for (List<Integer> query : queries) {
        Integer qType = query.get(0);
        Integer qVal = query.get(1);
        switch (qType) {
        case 1:
            Integer countVal = countMap.merge(qVal, 1, Integer::sum);
            freqMap.merge(countVal, 1, Integer::sum);
            freqMap.computeIfPresent(countVal - 1, (key, value) -> value - 1);
        case 2:
            countMap.computeIfPresent(qVal, (key, value) -> {
                freqMap.merge(value, -1, Integer::sum);
                freqMap.merge(value - 1, 1, Integer::sum);
                return value - 1;
            });
        case 3:
            Integer freqVal = freqMap.get(qVal);
            res.add(freqVal == null || freqVal < 1 ? 0 : 1);
        }
    }
    return res;
}