leetcode
leetcode 2401 ~ 2450
子序列最大优雅度

子序列最大优雅度

难度:

标签:

题目描述

You are given a 0-indexed 2D integer array items of length n and an integer k.

items[i] = [profiti, categoryi], where profiti and categoryi denote the profit and category of the ith item respectively.

Let's define the elegance of a subsequence of items as total_profit + distinct_categories2, where total_profit is the sum of all profits in the subsequence, and distinct_categories is the number of distinct categories from all the categories in the selected subsequence.

Your task is to find the maximum elegance from all subsequences of size k in items.

Return an integer denoting the maximum elegance of a subsequence of items with size exactly k.

Note: A subsequence of an array is a new array generated from the original array by deleting some elements (possibly none) without changing the remaining elements' relative order.

 

Example 1:

Input: items = [[3,2],[5,1],[10,1]], k = 2
Output: 17
Explanation: In this example, we have to select a subsequence of size 2.
We can select items[0] = [3,2] and items[2] = [10,1].
The total profit in this subsequence is 3 + 10 = 13, and the subsequence contains 2 distinct categories [2,1].
Hence, the elegance is 13 + 22 = 17, and we can show that it is the maximum achievable elegance. 

Example 2:

Input: items = [[3,1],[3,1],[2,2],[5,3]], k = 3
Output: 19
Explanation: In this example, we have to select a subsequence of size 3. 
We can select items[0] = [3,1], items[2] = [2,2], and items[3] = [5,3]. 
The total profit in this subsequence is 3 + 2 + 5 = 10, and the subsequence contains 3 distinct categories [1,2,3]. 
Hence, the elegance is 10 + 32 = 19, and we can show that it is the maximum achievable elegance.

Example 3:

Input: items = [[1,1],[2,1],[3,1]], k = 3
Output: 7
Explanation: In this example, we have to select a subsequence of size 3. 
We should select all the items. 
The total profit will be 1 + 2 + 3 = 6, and the subsequence contains 1 distinct category [1]. 
Hence, the maximum elegance is 6 + 12 = 7.  

 

Constraints:

  • 1 <= items.length == n <= 105
  • items[i].length == 2
  • items[i][0] == profiti
  • items[i][1] == categoryi
  • 1 <= profiti <= 109
  • 1 <= categoryi <= n
  • 1 <= k <= n

代码结果

运行时间: 141 ms, 内存: 40.8 MB


/*
 * 使用 Java Stream API 实现:
 * 1. 首先,我们可以使用流来对 items 数组按利润排序。
 * 2. 接下来,我们可以使用 reduce 方法来计算利润的总和,同时使用 distinct 方法过滤不同类别。
 * 3. 最后,通过组合这些结果来计算优雅度。
 */

import java.util.*;
import java.util.stream.*;

public class MaxEleganceStream {
    public int findMaxElegance(int[][] items, int k) {
        List<int[]> sortedItems = Arrays.stream(items)
                .sorted((a, b) -> b[0] - a[0])
                .collect(Collectors.toList());
        
        Set<Integer> categories = new HashSet<>();
        int totalProfit = IntStream.range(0, k)
                .map(i -> {
                    categories.add(sortedItems.get(i)[1]);
                    return sortedItems.get(i)[0];
                })
                .sum();
        
        int maxElegance = totalProfit + categories.size() * categories.size();
        
        for (int i = k; i < sortedItems.size(); i++) {
            if (!categories.contains(sortedItems.get(i)[1])) {
                categories.add(sortedItems.get(i)[1]);
                totalProfit += sortedItems.get(i)[0] - sortedItems.get(k - 1)[0];
                maxElegance = Math.max(maxElegance, totalProfit + categories.size() * categories.size());
                k++;
            }
        }
        return maxElegance;
    }
}

解释

方法:

首先按项目利润降序对items数组进行排序,确保优先选择利润最高的项目。接着,选取前k个项目作为初始子序列,计算这些项目的总利润并记录已选择的类别。如果在这前k个项目中有重复类别的项目,将其利润存入dup列表。然后,计算初始子序列的优雅度。接下来,遍历剩余的项目,如果遇到新的类别(不在已选择的类别集合中),且dup列表非空(意味着有可以替换的低利润项目),则用当前项目替换dup中的一个项目,更新总利润,并重新计算优雅度。这样,可以尝试通过添加新类别来提高优雅度,同时尽量保持高利润。最后返回遍历过程中计算的最大优雅度。

时间复杂度:

O(n log n)

空间复杂度:

O(k)

代码细节讲解

🦆
为什么在选择最初的k个项目时,直接按照利润的降序进行排序,而不考虑类别的独特性?
在初步选择项目时,优先考虑利润最高的项目是为了尽可能地提高子序列的初始总利润。虽然类别的独特性也对优雅度有贡献,但在初始阶段,高利润项目对优雅度的直接影响较大,因为优雅度的计算公式中利润直接被加和。此外,稍后在选择过程中仍有机会通过替换重复类别的低利润项目来调整,从而增加类别的独特性和整体优雅度。
🦆
在处理重复类别时,是如何决定哪个项目的利润放入dup列表的?是否总是选择利润最低的项目,如果是,为什么?
在算法中,当遇到一个类别已存在于已选择的集合中时,该项目的利润会被添加到dup列表。由于项目是按利润降序排序的,因此当一个类别第二次出现时,其利润必然不高于该类别首次出现的项目。因此,放入dup列表的自然是较低的利润项目。这样做是因为,如果后续需要替换以提高类别的独特性,优先替换利润较低的项目可以最大程度保持总利润。
🦆
计算优雅度时使用了表达式`total_profit + distinct_categories^2`,其中的平方是否会导致类别的影响过于突出?
使用平方的方式确实会使类别数量的影响在优雅度的计算中变得更加显著。这种设计是有意为之,目的是强调类别的多样性对于优雅度的重要性。这样的设计促使算法在保持较高利润的同时,也尽可能地增加类别的独特性,从而达到一个利润与类别多样性的平衡。
🦆
如果在遍历剩余项目时遇到的新类别项目利润非常低,是否还应该替换dup中的项目?这种情况下如何平衡利润和类别数量的影响?
遇到新类别但利润非常低的项目时,是否替换需要权衡利润与类别数量的增加。如果新类别的加入通过类别数量的增加可以显著提高优雅度(即使牺牲一些利润),那么还是值得替换的。但如果利润损失过大,导致优雅度反而下降,则不应替换。这种决策需要在实现中通过计算替换前后的优雅度来确定,选择能使优雅度最大化的操作。

相关问题