给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。
数学表达式如下:
如果存在这样的 i, j, k, 且满足 0 ≤ i < j < k ≤ n-1,
使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否则返回 false 。
说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1) 。
示例 1:
输入: [1,2,3,4,5]
输出: true
示例 2:
输入: [5,4,3,2,1]
输出: false
分析:
首先是理解题目意思,arr[i]<arr[j]<arr[k]其中i,j,k可以不是连续的,只要相对有序就行。
其次是分析题目:
目的 : 找到三个有序排列的数
步骤 : 先找到两个相对有序的数 first second,再从剩余的数中找大于second的数,找到则返回true,没找到就继续
如何确定 first 和 second 的值 : first保存当前发现的最小值,second保存大于first的最小值
什么时候开始查找大于second的数 : 每当 second 的值改变了的时候,说明first 和 second 的值一定是相对有序的,这时从剩余的数里面查找大于second的数
复杂度分析:
最好的情况是O(n),最差的情况是O(n^2),平均下来还是O(n^2),大约等于 (数组的逆序数)*(n^2)的复杂度。
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
// 使用两个变量 first 和 second 维护一个二元组,表示当前数字前的最小的两个有序变量
// 如果有比first小的数字就更新 first, 如果数字介于first 和 second 之间
// 就更新second, second一旦更新就表示一定有一个有序二元组,然后就在后续数字中查找
// 大于second 的数字,有就返回true,否则继续
int first=INT_MAX, second=INT_MAX;
for(int i=0; i<nums.size(); i++){
if(nums[i]<first)
first = nums[i];
else if(nums[i]>first && nums[i]<second){
second = nums[i];
// 找到二元组,开始在后续数组中查找
for(int j=i+1; j<nums.size(); j++){
if(second < nums[j])
return true;
}
}
}
return false;
}
};
后来想了第二种解法,和上一个一样,只是在判断第三个数字的时候有了变化,因为初始的时候first和second都是INT_MAX,所以一旦first和second都改变了过后,那么一定存在一个相对有序的二元组了,只要再出现一个数字大于second,那么就说明存在了一个有序三元组,代码如下:
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
// 使用两个变量 first 和 second 维护一个二元组,表示当前数字前的最小的两个有序变量
// 如果有比first小的数字就更新 first, 如果数字介于first 和 second 之间
// 就更新second, second一旦更新就表示一定有一个有序二元组
// 因为已经有了一个有序的二元组
// 大于second 的数字,有就返回true,否则继续
int first=INT_MAX, second=INT_MAX;
for(int i=0; i<nums.size(); i++){
if(nums[i]<first)
first = nums[i];
else if(nums[i]>first && nums[i]<second){
second = nums[i];
}
if(nums[i]>second)
return true;
}
return false;
}
};