元素和最小的山形三元组 I

标签: 数组

难度: Easy

给你一个下标从 0 开始的整数数组 nums

如果下标三元组 (i, j, k) 满足下述全部条件,则认为它是一个 山形三元组

  • i < j < k
  • nums[i] < nums[j]nums[k] < nums[j]

请你找出 nums元素和最小 的山形三元组,并返回其 元素和 。如果不存在满足条件的三元组,返回 -1

示例 1:

输入:nums = [8,6,1,5,3]
输出:9
解释:三元组 (2, 3, 4) 是一个元素和等于 9 的山形三元组,因为: 
- 2 < 3 < 4
- nums[2] < nums[3] 且 nums[4] < nums[3]
这个三元组的元素和等于 nums[2] + nums[3] + nums[4] = 9 。可以证明不存在元素和小于 9 的山形三元组。

示例 2:

输入:nums = [5,4,8,7,10,2]
输出:13
解释:三元组 (1, 3, 5) 是一个元素和等于 13 的山形三元组,因为: 
- 1 < 3 < 5 
- nums[1] < nums[3] 且 nums[5] < nums[3]
这个三元组的元素和等于 nums[1] + nums[3] + nums[5] = 13 。可以证明不存在元素和小于 13 的山形三元组。

示例 3:

输入:nums = [6,5,4,3,4,5]
输出:-1
解释:可以证明 nums 中不存在山形三元组。

提示:

  • 3 <= nums.length <= 50
  • 1 <= nums[i] <= 50

Submission

运行时间: 26 ms

内存: 16.1 MB

class Solution:
    def minimumSum(self, nums: List[int]) -> int:
        lmns = []
        for x in nums:
            lmn = x if not lmns else min(lmns[-1], x)
            lmns.append(lmn)
        res = float("inf")
        rmn = float("inf")
        for i in range(len(nums))[::-1]:
            if nums[i] > lmns[i] and nums[i] > rmn:
                res = min(res, nums[i] + lmns[i] + rmn)
            rmn = min(rmn, nums[i])
        return -1 if res == float("inf") else res

Explain

此题解采用了两次遍历的策略来寻找最小的山形三元组。首先,从左到右遍历数组,记录每个位置左侧的最小值。接着,从右到左遍历数组,记录每个位置右侧的最小值,并且检查当前元素是否可以作为山形三元组的顶点(即 nums[j]),根据前一次遍历的结果,判断是否存在合适的 nums[i] 和 nums[k]。如果存在,则计算可能的三元组和,并更新最小和。如果遍历结束后没有找到有效的山形三元组,则返回 -1。

时间复杂度: O(n)

空间复杂度: O(n)

class Solution:
    def minimumSum(self, nums: List[int]) -> int:
        # 创建一个数组,用于存储从左侧到当前位置的最小值
        lmns = []
        for x in nums:
            lmn = x if not lmns else min(lmns[-1], x)
            lmns.append(lmn)
        # 初始化结果为无穷大,用于寻找最小值
        res = float('inf')
        # 从右向左遍历,同时维护从当前位置到末尾的最小值
        rmn = float('inf')
        for i in range(len(nums))[::-1]:
            # 检查当前元素是否可以作为山形三元组的顶点
            if nums[i] > lmns[i] and nums[i] > rmn:
                res = min(res, nums[i] + lmns[i] + rmn)
            # 更新右侧最小值
            rmn = min(rmn, nums[i])
        # 如果没有找到有效的三元组,返回-1
        return -1 if res == float('inf') else res

Explore

遍历数组时,从左到右记录每个位置左侧的最小值是为了快速确定任意中间顶点j左侧的最小元素nums[i](即i<j)。这是寻找山形三元组的关键步骤之一,因为山形三元组要求顶点两侧的元素都比顶点小。通过这种方式,可以在遍历中直接访问已经计算好的左侧最小值,从而有效减少重复计算和提高算法效率。

一个元素nums[j]能成为山形三元组的顶点的条件是:存在i和k(i < j < k),使得nums[i] < nums[j] > nums[k]。在算法中,使用两次遍历结合左侧最小值和右侧最小值来判断。具体地,在从右到左遍历时,检查当前元素nums[j]是否大于左侧最小值lmns[j]和右侧最小值rmn。这样能确保找到的nums[j]是一个有效的山形顶点。

在从右到左的遍历中,维护右侧最小值rmn的目的是记录从当前位置到数组末尾的最小值。这个值用于检验当前元素nums[j]是否可以作为山形三元组的顶点,也就是需要判断是否存在右侧元素nums[k](k > j),使得nums[k]小于nums[j]。在每次迭代中,通过比较当前元素nums[i]和当前存储的rmn来更新右侧最小值,确保rmn总是反映了从当前位置到数组末尾的最小值。

如果数组长度较短,如只有两个元素,那么不可能形成山形三元组,因为山形三元组需要至少三个元素(i, j, k)。因此,在算法开始时检查数组长度是否小于3是有必要的,如果是,则可以直接返回-1,避免不必要的计算。这种情况下,算法的时间复杂度和空间复杂度都会得到降低,同时也能防止在执行后续操作时因数组长度不足而出现错误。