用了一种暴力算法 过于暴力 超时了 试了官方的C++也超时了
class Solution {
public:
int maxProfit(vector<int>& prices) {
//找最大 最小值 最小值下标在最大值下标之前
vector<int>::iterator it;
int max=prices[0];
int min=prices[0];
int min_x=0;
int max_x=0;
for(int i=1;i<prices.size();i++)//最小值
{
if(min>prices[i])
{
min=prices[i];
min_x=i;
}
}
for(int i=1;i<prices.size();i++)//最大值
{
if(max<prices[i])
{
max=prices[i];
max_x=i;
}
}
while(max_x<min_x) //最大值坐标小于最小值时,则再从最大值加一开始遍历再找最大值 也可直接剔除最大值 但可能出错
{
for(int i=max_x+1;i<prices.size();i++)
{
if(max<prices[i])
{
max=prices[i];
max_x=i;
}
}
}
int result=prices[max_x]-prices[min_x];
return result;
}
};
在这种写法中之前用到向量删除元素 造成野指针
for(vector::iterator iter=veci.begin(); iter!=veci.end(); iter++)
{
if( *iter == 3)
veci.erase(iter);
}
错误写法
因为earase结束后,iter变成了野指针,iter++就产生了错误。
erase()返回值是一个迭代器,指向删除元素下一个元素;如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素;
for(vector::iterator iter=veci.begin(); iter!=veci.end(); )
{
if( *iter == 3)
iter = veci.erase(iter);
else
iter ++
}
或
prices.erase(remove(prices.begin(),prices.end(),max),prices.end());
但是还是会超时
2.这是一个最大连续子数组和:
解答区有很多很棒的答案 建议详细阅读
有牛顿莱布尼茨公式可知
区间和可以由区间差来求 那么区间差自然可以有区间和来求
在上面的公式中,我们把 F()表示的数组称为前缀和。
最大连续子数组和可以使用动态规划求解, dp[i]dp[i] 表示以i为结尾的最大连续子数组和,递推公式为:
dp[i] = max(0, dp[i-1])
F(x)实际上是f(x)的原函数。在本题中,F(b)和F(a)分别代表买入卖出点,我们要算二者的差,所以F(b) - F(a) = sum(f(a), …f(b))。 f(a), f(b)是F(x)的导函数。所以这里应该先对股票序列求导,即前后做差,然后计算其连续子数组最大和。
而不是直接计算其连续子数组最大和
关于对序列求导即前后做差:差分法,是一种微分方程数值方法,是通过有限差分来近似导数,从而寻求微分方程的近似解。差分法就是把微分用有限差分代替,把导数用有限差商代替,从而把基本方程和边界条件(一般均为微分方程)近似地改用差分方程(代数方程)来表示,把求解微分方程的问题改换成为求解代数方程的问题。
新的数组元素为相邻元素之差,a[i]-a[j]=a[i]-a[i-1]+a[i-1]-a[i-2]+…+a[j+1]-a[j]=dif[i]+dif[i-1]+…+dif[j+1]。两数之差a[i]-a[j]相当于求最大连续子数组和,该数组为dif数组。
代码:(差分法)
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size()<=1) return 0;
int p;
vector<int> diff(prices.size()-1);//两数差数组 有可能为负数
for(int i=0;i<prices.size()-1;i++)
{
diff[i]=prices[i+1]-prices[i];
}
vector<int> dp(diff.size());//最大连续差数组的和
dp[0]=max(0,diff[0]);//与0比较 找正数
p=dp[0];
for(int i=1;i<dp.size();i++)
{
dp[i]=max(0,dp[i-1]+diff[i]);//转换方程
p=max(p,dp[i]);
}
return p;
}
};
还可将diff和dp数组优化掉
建议详细阅读以下几篇文章与解答
详见:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/121-mai-mai-gu-piao-de-zui-jia-shi-ji-dp-7-xing-ji/
还有一篇讲解股票买卖类型题的(强烈建议仔细阅读):https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/
状态转移方程:
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
max( 选择 rest , 选择 sell )
解释:今天未持有两种可能:
昨天就没持有则为dp[i-1][k][0]
昨天有今天卖了则为dp[i-1][k][1] (昨天持有)+prices[i] (今天卖了)
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
max( 选择 rest , 选择 buy )
解释:今天我持有着股票,有两种可能:
要么我昨天就持有着股票,然后今天选择 rest,所以我今天还持有着股票;
要么我昨天本没有持有,但今天我选择 buy,所以今天我就持有股票了。今天买入要减去prices[i]
// k == 1 可将k省去
int maxProfit_k_1(int[] prices) {
int n = prices.length;
// base case: dp[-1][0] = 0, dp[-1][1] = -infinity
int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) { //用变量代替数组则不需要考虑数组越界(i-1==-1)的问题
// dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
// dp[i][1] = max(dp[i-1][1], -prices[i])
dp_i_1 = Math.max(dp_i_1, -prices[i]);
}
return dp_i_0;
}
123 K=2
int n=prices.size();
int dp_i_10=0;
int dp_i_20=0;
int dp_i_11=INT_MIN;
int dp_i_21=INT_MIN;
for(int i=0;i<n;i++)
{
dp_i_10=max(dp_i_10,dp_i_11+prices[i]);
dp_i_11=max(dp_i_11,-prices[i]);//dp[i-1][k-1][0] k=1时 k-1=0则其为0
dp_i_20=max(dp_i_20,dp_i_21+prices[i]);
dp_i_21=max(dp_i_21,dp_i_10-prices[i]);
}
return dp_i_20;
K=正无穷,有冰冻期
int maxProfit(vector<int>& prices) {
// dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
// dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]);
int n=prices.size();
int dp_i_0=0;//前一个状态
int dp_i_1=INT_MIN;
int dp_pre_0=0;//dp[i-2][0] 前前一个状态
for(int i=0;i<n;i++)
{
int temp=dp_i_0;
dp_i_0=max(dp_i_0,dp_i_1+prices[i]);
dp_i_1=max(dp_i_1,dp_pre_0-prices[i]);
dp_pre_0=temp;//状态同样需要递进 递增
}
return dp_i_0;
}
k为任意值
int maxProfit(int k, vector<int>& prices) {
if(prices.size()<2||k<1) return 0;
if(k>=prices.size()/2) //k超过n/2则没有约作用 k=正无穷
{
int dp_i_0=0; int dp_i_1=INT_MIN;
for(int i=0;i<prices.size();i++)
{
int temp=dp_i_0;
dp_i_0=max(dp_i_0,dp_i_1+prices[i]);
dp_i_1=max(dp_i_1,temp-prices[i]);
}
return dp_i_0;
}
else{
int n=prices.size();
int dp[n][k+1][2]={0}; //注意dp数组位置
for(int i=0;i<n;i++)
{
for(int j=k;j>0;j--)
{
if(i-1==-1)
{
dp[i][j][0]=0;
dp[i][j][1]=-prices[i];
continue;
}
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]+prices[i]);
dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0]-prices[i]);
}
}
return dp[n-1][k][0];
}
}
关于区间和的文章:
https://zhuanlan.zhihu.com/p/54337418
这个题解答区的第二解让我对数学与编程,算法结合有了初步认识 推荐仔细研究