class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.empty()) return 0;
int min=prices[0];
int max=0;
for(int i=0;i<prices.size();i++){
min = std::min(min,prices[i]);
max = std::max(max,prices[i]-min);
}
return max;
}
};
理一下思路:
- 先定义出
min
和max
- 在循环中,遇到比
min
小的prices[i]
,就改变最小值 max
的操作同样是如此
一个循环下来,就可以得出答案
但是呢,自己多思考了一下,就炸出了自己的思维漏洞
[7,2,11,1,9,4]
假如,在遇到比min
小的那个数之前,就已经得出了这个数组最大的差值max
那这时候再改变最小值min
是不是有问题?
就如上这个数组,当min==2
时,最大差值是max==11-2==9
,而遍历到后面min=std::min(2,1)
那max
怎么办?
这里的例子比较简单,一下子能想通过来,但当时没看答案之前,就想不通的…
因为max
已经记录下来了,如果后面有一个数n>=11
,那n-1 > 11-2
这时max
就会改变,而不是当时自己以为的已经是最大
像这样修改前面已经暂定下来的值的题,还有一道
最长上升子序列好像是dp里一个常见的类型题,百度百科直接给出了两种时间复杂度的解法,也有博主整理了这个问题
动态规划
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = nums.size();
vector<int> ans(len,1);
for(int i=1;i<len;i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]) ans[i] = std::max(ans[i],ans[j]+1);
}
}
sort(ans.begin(),ans.end());
return ans[len-1];
}
};
这里还有一种解法 —— 贪心+二分
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = nums.size();
vector<int> ans;
ans.push_back(nums[0]);
for(int i=1;i<len;i++){
int back = ans[ans.size()-1];
if(nums[i]==back) continue;
else if(nums[i]>back) ans.push_back(nums[i]);
else{
int left=0;
int right=ans.size();
while(left<right){
int mid=(left+right)>>1;
if(ans[mid]<nums[i]) left=mid+1;
else right=mid;
}
ans[right]=nums[i];
}
}
return ans.size();
}
};
在看代码时,记住一个前提,程序返回的是递增子序列的长度,而不是递增的子序列
输入的数组nums = [10,9,2,5,3,7,101,18]
,放置子序列的容器ans
程序的思路:
遍历nums,若nums[i]比ans最后一个元素大,则将nums[i]添加到ans尾部
否则,替换ans数组中第一个比nums[i]大于或等于的元素
程序开始:
int back=ans[ans.size()-1];
back==10
,nums[i]==9
>>>ans=={ 10 }
ans=={ 9 }
back==9
,nums[i]==2
>>>ans=={ 9 }
ans=={ 2 }
back==2
,nums[i]==5
>>>ans=={ 2,5 }
back==5
,nums[i]==3
>>>ans=={ 2,5 }
ans=={ 2,3 }
back==3
,nums[i]==7
>>>ans=={ 2,3,7 }
back==7
,nums[i]==101
>>>ans=={ 2,3,7,101 }
back==101
,nums[i]==18
>>>ans=={ 2,3,7,101 }
ans=={ 2,3,7,18 }
程序返回:
4
为什么可以这么做?前面已经确定下来的子序列还能修改?
如果数组是nums[10,9,1,2,8,9,10,3,4,5,18,101]
,而程序结束时ans={1,2,3,4,5,18,101}
最长递增子序列可以是{1,2,8,9,10,18,101}
,也可以是{1,2,3,4,5,18,101}
如果数组nums
很长很长,那明显{1,2,3,4,5···}
的序列会更长
如果数组nums[10,9,1,2,8,9,10,3,4]
,在4
就结束,ans={1,2,3,4,10}
这个不是最长递增子序列,但ans
的长度是正确答案
在{1,2,8,9,10}
数组内,任意替换除了头尾的元素,最长递增子序列都是原来的序列
而一旦替换了最后一个元素,那最长递增子序列又有一个答案,而且是更优的答案