leetcode
leetcode 2451 ~ 2500
有序三元组中的最大值 I

有序三元组中的最大值 I

难度:

标签:

题目描述

You are given a 0-indexed integer array nums.

Return the maximum value over all triplets of indices (i, j, k) such that i < j < k. If all such triplets have a negative value, return 0.

The value of a triplet of indices (i, j, k) is equal to (nums[i] - nums[j]) * nums[k].

 

Example 1:

Input: nums = [12,6,1,2,7]
Output: 77
Explanation: The value of the triplet (0, 2, 4) is (nums[0] - nums[2]) * nums[4] = 77.
It can be shown that there are no ordered triplets of indices with a value greater than 77. 

Example 2:

Input: nums = [1,10,3,4,19]
Output: 133
Explanation: The value of the triplet (1, 2, 4) is (nums[1] - nums[2]) * nums[4] = 133.
It can be shown that there are no ordered triplets of indices with a value greater than 133.

Example 3:

Input: nums = [1,2,3]
Output: 0
Explanation: The only ordered triplet of indices (0, 1, 2) has a negative value of (nums[0] - nums[1]) * nums[2] = -3. Hence, the answer would be 0.

 

Constraints:

  • 3 <= nums.length <= 100
  • 1 <= nums[i] <= 106

代码结果

运行时间: 26 ms, 内存: 16.0 MB


/*
 * 思路:使用 Java Stream API 实现上述逻辑。
 * 尽管 Stream API 主要用于简化集合处理,但我们可以将其用于生成 i, j, k 的所有可能组合。
 */

import java.util.stream.IntStream;

public class Solution {
    public int maximumTripletValue(int[] nums) {
        int n = nums.length;
        return IntStream.range(0, n - 2)
            .boxed()
            .flatMap(i -> IntStream.range(i + 1, n - 1)
                .boxed()
                .flatMap(j -> IntStream.range(j + 1, n)
                    .mapToObj(k -> new int[]{i, j, k})))
            .mapToInt(triplet -> (nums[triplet[0]] - nums[triplet[1]]) * nums[triplet[2]])
            .filter(value -> value > 0)
            .max()
            .orElse(0);
    }
}

解释

方法:

该题解采用了前缀最大值和后缀最大值的方法。首先,通过一次从后向前的遍历构建一个后缀最大值数组`suf_max`,该数组在每个位置i存储了从i到数组末尾的最大值。随后,在一次从前向后的遍历中,使用一个变量`pre_max`来记录从数组开始到当前位置的最大值,然后对于每个位置j,计算`(pre_max - nums[j]) * suf_max[j + 1]`,并更新结果`ans`为所有可能组合中的最大值。这种方法有效地利用了动态规划的思想,通过记录前面的计算结果来避免重复计算,从而优化了时间复杂度。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
算法中的后缀最大值数组`suf_max`为什么要从后向前计算,而不是从前向后?
后缀最大值数组`suf_max[i]`定义为从索引i到数组末尾的最大值。如果从后向前计算,可以确保每个位置i的值是基于i+1的值和当前位置的值计算得到的,这样可以一次遍历就完成数组的填充。反之,若从前向后计算,则每次更新suf_max[i]都需要重新检查后面所有元素,导致效率较低。
🦆
为什么在计算最大三元组值时,只需要`pre_max`和`suf_max[j + 1]`,而不需要考虑中间元素`nums[j]`的其他可能性?
在计算最大三元组值时,关键在于最大化`(pre_max - nums[j]) * suf_max[j + 1]`这个表达式。这里`pre_max`是截至当前元素之前的最大值,而`suf_max[j + 1]`是从j+1至数组末尾的最大值。nums[j]作为中间元素,其值直接参与计算,无需考虑其他属性,因为我们已经通过`pre_max`和`suf_max[j + 1]`保证了最大值的计算覆盖所有可能的最大和最小差异组合。
🦆
在构造`suf_max`数组时,为什么数组大小需要是`n+1`,而不是`n`?这个额外的一位具体起什么作用?
数组`suf_max`的大小是`n+1`以便处理边界情况,特别是当遍历到数组的最后一个元素时。suf_max的最后一个元素`suf_max[n]`通常设置为一个很小的值或初始化值(如0),这样可以确保在计算`j = n-1`时,`suf_max[j + 1]`有定义且不会影响结果的正确性。
🦆
如果数组`nums`中的所有元素都相同,这种方法的输出结果会是什么?这是否正确反映了题目的要求?
如果数组中的所有元素都相同,那么`pre_max`和`suf_max[j + 1]`的值也将与`nums[j]`相同。因此,`(pre_max - nums[j]) * suf_max[j + 1]`的计算结果为0。这意味着无论数组中的元素是什么,输出结果都将是0。这符合题目要求,因为没有任何三元组的组合能产生非零的`(pre_max - nums[j]) * suf_max[j + 1]`值。

相关问题