给你一个下标从 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 <= 105
1 <= nums[i] <= 108
1. 这题一开始想的是直接暴力枚举所有数,如果数据范围小的话,是可以过的,但是这题的数据范围在1e5了,所以暴力循环肯定是会超时的
暴力代码
class Solution:
def minimumSum(self, nums: List[int]) -> int:
lst = []
for i in range(0,len(nums)-2):
for j in range(i+1,len(nums)-1):
for k in range(j+1,len(nums)):
if i 0:
return min(lst)
return -1
2. 然后是需要进行优化的,要保持在O(n)左右基本才可以
3. 这该如何优化呢?
4. 我们通过题目可以得出,
i < j < k
nums[i] < nums[j]
且 nums[k] < nums[j]
这里面主要就是j在中间,然后i,k的数要比j值小
5. 这样看的话,其实我们只需要枚举这个j值就可以了,然后把j的左边和j的右边分成两个部分
6. 要让值最小,且要满足条件,也就是,左边的最小值肯定是要比j的值要小的,如果左边最小的值比j值还要大的话,那肯定是不满足条件的,右边也是如此
7. 这个时候我们就要去枚举j值,然后看左边最小的和右边的最小值,是否都满足条件,如果满足条件的话,就可以相加,然后每次求出一个总和,这个值就是满足条件的和值,然后最后在这些值里面找一个最小的值就可以了
8. 然后现在的问题就是如何找到左边和右边的最小值,难道要每遍历一个j值,就要左边和右边去找一个i,k值吗?
9, 行不行,我们先看代码:
class Solution:
def minimumSum(self, nums: List[int]) -> int:
minn = inf
# pre = nums[:]
# ba = nums[:]
for i in range(1,len(nums)):
pre = min(nums[:i])
ba = min(nums[i:])
if nums[i] > max(pre,ba):
minn = min(minn,nums[i] + pre + ba)
if minn < inf:
return minn
return -1
这样的结果其实超时的,在你遍历到j的时候,又要去遍历前面的数,一直在不断重复遍历
10. 然后这个时候我们又要进一步优化,也就是我们可以提前用一个列表进行保存,用两个列表裂变进行保存之前最小的值
11. 也就是当我们遍历到j的时候,这个时候,我们提前声明了一个pre的列表,pre[j]的值就是在j前面的最小值,再声明一个ba列表,表示后面最小的值,这个我们最后判断的时候,就看我们的nums[j]的值是否大于pre[j]和ba[j]的值了
12. 那我们应该如何来保存这个pre和ba呢,这个时候就要采用前缀和的思想了,我们的前缀和就是保存前面和当前的和值
13. 也就是从第二个数开始,判断当前的数和前面一个数(表示前面所有值的最小值)的值谁小,谁小的话就保存进去,然后我们的ba也是如此,ba要从后面开始遍历,因为要查看j后面的最小值
14. 最后我们通过pre和nums和ba的关系,就可以得出最后的代码了
class Solution:
def minimumSum(self, nums: List[int]) -> int:
minn = inf
pre = nums[:]
ba = nums[:]
for i in range(1,len(nums)):
pre[i] = min(pre[i],pre[i-1]) # 前面的最小值
for i in range(len(nums)-2,-1,-1):
ba[i] = min(ba[i],ba[i+1]) # 后面的最小值
for i in range(1,len(nums)):
if nums[i] > max(pre[i],ba[i]):
minn = min(minn,pre[i] +ba[i] + nums[i]) # 求最小值
if minn < inf:
return minn
return -1
这个地方要注意一下,为什么要pre = nums[:]呢,因为这个地方,如果你直接=nums的话,他是直接将pre指向和nums的同一片区域,也就是你pre里面的值改变的话,nums的值也会改变,所以这个地方应该直接把nums里面的值重新赋值给pre,也就是创建了一个新的区域,而不是引用同一片区域