class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 给定数组的最长严格上升子序列的长度。
* @param arr int整型vector 给定的数组
* @return int整型
*/
int LIS(vector<int>& arr) {
// write code here
//动态规划思路一:1,状态定义:dp[i]表示以arr[i]作为结尾的LIS的长度
//2,状态转移:arr[i]显然要添加到前面已存在的LIS的末尾然后使得长度加一,
//3,转移方程:dp[i]=max(dp[j])+1,其中j<i,并且arr[j]<arr[i]
//4,边界条件:dp数组全部初始化为1,因为每个元素自身就是长度一的LIS
//时间复杂度O(n^2),空间复杂度O(n)
// int size=arr.size();
// if(size==0)
// return 0;
// vector<int>dp(size,1);
// //遍历arr数组
// for(int i =0; i<size; i++)
// {
// //遍历dp数组
// for(int j=0; j<i; j++)
// {
// if(arr[j]<arr[i])
// dp[i]=max(dp[j]+1,dp[i]);
// }
// }
// //algorithm中内置找最大值的函数,返回指向最大值的容器
// auto it=max_element(dp.begin(),dp.end());
// return *it;
//思路二:二分查找+贪心
//1,状态定义:dp[i]代表所有长度为i+1的LIS中末位元素的最小值
//2,状态转移:初始dp为空,依次遍历arr中的元素,找到dp中第一个大于等于arr[i]的位置将其更新为arr[i],如果均小于则将dp长度加一然后把arr[i]添加到dp末尾。
//解释:dp数组必然是严格上升,可以反证法证明。每个arr[i]也只能更新dp中的一个位置,因为更新多个位置则dp中出现相同元素就不满足严格上升。在我们遍历到arr[i]时,理论上它可以更新dp中第一个大于等于arr[i]以及之前的所有位置,但要满足dp是最小末尾的条件我们只能更新最后一个位置。
vector<int>dp;
int size=arr.size();
//遍历arr
for(int i=0; i<size; i++)
{
//找到dp中第一个大于等于arr[i]的位置(lower_bound找到第一个大于等于的位置,upper_bound找到第一个大于的位置)
auto it =lower_bound(dp.begin(),dp.end(),arr[i]);
//如果找到
if(it!=dp.end())
*it=arr[i];
//没找到
else
{
dp.push_back(arr[i]);
}
}
//最后返回dp数组的长度即可
return dp.size();
}
};