C++实现数组中是否存在递增三元组的巧妙方法
在解决数组问题时,尤其是涉及到子序列的查找,我们需要考虑时间复杂度和空间复杂度,以确保算法的效率。我们将介绍一种高效的解决方案,详细讲解其思路和实现。
问题描述
给你一个整数数组 nums
,判断这个数组中是否存在长度为3的递增子序列。如果存在这样的三元组下标 (i, j, k)
且满足 i < j < k
,使得 nums[i] < nums[j] < nums[k]
,返回 true
;否则,返回 false
。
示例
-
输入:nums = [1,2,3,4,5]
输出:true
解释:任何i < j < k
的三元组都满足题意。 -
输入:nums = [5,4,3,2,1]
输出:false
解释:不存在满足题意的三元组。 -
输入:nums = [2,1,5,0,4,6]
输出:true
解释:三元组(3, 4, 5)
满足题意,因为nums[3] == 0 < nums[4] == 4 < nums[5] == 6
。
提示
- 1 < = nums.length < = 5 ∗ 1 0 5 1 <= \text{nums.length} <= 5 * 10^5 1<=nums.length<=5∗105
- − 2 31 < = nums[i] < = 2 31 − 1 -2^{31} <= \text{nums[i]} <= 2^{31} - 1 −231<=nums[i]<=231−1
334. 递增的三元子序列 - 力扣(LeetCode)
常规方法和其局限性
一个直观的想法是使用三重循环遍历所有可能的三元组,判断是否存在递增关系。代码如下:
class Solution {
public:bool increasingTriplet(vector<int>& nums) {if (nums.size() <= 2)return false;for (int i = 0; i < nums.size() - 2; i++) {for (int j = i + 1; j < nums.size() - 1; j++) {for (int k = j + 1; k < nums.size(); k++) {if (nums[i] < nums[j] && nums[j] < nums[k])return true;}}}return false;}
};
然而,这种方法的时间复杂度是 O( n 3 n^3 n3),在处理大规模数据时会导致超时。
高效方法:双变量法
为了提高效率,我们可以使用双变量法,只需一次遍历即可解决问题,时间复杂度为 O(n),空间复杂度为 O(1)。具体思路如下:
- 初始化两个变量:
first
和second
,分别表示找到的最小值和次小值,初始值为INT_MAX
。 - 遍历数组:
- 如果当前元素小于或等于
first
,更新first
。 - 否则,如果当前元素小于或等于
second
,更新second
。 - 否则,说明找到了一个递增三元组,返回
true
。
- 如果当前元素小于或等于
- 返回结果:如果遍历结束后未找到递增三元组,返回
false
。
代码实现
class Solution {
public:bool increasingTriplet(vector<int>& nums) {int first = INT_MAX;int second = INT_MAX;for (int num : nums) {if (num <= first) {first = num; // 更新最小值} else if (num <= second) {second = num; // 更新次小值} else {return true; // 找到一个递增三元组}}return false; // 没有找到递增三元组}
};
详细解释
-
初始化:
first
和second
被初始化为最大整数值,表示当前还没有找到有效的最小和次小值。
-
遍历数组:
- 对于每个元素
num
,先与first
比较,如果num
小于或等于first
,则更新first
。 - 如果
num
大于first
且小于或等于second
,则更新second
。 - 如果
num
大于second
,则说明我们找到了一个递增三元组,立即返回true
。
- 对于每个元素
-
返回结果:
- 如果遍历完数组后仍未找到递增三元组,返回
false
。
- 如果遍历完数组后仍未找到递增三元组,返回
总结
通过双变量法,我们可以在 O(n) 的时间复杂度和 O(1) 的空间复杂度内解决判断递增三元组的问题。这种方法通过维护两个变量,巧妙地减少了不必要的遍历,提高了算法效率,适合处理大规模数据。