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

相关推荐
爱上语文1 小时前
Java LeetCode每日一题
java·开发语言·leetcode
大二转专业6 小时前
408算法题leetcode--第24天
考研·算法·leetcode
__AtYou__12 小时前
Golang | Leetcode Golang题解之第448题找到所有数组中消失的数字
leetcode·golang·题解
转调13 小时前
每日一练:地下城游戏
开发语言·c++·算法·leetcode
huanxiangcoco14 小时前
152. 乘积最大子数组
python·leetcode
希望有朝一日能如愿以偿15 小时前
力扣题解(飞机座位分配概率)
算法·leetcode·职场和发展
Espresso Macchiato16 小时前
Leetcode 3306. Count of Substrings Containing Every Vowel and K Consonants II
leetcode·滑动窗口·leetcode medium·leetcode 3306·leetcode周赛417
数据分析螺丝钉17 小时前
力扣第240题“搜索二维矩阵 II”
经验分享·python·算法·leetcode·面试
￴ㅤ￴￴ㅤ9527超级帅17 小时前
LeetCode hot100---数组及矩阵专题(C++语言)
c++·leetcode·矩阵
鱼跃鹰飞18 小时前
Leecode热题100-295.数据流中的中位数
java·服务器·开发语言·前端·算法·leetcode·面试