LeetCode 1402. 做菜顺序:排序 + 二分查找 + 前缀(贪心) - 按思路讲解

【LetMeFly】1402.做菜顺序:排序 + 二分查找 + 前缀(贪心) - 按思路讲解

力扣题目链接:https://leetcode.cn/problems/reducing-dishes/

一个厨师收集了他 n 道菜的满意程度 satisfaction ,这个厨师做出每道菜的时间都是 1 单位时间。

一道菜的 「喜爱时间」系数定义为烹饪这道菜以及之前每道菜所花费的时间乘以这道菜的满意程度,也就是 time[i]*satisfaction[i]

请你返回做完所有菜 「喜爱时间」总和的最大值为多少。

你可以按 任意 顺序安排做菜的顺序,你也可以选择放弃做某些菜来获得更大的总和。

示例 1:

复制代码
输入:satisfaction = [-1,-8,0,5,-9]
输出:14
解释:去掉第二道和最后一道菜,最大的喜爱时间系数和为 (-1*1 + 0*2 + 5*3 = 14) 。每道菜都需要花费 1 单位时间完成。

示例 2:

复制代码
输入:satisfaction = [4,3,2]
输出:20
解释:按照原来顺序相反的时间做菜 (2*1 + 3*2 + 4*3 = 20)

示例 3:

复制代码
输入:satisfaction = [-1,-4,-5]
输出:0
解释:大家都不喜欢这些菜,所以不做任何菜可以获得最大的喜爱时间系数。

提示:

  • n == satisfaction.length
  • 1 <= n <= 500
  • -1000 <= satisfaction[i] <= 1000

方法一:排序 + 二分查找 + 前缀(贪心)

假设选了一个做菜序列 [ a , b , c , d , ⋯   ] [a,b,c,d,\cdots] [a,b,c,d,⋯],那么很容易想到这道题的关键:菜开始的越晚权重越大。因此本题的核心思路(贪心)是:satisfaction越高的菜越往后放

二话不说,先排个序 吧。反正satisfaction为正的菜是一定要做的(只有好处没有坏处),所以就二分查找一下排序后第一个satisfaction为正的菜的位置positiveLocation,从positiveLocation到数组末尾的"正菜"先依次加入到做菜序列中。

好了,"正菜"处理完了,那么"负菜"就一无是处了吗?当然不是。每往做菜序列前面增加一道菜品,后面每道菜的权重都会加一。也就是说,在现在的做菜序列基础上,每新加一道负菜,总分的变化是"正菜satisfaction之和 加上 负菜satisfaction之和"(含新增的负菜。

那么到底怎么处理负菜呢?只需要统计一下"正菜satisfaction之和sumPositive",以及加上这道负菜的话"负菜satisfaction之和sumNegative",如果 a b s ( s u m P o s i t i v e ) > = a b s ( s u m N e g a t i v e ) abs(sumPositive) >= abs(sumNegative) abs(sumPositive)>=abs(sumNegative),那么就将这道菜加入到做菜序列之首,否则就不加。

对于同为负数的两道菜,当然是优先选择较大的那个负数菜喽(能选 − 1 -1 −1不选 − 2 -2 −2)。

  • 时间复杂度 O ( n × log ⁡ n ) O(n\times \log n) O(n×logn)。排序的时间复杂度是 n log ⁡ n n\log n nlogn,二分(只二分了一次)的时间复杂度为 log ⁡ n \log n logn,选菜的总时间复杂度不超过 O ( n ) O(n) O(n)。其中 n = l e n ( s a t i s f a c t i o n ) n=len(satisfaction) n=len(satisfaction)。
  • 空间复杂度 O ( log ⁡ n ) O(\log n) O(logn)。排序的空间复杂度为 O ( log ⁡ n ) O(\log n) O(logn),其余部分空间复杂度都为 O ( 1 ) O(1) O(1)。

AC代码

C++
cpp 复制代码
class Solution {
public:
    int maxSatisfaction(vector<int>& satisfaction) {
        sort(satisfaction.begin(), satisfaction.end());
        int positiveLocation = upper_bound(satisfaction.begin(), satisfaction.end(), 0) - satisfaction.begin();
        int ans = 0, sumPositive = 0;
        for (int i = positiveLocation; i < satisfaction.size(); i++) {
            ans += (i - positiveLocation + 1) * satisfaction[i];
            sumPositive += satisfaction[i];
        }
        int sumNegative = 0;
        for (int i = positiveLocation - 1; i >= 0; i--) {
            sumNegative += satisfaction[i];
            if (-sumNegative > sumPositive) {
                break;
            }
            ans += sumPositive + sumNegative;
        }
        return ans;
    }
};
Python
python 复制代码
# from typing import List
# from bisect import bisect_right


class Solution:
    def maxSatisfaction(self, satisfaction: List[int]) -> int:
        satisfaction.sort()
        positiveLocation = bisect_right(satisfaction, 0)
        ans, sumPositive = 0, 0
        for i in range(positiveLocation, len(satisfaction)):
            ans += (i - positiveLocation + 1) * satisfaction[i]
            sumPositive += satisfaction[i]
        sumNegative = 0
        for i in range(positiveLocation - 1, -1, -1):
            sumNegative += satisfaction[i]
            if -sumNegative > sumPositive:
                break
            ans += sumPositive + sumNegative
        return ans

同步发文于CSDN,原创不易,转载经作者同意后请附上原文链接哦~

Tisfy:https://letmefly.blog.csdn.net/article/details/133974648

相关推荐
清炒孔心菜8 小时前
每日一题 LCR 078. 合并 K 个升序链表
leetcode
茶猫_10 小时前
力扣面试题 - 25 二进制数转字符串
c语言·算法·leetcode·职场和发展
一直学习永不止步13 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
Rstln14 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展
珹洺14 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
几窗花鸢14 小时前
力扣面试经典 150(下)
数据结构·c++·算法·leetcode
Lenyiin19 小时前
02.06、回文链表
数据结构·leetcode·链表
烦躁的大鼻嘎19 小时前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode
祁思妙想20 小时前
10.《滑动窗口篇》---②长度最小的子数组(中等)
leetcode·哈希算法
alphaTao21 小时前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode