Medium

题目描述

给你一个大小为 n 的整数数组 pizzas,其中 pizzas[i] 表示第 i 个披萨的重量。每天你恰好吃 4 个披萨。由于你惊人的新陈代谢,当你吃重量为 W、X、Y 和 Z 的披萨时,其中 W <= X <= Y <= Z,你只会增加 1 个披萨的重量!

  • 在奇数天(从 1 开始索引),你增加重量 Z。
  • 在偶数天,你增加重量 Y。

通过最优地吃掉所有披萨,找到你能获得的最大总重量。

注意:保证 n 是 4 的倍数,每个披萨只能吃一次。

示例 1:

输入:pizzas = [1,2,3,4,5,6,7,8]
输出:14
解释:
第 1 天,你吃索引为 [1, 2, 4, 7] 的披萨 = [2, 3, 5, 8]。你增加重量 8。
第 2 天,你吃索引为 [0, 3, 5, 6] 的披萨 = [1, 4, 6, 7]。你增加重量 6。
吃掉所有披萨后获得的总重量是 8 + 6 = 14。

示例 2:

输入:pizzas = [2,1,1,1,1,1,1,1]
输出:3
解释:
第 1 天,你吃索引为 [4, 5, 6, 0] 的披萨 = [1, 1, 1, 2]。你增加重量 2。
第 2 天,你吃索引为 [1, 2, 3, 7] 的披萨 = [1, 1, 1, 1]。你增加重量 1。
吃掉所有披萨后获得的总重量是 2 + 1 = 3。

约束:

  • 4 <= n == pizzas.length <= 2 * 10^5
  • 1 <= pizzas[i] <= 10^5
  • n 是 4 的倍数。

解题思路

这是一道贪心策略题目。关键在于理解每天的收益规则:

核心观察:

  1. 奇数天获得最大值Z,偶数天获得第二大值Y
  2. 奇数天应该选择3个最小的披萨+1个最大的披萨
  3. 偶数天应该选择2个最小的披萨+2个最大的披萨

算法思路:

  1. 将披萨重量排序
  2. 计算总天数 days = n/4,奇数天数为 ceil(days/2)
  3. 使用贪心策略:
    • 对于奇数天,从最大的披萨中选1个,从最小的披萨中选3个
    • 对于偶数天,从剩余最大的披萨中选2个,从剩余最小的披萨中选2个

实现细节: 使用双指针技术,left指向当前最小披萨,right指向当前最大披萨。根据天数奇偶性决定选择策略,每次选择后更新指针位置。

时间复杂度主要在排序阶段,贪心选择只需要O(n)时间。

代码实现

class Solution {
public:
    long long maxWeight(vector<int>& pizzas) {
        sort(pizzas.begin(), pizzas.end());
        int n = pizzas.size();
        int days = n / 4;
        int oddDays = (days + 1) / 2;
        
        long long result = 0;
        int left = 0, right = n - 1;
        
        // Process odd-numbered days first
        for (int i = 0; i < oddDays; i++) {
            result += pizzas[right];  // Take the largest
            right--;
            left += 3;  // Skip 3 smallest
        }
        
        // Process even-numbered days
        int evenDays = days - oddDays;
        for (int i = 0; i < evenDays; i++) {
            result += pizzas[right - 1];  // Take the second largest
            right -= 2;  // Skip 2 largest
            left += 2;   // Skip 2 smallest
        }
        
        return result;
    }
};
class Solution:
    def maxWeight(self, pizzas: List[int]) -> int:
        pizzas.sort()
        n = len(pizzas)
        days = n // 4
        odd_days = (days + 1) // 2
        
        result = 0
        left, right = 0, n - 1
        
        # Process odd-numbered days first
        for i in range(odd_days):
            result += pizzas[right]  # Take the largest
            right -= 1
            left += 3  # Skip 3 smallest
        
        # Process even-numbered days
        even_days = days - odd_days
        for i in range(even_days):
            result += pizzas[right - 1]  # Take the second largest
            right -= 2  # Skip 2 largest
            left += 2   # Skip 2 smallest
        
        return result
public class Solution {
    public long MaxWeight(int[] pizzas) {
        Array.Sort(pizzas);
        int n = pizzas.Length;
        int days = n / 4;
        int oddDays = (days + 1) / 2;
        
        long result = 0;
        int left = 0, right = n - 1;
        
        // Process odd-numbered days first
        for (int i = 0; i < oddDays; i++) {
            result += pizzas[right];  // Take the largest
            right--;
            left += 3;  // Skip 3 smallest
        }
        
        // Process even-numbered days
        int evenDays = days - oddDays;
        for (int i = 0; i < evenDays; i++) {
            result += pizzas[right - 1];  // Take the second largest
            right -= 2;  // Skip 2 largest
            left += 2;   // Skip 2 smallest
        }
        
        return result;
    }
}
var maxWeight = function(pizzas) {
    pizzas.sort((a, b) => a - b);
    const n = pizzas.length;
    const days = Math.floor(n / 4);
    const oddDays = Math.floor((days + 1) / 2);
    
    let result = 0;
    let left = 0, right = n - 1;
    
    // Process odd-numbered days first
    for (let i = 0; i < oddDays; i++) {
        result += pizzas[right];  // Take the largest
        right--;
        left += 3;  // Skip 3 smallest
    }
    
    // Process even-numbered days
    const evenDays = days - oddDays;
    for (let i = 0; i < evenDays; i++) {
        result += pizzas[right - 1];  // Take the second largest
        right -= 2;  // Skip 2 largest
        left += 2;   // Skip 2 smallest
    }
    
    return result;
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(n log n)主要开销在排序,贪心选择为O(n)
空间复杂度O(1)只使用常数额外空间(不考虑排序的空间开销)