leetcode
leetcode 2401 ~ 2450
操作使得分最大

操作使得分最大

难度:

标签:

题目描述

You are given an array nums of n positive integers and an integer k.

Initially, you start with a score of 1. You have to maximize your score by applying the following operation at most k times:

  • Choose any non-empty subarray nums[l, ..., r] that you haven't chosen previously.
  • Choose an element x of nums[l, ..., r] with the highest prime score. If multiple such elements exist, choose the one with the smallest index.
  • Multiply your score by x.

Here, nums[l, ..., r] denotes the subarray of nums starting at index l and ending at the index r, both ends being inclusive.

The prime score of an integer x is equal to the number of distinct prime factors of x. For example, the prime score of 300 is 3 since 300 = 2 * 2 * 3 * 5 * 5.

Return the maximum possible score after applying at most k operations.

Since the answer may be large, return it modulo 109 + 7.

 

Example 1:

Input: nums = [8,3,9,3,8], k = 2
Output: 81
Explanation: To get a score of 81, we can apply the following operations:
- Choose subarray nums[2, ..., 2]. nums[2] is the only element in this subarray. Hence, we multiply the score by nums[2]. The score becomes 1 * 9 = 9.
- Choose subarray nums[2, ..., 3]. Both nums[2] and nums[3] have a prime score of 1, but nums[2] has the smaller index. Hence, we multiply the score by nums[2]. The score becomes 9 * 9 = 81.
It can be proven that 81 is the highest score one can obtain.

Example 2:

Input: nums = [19,12,14,6,10,18], k = 3
Output: 4788
Explanation: To get a score of 4788, we can apply the following operations: 
- Choose subarray nums[0, ..., 0]. nums[0] is the only element in this subarray. Hence, we multiply the score by nums[0]. The score becomes 1 * 19 = 19.
- Choose subarray nums[5, ..., 5]. nums[5] is the only element in this subarray. Hence, we multiply the score by nums[5]. The score becomes 19 * 18 = 342.
- Choose subarray nums[2, ..., 3]. Both nums[2] and nums[3] have a prime score of 2, but nums[2] has the smaller index. Hence, we multipy the score by nums[2]. The score becomes 342 * 14 = 4788.
It can be proven that 4788 is the highest score one can obtain.

 

Constraints:

  • 1 <= nums.length == n <= 105
  • 1 <= nums[i] <= 105
  • 1 <= k <= min(n * (n + 1) / 2, 109)

代码结果

运行时间: 392 ms, 内存: 43.1 MB


/*
题目思路:
1. 计算每个数的质数分数。
2. 使用Stream API对数组按质数分数排序。
3. 获取排序后前k个元素并累乘其值。
4. 为防止溢出,结果取模 10^9 + 7。
*/

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

public class Solution {
    public static int maxScore(int[] nums, int k) {
        final int MOD = 1000000007;
        return Arrays.stream(nums)
                .boxed()
                .sorted(Comparator.comparingInt(Solution::getPrimeScore).reversed().thenComparingInt(n -> n))
                .limit(k)
                .mapToLong(Long::valueOf)
                .reduce(1, (a, b) -> (a * b) % MOD);
    }

    private static int getPrimeScore(int num) {
        Set<Integer> primeFactors = new HashSet<>();
        for (int i = 2; i * i <= num; i++) {
            while (num % i == 0) {
                primeFactors.add(i);
                num /= i;
            }
        }
        if (num > 1) primeFactors.add(num);
        return primeFactors.size();
    }
}

解释

方法:

本题解采用的是质数分数的贡献法结合单调栈的策略。首先,通过预处理计算每个数的质数分数(即不同质因子的数量)。使用单调栈来为每个元素找到左侧和右侧第一个质数分数更低的元素位置。这些位置帮助确定每个元素可以作为最大值的子数组的范围。对数组元素按照值进行降序排序后,尝试最多k次操作,每次选择范围最大的元素以最大化分数。通过计算该元素出现的次数(由其在单调栈中确定的左右边界计算得出),决定是否可以用完所有的操作。如果在某点用完所有操作,或者找到了最优解,循环终止。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
质数分数是如何计算的,为什么要采用筛法来实现?
质数分数是指某个整数的不同质因子的数量。例如,12的质因子有2和3,因此它的质数分数是2。为了有效地计算每个整数的质数分数,我们采用筛法(例如埃拉托斯特尼筛法)。通过这种方法,我们从最小的质数开始,标记它的所有倍数,并增加其质因子的计数。这种方式使得我们能够高效地处理大范围内的整数,并对每个数的质因子进行计算,避免了对每个数进行独立因式分解的重复和计算上的不便。
🦆
单调栈在这个问题中的作用是什么?为什么选择单调栈而不是其他数据结构?
在本题中,单调栈用于为每个数组元素找到左侧和右侧第一个质数分数更低的元素。这样可以确定每个元素可以作为最大值的子数组的范围。选择单调栈是因为它能够在一次遍历中解决这类“下一个更小元素”或“前一个更小元素”的问题,同时保持时间复杂度为O(n)。如果使用其他数据结构如堆或二分搜索树,则处理这类问题通常会更复杂且效率较低。
🦆
在题解中,如何确定每个元素可以作为最大值的子数组的范围?
每个元素的子数组范围是通过单调栈计算的左右边界确定的。在构建单调栈的过程中,为每个元素找到左侧和右侧第一个质数分数更低的元素。这些位置即为子数组的边界。左边界是当前元素左侧第一个质数分数更低的元素的位置,右边界是右侧第一个质数分数更低的元素的位置。因此,每个元素的子数组范围可以通过这些边界确定。
🦆
排序步骤为什么要按照元素的值进行降序,这样的排序对算法的影响是什么?
按元素值降序排序的目的是优先处理值较大的元素。因为我们的目标是最大化分数,所以首先考虑值较大的元素可能会带来更高的分数贡献。这样的排序保证我们在尽可能使用较少的操作次数的情况下,最大化每次操作的贡献,从而在给定操作次数内达到最大的分数。排序后,算法首先尝试将操作次数分配给值最大的元素,这通常可以使得总分数更优。

相关问题