Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array.
Formally the function should:
Return true if there exists i, j, k
such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false.
Note: Your algorithm should run in O(n) time complexity and O(1) space complexity.
Example 1:
Input: [1,2,3,4,5]
Output: true
Example 2:
Input: [5,4,3,2,1]
Output: false
题目要求判断给出的数组中是否存在三个元素,nums[i]、nums[j]、nums[k],这三个元素满足nums[i] < nums[j] < nums[k],并且i < j < k。
题目还要求时间复杂度为O(n),空间复杂度为O(1)。
如果暂时不管时间和空间复杂度的事情,如何确定数组中是否存在满足上面条件的三元组呢,brute force则是O(N^3),将所有的三元组全都找出来,判断其中是否存在满足条件的三元组,但是这种方法太蠢了。
如果对于每一个数组的元素C,我们都知道在它之前的元素中的最小值A和在它之后的元素的最大值D呢,这样子如果A < C < D,那么直接返回true就可以啦。我们维护两个数组,former和latter,former[i]表示在i之前的所有元素的最小值,latter[i]表示的是i之后所有元素中的最大值。这样的时间复杂度为O(n),但是空间复杂度为O(n),这点不是太好。
bool increasingTriplet(vector<int>& nums)
{
int size = nums.size();
if(size <= 2)return false;
vector<int> former(size, INT32_MAX), latter(size, INT32_MIN);
former[0] = nums[0];latter[size - 1] = nums[size - 1];
for(int i = 1; i < size; i++)
former[i] = former[i - 1] < nums[i] ? former[i - 1] : nums[i];
for(int i = size - 2; i >= 0; i--)
latter[i] = latter[i + 1] > nums[i] ? latter[i + 1] : nums[i];
for(int i = 1; i < size -1; i++)
if(former[i] < nums[i] && latter[i] > nums[i])return true;
return false;
}
下面是一种巧妙的策略。
维护两个指针small和large,这两个指针都被初始化为INT32_MAX。遍历vector,如果某个元素小于small,这将small更新,相当于当前遇到的数组元素的最小值。如果当前元素大于small,却小于large,说明在此之前,small已经从INT32_MAX更新为另一个值了,也就是说当前元素之前有一个元素小于当前元素(注意这句话)。而如果当前元素大于small和large,说明此时的small和large都被更新过了。此时,我们虽然不能确定这个三元组是什么,但是可以保证在当前元素current element之前,存在一个元素满足current element > large,并且在large之前有一个元素小于large(为什么不能说这个三元组就是small, large, current element,这是因为small和large的索引大小关系不能确定)。下面的代码满足了O(n)的时间复杂度和O(1)的空间复杂度。
bool increasingTriplet(vector<int>& nums)
{
int size = nums.size();
if(size <= 2)return false;
int small = INT32_MAX, large = INT32_MAX;
for(int i = 0; i < size; i++)
{
if(nums[i] <= small) {small = nums[i];}
else if(nums[i] <= large) {large = nums[i];}
else return true;
}
return false;
}