leetcode 300 最长递增子序列 动态规划
想弄明白动态规划建议看大佬的笔记 算法书籍分享
class Solution {
public:
int max(int a,int b){
int result=a>b?a:b;
return result;
}
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
int dp[n];
for(int i =0;i<n;++i){
dp[i]=1;
}
int res=dp[0];
for(int i =1;i<n;++i){
for(int j=0;j<i;++j){
if(nums[i]>nums[j]){
dp[i]=max(dp[i],dp[j]+1);
}
}
res=max(res,dp[i]);
}
return res;
}
};
方法2
大大的重点,核心的东西
维护一个结果数组,如果当前元素比结果数组的值都大的的话,就追加在结果数组后面(相当于递增序列长度加了1);否则的话用当前元素覆盖掉第一个比它大的元素(这样做的话后续递增序列才有可能更长,即使并没有更长,这个覆盖操作也并没有副作用哈,当然这个覆盖操作可能会让最终的结果数组值并不是最终的递增序列值,这无所谓)
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if (nums.empty()) {
return 0;
}
int N = nums.size();
vector<int> dp;
for (int i = 0; i < N; i++) {
auto iter = lower_bound(dp.begin(), dp.end(), nums[i]);
/*lower_bound( begin,end,num):从有序数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,
找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。*/
if (iter == dp.end()) {
dp.push_back(nums[i]);
} else {
*iter = nums[i];
}
}
return dp.size();
}
};
做一点点解释
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
注意
他俩的返回值是一个迭代器指针,所以可以用 *
取内容
upper_bound返回一个迭代器指针,指向第一个大于val值的位置。如果没有元素大于val,则返回last。
lower_bound返回一个迭代器指针,指向第一个大于等于val值的位置。如果没有元素大于等于val(所有元素都小于val),则返回last。
一个可能更好理解的版本 maybe?
这相当于把迭代器指针转换成了数组索引的形式
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if (nums.empty()) {
return 0;
}
int N = nums.size();
vector<int> dp;
for (int i = 0; i < N; i++) {
int iter = lower_bound(dp.begin(), dp.end(), nums[i])-dp.begin();
/*lower_bound( begin,end,num):从有序数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,
找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。*/
if (iter == dp.size()) {
dp.push_back(nums[i]);
} else {
dp[iter] = nums[i];
}
}
return dp.size();
}
};