题目
思路一 双向遍历
用两个数组存储,从前往后遍历存储当前的最小值,从后往前遍历存储当前的最大值,第三次遍历判断当前数据是否大于从前往后遍历的最小值和从后往前遍历的最大值。
代码一
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int n=nums.size();
vector<int> minv(n),maxv(n);
int minn=INT_MAX,maxx=INT_MIN;
for(int i=0;i<n;i++){
minn=min(minn,nums[i]);
minv[i]=minn;
}
for(int i=n-1;i>=0;i--){
maxx=max(maxx,nums[i]);
maxv[i]=maxx;
}
for(int i=0;i<n;i++){
if(minv[i]<nums[i]&&nums[i]<maxv[i])
return true;
}
return false;
}
};
思路二 贪心
设置两个变量first和second记录目前最小的两个数,初始化first为数组第一个元素,second为INT_MAX。如果当前数比second大,就返回true。否则,如果当前数比first大,就更新second为当前树。否则,说明当前数不比first大,就更新first为当前数。中心思想是我们想要让前两个数都尽量小,然后找第三个数。
代码二
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int n=nums.size(),first=nums[0],second=INT_MAX;
for(int i=1;i<n;i++){
if(nums[i]>second)
return true;
else if(nums[i]>first)
second=nums[i];
else
first=nums[i];
}
return false;
}
};
思路三 贪心+二分
将思路二推广到一般情况,创建一个数组f,初始化所有元素为INT_MAX,f[len]=x,表示长度为len的最长上升子序列的最小结尾元素为x,可以证明f具有单调性。遍历原数组的同时,维护f,二分查找小于nums[i]的最大下标,来作为nums[i]的前一个数。
代码三
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int n=nums.size(),ans=0;
vector<int> f(n+1,INT_MAX);
for(int i=0;i<n;i++){
int t=nums[i];
int l=1,r=i+1;
while(l<r){
int mid=(l+r)>>1;
if(f[mid]>=t) r=mid;
else l=mid+1;
}
ans=max(r,ans);
f[r]=t;
}
return ans>=3;
}
};