leetcode-最大的团队表现值

 题目是LeetCode第180场周赛的第四题,链接:最大的团队表现值。具体描述为:公司有编号为 1 到 n 的 n 个工程师,给你两个数组 speed 和 efficiency ,其中 speed[i] 和 efficiency[i] 分别代表第 i 位工程师的速度和效率。请你返回由最多 k 个工程师组成的 ​​​​​​最大团队表现值 ,由于答案可能很大,请你返回结果对 10^9 + 7 取余后的结果。团队表现值 的定义为:一个团队中「所有工程师速度的和」乘以他们「效率值中的最小值」。

 示例1:

输入:n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 2
输出:60
解释:
我们选择工程师 2(speed=10 且 efficiency=4)和工程师 5(speed=5 且 efficiency=7)。他们的团队表现值为 performance = (10 + 5) * min(4, 7) = 60 。

 示例2:

输入:n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 3
输出:68
解释:
此示例与第一个示例相同,除了 k = 3 。我们可以选择工程师 1 ,工程师 2 和工程师 5 得到最大的团队表现值。表现值为 performance = (2 + 10 + 5) * min(5, 4, 7) = 68 。

 示例3:

输入:n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 4
输出:72

 这是个hard难度的题目,一开始也是以为就是个动态规划的公式,陷了进去愣是找不到递推公式。后来比赛结束后才在评论区看到这压根就不是动态规划的题目,而是贪心算法。。。

 因为效率取决于k个人中的最小效率,所以直接对效率降序排序(此时对应的速度也会被排序),那么可以看到,只要指定最小效率为降序数组的第i个效率,那么当前最大团队表现值就一定是前面的min(k, i)个最大speed之和乘以这个最小效率,也就是说,只需遍历一遍降序数组就可以得到结果了。具体过程为:

  • 对于一个二维数组(speed, efficiency)按efficiency降序排序得到s
  • 初始化一个大小为k的最小堆topk用以维护k个最大speed
  • 对于前k个efficiency,直接将speed加入最小堆,同时统计全部speed之和totalSpeed,更新最大团队表现值
  • 对于k个之后的efficiency,只有当对应的speed小于k个speed中的最小值(即堆顶元素)时才有必要继续更新totalSpeed以及最大团队表现值,否则可以跳过

 因为排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),遍历过程则只需要 O ( n l o g k ) O(nlogk) O(nlogk) l o g k logk logk为将数据加入最小堆所需时间),所以总的时间复杂度为 O ( n l o g n ) + O ( n l o g k ) O(nlogn)+O(nlogk) O(nlogn)+O(nlogk),空间复杂度为 O ( n ) O(n) O(n)(存储排序后数据)。

 JAVA版代码如下:

class Solution {
    public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
        int[][] speedAndEff = new int[n][2];
        for (int i = 0; i < n; ++i) {
            speedAndEff[i][0] = speed[i];
            speedAndEff[i][1] = efficiency[i];
        }
        Arrays.sort(speedAndEff, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o2[1] - o1[1];
            }
        });

        Queue topk = new PriorityQueue<Integer>(k);
        long maxResult = 0, totalSpeed = 0;
        for (int i = 0; i < k; ++i) {
            topk.offer(speedAndEff[i][0]);
            totalSpeed += speedAndEff[i][0];
            maxResult = Math.max(maxResult, totalSpeed * speedAndEff[i][1]);
        }
        for (int i = k; i < n; ++i) {
            if (speedAndEff[i][0] > (int)topk.peek()) {
                totalSpeed = totalSpeed - (int)topk.poll() + speedAndEff[i][0];
                topk.offer(speedAndEff[i][0]);
                maxResult = Math.max(maxResult, totalSpeed * speedAndEff[i][1]);
            }
        }
        return (int)(maxResult % 1000000007);
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int:
        speedAndEff = list(zip(speed, efficiency))              #组成(speed, efficiency)
        speedAndEff.sort(key=lambda x : x[1], reverse=True)     #按efficiency降序排序

        import heapq
        topk = []
        maxResult, totalSpeed = 0, 0
        for i in range(k):                                      #前k个全部加入最小堆中,同时计算最大表现值(可以小于k个人)
            heapq.heappush(topk, speedAndEff[i][0])
            totalSpeed += speedAndEff[i][0]
            maxResult = max(maxResult, totalSpeed * speedAndEff[i][1])

        for i in range(k, n):                                   #对于k个之后的,只有speed大于当前最小speed的才有必要继续计算
            if speedAndEff[i][0] > topk[0]:
                totalSpeed = totalSpeed - topk[0] + speedAndEff[i][0]
                heapq.heapreplace(topk, speedAndEff[i][0])
                maxResult = max(maxResult, totalSpeed * speedAndEff[i][1])
        
        return maxResult % 1000000007

 提交结果如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值