LeetCode#1086. High Five

1086. High Five

Example 1:

Input: items =
[[1,91],[1,92],[2,93],[2,97],[1,60],[2,77],[1,65],[1,87],[1,100],[2,100],[2,76]]
Output: [[1,87],[2,88]] Explanation: The student with ID = 1 got
scores 91, 92, 60, 65, 87, and 100. Their top five average is (100 +
92 + 91 + 87 + 65) / 5 = 87. The student with ID = 2 got scores 93,
97, 77, 100, and 76. Their top five average is (100 + 97 + 93 + 77 +
76) / 5 = 88.6, but with integer division their average converts to
88.

Approach 1: Using Sorting

Intuition

Since we have to take into account the top 5 values corresponding to each id, we can sort the items array, first based on the id and next based on the score, i.e. items will be sorted based on increasing order of their ids. In case we have a tie for the value of ids, the items are then sorted based on decreasing order of the scores.

Algorithm

We can implement the idea for Approach 1 simply by having a custom comparator, which sorts the array based on the increasing order of ids and in case of tie, with the decreasing order of scores.

Below is the implementation of this approach.

[Java]

class Solution {

    private int K;

    public int[][] highFive(int[][] items) {
        this.K = 5;
        Arrays.sort(
                items,
                new Comparator<int[]>() {
                    @Override
                    public int compare(int[] a, int[] b) {
                        if (a[0] != b[0])
                            // item with lower id goes first
                            return a[0] - b[0];
                        // in case of tie for ids, item with higher score goes first
                        return b[1] - a[1];
                    }
                });
        List<int[]> solution = new ArrayList<>();
        int n = items.length;
        int i = 0;
        while (i < n) {
            int id = items[i][0];
            int sum = 0;
            // obtain total using the top 5 scores
            for (int k = i; k < i + this.K; ++k)
                sum += items[k][1];
            // ignore all the other scores for the same id
            while (i < n && items[i][0] == id)
                i++;
            solution.add(new int[] {id, sum / this.K});
        }
        int[][] solutionArray = new int[solution.size()][];
        return solution.toArray(solutionArray);
    }
}
Approach 2: Using Map and Max Heap

Intuition

We can notice here that the only scores that contribute towards the calculation of the average are the top 5 scores. Therefore, if we only need the top 5 scores for each of the id we can ignore the rest of the scores. This can be done using a max heap.

Algorithm

We can maintain a max heap of all the scores for every id. This way, we can simply obtain the top 5 scores for each of the id by obtaining the first 5 elements from the max heap (which are indeed the top 5). Additionally, we would also need a map where the id of the student will be used as the key (as we want scores for the same id to be clubbed together in the same max heap).

Note that we’ll be using an ordered map (or a tree map) in this case as we want the final output scores to be in sorted order (which we can obtain by directly iterating over the keys of the map).

Below is the implementation of this approach.
[Java]

class Solution {
    private int K;

    public int[][] highFive(int[][] items) {
        this.K = 5;
        TreeMap<Integer, Queue<Integer>> allScores = new TreeMap<>();
        for (int[] item : items) {
            int id = item[0];
            int score = item[1];
            if (!allScores.containsKey(id))
                // max heap
                allScores.put(id, new PriorityQueue<>((a,b) -> b - a));
            // Add score to the max heap
            allScores.get(id).add(score);
        }

        List<int[]> solution = new ArrayList<>();

        for (int id : allScores.keySet()) {
            int sum = 0;
            // obtain the top k scores (k = 5)
            for (int i = 0; i < this.K; ++i)
                sum += allScores.get(id).poll();
            solution.add(new int[] {id, sum / this.K});
        }
        int[][] solutionArray = new int[solution.size()][];
        return solution.toArray(solutionArray);
    }
}
Approach 3: Using Map and Min Heap

Intuition

Till now, we have used a max heap using which we can obtain the top 5 elements by simply popping them out of the max heap one by one. However, for this, we have to store all the scores for each id in the max heap. This is inefficient. Since we are only interested in obtaining the top 5 scores, we do not need to store all the scores.

This can be made efficient using a min heap. In this approach, we will keep a min heap of the top 5 scores for each of the id. Whenever we encounter a score for an id, which is greater than the minimum score present in the min heap of that particular id, we update our min heap by adding the current score and removing the minimum score. This way, the size of the min heap never exceeds 5 which is a much more efficient implementation than keeping all the scores in the heap.

Algorithm

For each of the id, we can keep inserting all the scores in the corresponding min heap. Whenever we reach a state where the size of the min heap exceeds 5, we’ll simply remove the minimum element from the min heap, thereby making sure that the size of the min heap never exceeds 5.

Below is the implementation of this approach.
[Java]

class Solution {
    private int K;

    public int[][] highFive(int[][] items) {
        this.K = 5;
        TreeMap<Integer, Queue<Integer>> allScores = new TreeMap<>();
        for (int[] item : items) {
            int id = item[0];
            int score = item[1];
            if (!allScores.containsKey(id))
                allScores.put(id, new PriorityQueue<>());
            // insert the score in the min heap
            allScores.get(id).add(score);
            // remove the minimum element from the min heap in case the size of the min heap exceeds 5 
            if (allScores.get(id).size() > this.K)
                allScores.get(id).poll();
        }

        List<int[]> solution = new ArrayList<>();

        for (int id : allScores.keySet()) {
            int sum = 0;
            // min heap contains the top 5 scores
            for (int i = 0; i < this.K; ++i)
                sum += allScores.get(id).poll();
            solution.add(new int[] {id, sum / this.K});
        }
        int[][] solutionArray = new int[solution.size()][];
        return solution.toArray(solutionArray);
    }
}
Approach 4: Using priority queue for each id

[Python]

class Solution:
    def highFive(self, items: List[List[int]]) -> List[List[int]]:
        d = collections.defaultdict(list)
        
        for idx, val in items:
            heapq.heappush(d[idx], val)
            
            if len(d[idx]) > 5:
                heapq.heappop(d[idx])
        
        res = [[i, sum(d[i]) // len(d[i])] for i in sorted(d)]
        
        return res
Approach 5: Running Length Encoding

first sort reversely by id and score, and then calculate average for each id
[Python]

class Solution:
    def highFive(self, items: List[List[int]]) -> List[List[int]]:
        items.sort(reverse=True)
        
        res = []
        curr = []
        idx = items[0][0]
        
        for i, val in items:
            if i == idx:
                if len(curr) < 5:
                    curr.append(val)
            else:
                res.append([idx, sum(curr) // len(curr)])
                curr = [val]
                idx = i
        
        res.append([idx, sum(curr) // len(curr)])
        
        res = res[::-1]
        
        return res
Approach 6: Using priority queue for each id

[Python]

class Solution(object):
    def highFive(self, items):
        res = {}
        for i in items:
            if i[0] in res:
                res[i[0]].append(i[1])
                res[i[0]] = sorted(res[i[0]], reverse=True)
            else:
                res[i[0]] = [i[1]]
        return [[i,sum(res[i][:5])/5] for i in res.keys()]  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值