dp[i]=max(dp[j])+1 其中 0≤j
dp[i]代表0-i之间的序列中最长上升子序列的长度
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
if(n==0) return 0;
if(n==1) return 1;
//初始化数组并设定base case
vector<int> dp(n,1);
int res=0;
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i] = max(dp[i],dp[j]+1);
}
}
//更新最长子序列长度
res = max(res,dp[i]);
}
return res;
}
};
时间复杂度:O(N^2)
空间复杂度:O(N)
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = 1, n = (int)nums.size();
if (n == 0) return 0;
//初始化数组与base case
vector<int> d(n + 1, 0);
d[len] = nums[0];
for (int i = 1; i < n; ++i) {
//特殊情况一直递增
if (nums[i] > d[len]) d[++len] = nums[i];
else{
//不递增则二分查找,进行插入与更新
int l = 1, r = len, pos = 0; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
while (l <= r) {
int mid = (l + r) >> 1;
if (d[mid] < nums[i]) {
pos = mid;
l = mid + 1;
}
else r = mid - 1;
}
d[pos + 1] = nums[i];
}
}
return len;
}
};
dp[i] = max(dp[i], dp[j]+1);
动态规划
class Solution{
public:
int findLongestChain(vector<vector<int>>& pairs){
if(pairs.empty()) return 0;
//区间排序:按右端点进行排序,若右端点不相等,按右端点由小到大进行排序;若右端点相等,则按左端点由小到大进行排序
sort(pairs.begin(),pars.end(),[](const auto& a,const auto& b){
return (a[1]<b[1] || (a[1]==b[1] && a[0]<b[0]);
});
int n = pairs.size();
int res = 0;
vector<int> dp(n,1);
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(pairs[j][1]<pairs[i][0])
dp[i] = max(dp[i],dp[j]+1);
}
res = max(res,dp[i]);
}
return res;
}
};
动态规划+二分查找
int findLongestChain_2(vector<vector<int>>& pairs){
if(pairs.empty())return 0;
sort(pairs.begin(),pairs.end(),[](const auto& a,const auto& b){
return (a[0]<b[0])||(a[0]==b[0]&&a[1]<b[1]);
});
vector<vector<int>> dp;
for(auto& p:pairs){
//二分法寻找大于等于p[0]的最小值dp[i][1]
int left=0,right=dp.size();
while(left<right){//进入while循环区间内至少有2个元素,退出循环的极值只有0或size
int mid=left+((right-left)>>1);
if(dp[mid][1]>=p[0])right=mid;
else left=mid+1;
}
//dp[size-1][1]
if(left>=dp.size())dp.emplace_back(p);
//dp[left][1]大于(等于)p[0]同时也大于p[1],那么我们更新dp[left]为p,这样可以将left变小,以便形成最长的数对链
else if(dp[left][1]>p[1])dp[left]=p;
}
return dp.size();
}
区间贪心法
int findLongestChain(vector<vector<int>>& pairs){
if(pairs.empty())return 0;
//区间排序:按右端点进行排序,若右端点不相等,按右端点由小到大进行排序;若右端点相等,则按左端点由小到大进行排序
sort(pairs.begin(),pairs.end(),[](const auto& a,const auto& b){
return (a[1]<b[1])||(a[1]==b[1]&&a[0]<b[0]);
});
//count初始化为1,用来统计不重复子区间个数的
int count=1,end=pairs[0][1];
for(const auto& p:pairs){
if(p[0]>end){//区间不相交,需要更新边界以及不重复区间个数,注意不能有等号,即区间端点不能连续
count++;
end=p[1];
}
}
return count;
}
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() == 0){
return 0;
}
vector<int> up(nums.size(), 1); // 所有元素, 单独也构成一个摆动序列, 并且长度为 1
vector<int> down(nums.size(), 1);
for(int i = 1; i < nums.size(); i++)
for(int j = 0; j < i; j++)
if(nums[j] > nums[i]) // 说明 nums[j] -> nums[i] 是一个下降的过程, 那么只有在最长摆动序列中 nums[i] 位置的元素属于上升元素时, 此处的 nums[i] 才可以把它给延长, 并且延长后 nums[i] 位置本身是属于下降的元素
down[i] = max(down[i], up[j] + 1); //
else if(nums[j] < nums[i])
up[i] = max(up[i], down[j] + 1);
// 相同的元素直接跳过
int ret = 1;
for(int i = 0; i < nums.size(); i++){ // 从记录子找到最长的, 这部分代码也可以融入前面的动态规划中, 动态及更新全局最大值
ret = max(ret, down[i]);
ret = max(ret, up[i]);
}
return ret;
}
};
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() == 0){
return 0;
}
int up=1,down=1;
for(int i=1;i<nums.size();i++){
if(nums[i]>nums[i-1]){
up = down +1;
}
else if(nums[i]<nums[i-1]){
down = up+1;
}
}
return max(up,down);
}
};