从0开始,每次+1或者+2,求和为n有多少种可能
DP[i]
表示到达i
能有几种可能
初始状态DP[0]=1
递推公式DP[i]=DP[i-1]+DP[i-2]
因为每次只能+1或+2,所以而状态i-1
一定不会影响(改变)i-2
所以正向遍历即可(i-2
会改变i-1
)
#include
#include
using namespace std;
constexpr int N=50;
int climbStairs(int n)
{
int dp[N];
memset(dp,0,sizeof dp);
dp[0]=1;
for(int i=0;i>ans;
ans=climbStairs(ans);
cout<
预知股票价格,求一次买入+一次卖出能赚的最大金额
DP[i]
表示第i
天前的最低价格
对于第Day天的价格我们要找Day之前最便宜的股票买,所以递推式DP[day]=min{ Day[0,Day) }
而初始状态第一天之前的价格我们设置成>=prices[0]
即可,因为这时候是不赚钱甚至亏钱的,保持答案0
那么对于每一天day我们先用今天的价格prices[day]-DP[day-1]
获取今天的最高利润,然后DP[day]=min(prices[day],DP[day-1])
更新这一天之前(包含)的最低价格
由于是一次买入一次卖出,所以取最高值,并且DP[i]只和DP[i-1]有关,而这两者都是基于prices[i]计算/更新,
所以用一个变量aftre充当DP[i-1]即可
#include
using namespace std;
int maxProfit(vector& prices)
{
int lg=prices.size();
int after=INT_MAX,ans=0;
for(auto &price:prices)
{
ans=max(ans,price-after);
after=min(after,price);
}
return ans;
}
int main()
{
vector prices;int temp;
while(cin>>temp)
{
prices.push_back(temp);
}
int ans=maxProfit(prices);
cout<
如题。子数组 是数组中的一个连续部分。
主要说一下分治法
思路就是一个区间[l,r]
内的最大子数组要么处于[l,mid]
要么处于[mid+1,r]
,或者处于[l,r]
,虽然很像废话,但是对计算机来说不一样,由于要找子数组,所以要保持连续性,所以当这个区间内的最大子数组在[l,r]
情况下,一定是包含[l,mid]
的右边和[mid+1,r]
的左边
那么对于一个区间,我们维护它的左起最大子数组、右起最大子数组还有无条件子数组以及区间和
分别有什么作用呢?对于最小子区间[t,t]
这四个数值都是nums[t]
而对于一个父区间,它的左起子数组 是max [l,mid]->left ,[mid+1,r]->left+[l,mid]->sum
,为了保持连续性,只有两种可能,要么是左子区间的 左起最大子数组,要么是整个左子区间加上右子区间的 左起最大子数组
对于右起最大子数组也是一样的,保留右起的连续性;
还有一种无条件子数组,指的是不一定包含左起点或者右起点的最大子数组,由于这可能是答案的一部分,所以要对它进行保留和计算,计算方式是<左子区间的右连上右子区间的左>和两个子区间的无条件子数组中取最大值
#include
using namespace std;
struct ITEM
{
int l,r,m,sum;
};
ITEM query(int l,int r,vector& nums)
{
//cout<<"l:"<>1;
ITEM item1=query(l,mid,nums);
ITEM item2=query(mid+1,r,nums);
ITEM ret;
ret.l=max(item1.l,item1.sum+item2.l);
ret.r=max(item2.r,item2.sum+item1.r);
ret.m=max(item2.l+item1.r,max(item1.m,item2.m));
ret.sum=item1.sum+item2.sum;
return ret;
}
int maxSubArray(vector& nums)//分治法
{
int lg=nums.size();
ITEM ret=query(0,lg-1,nums);
int ans=max(ret.l,max(ret.r,ret.m));
return ans;
}
/*
int maxSubArray(vector& nums)//遍历法O(n)
{
int lg=nums.size(),temp=0,ans=nums[0];
for(auto &num:nums)
{
temp+=num;
ans=max(ans,temp);
if(temp<0) temp=0;
}
return ans;
}*/
int main()
{
vector nums;int num;
while(cin>>num)
nums.push_back(num);
int ans=maxSubArray(nums);
cout<
一个非负整数数组,从中选择数字字求最大和,要求不能选择连续的数字
先将问题想的复杂一点,DP[0][i]
表示第i个数字不选择时区间[0,i]
的最大和,DP[1][i]
表示选择第i个数字,这样可轻松推出dp[0][i]=max(dp[0][i-1],dp[1][i-1])
和dp[1][i]=max(nums[i]+dp[0][i-1],dp[0][i-1])
但是我们再想一想,DP[i]
表示第i个数字(不管选不选)时区间[0,i]
的最大和,那么由于不知道i是否被选上,所以我们的递推式只能变成DP[i]=max(DP[i-1],DP[i-2]+nums[i])
,这样是否合理呢?
是合理的因为DP[i]
不管选没选择这个递推式都不会选择连续的数字,只要初始状态合理就行,初始状态设置DP[0]=nums[0] DP[1]=max(nums[0],nums[1])
,从第一步DP[2]的计算我们就可以看出,无论如何我们都不会计算DP[2]包含nums[1]+nums[2]
,同时由于这个递推式只需要三个变量,所以可以用滚动变量解决
#include
using namespace std;
int rob(vector& nums)//J2
{
int lg=nums.size();
if(lg==1) return nums[0];
int temp1=nums[0],temp2=max(nums[0],nums[1]);
for(int i=2;i& nums)//J1
{
int lg=nums.size();
vector>dp(2,vector(lg));
dp[1][0]=nums[0];
for(int i=1;i nums;int num;
while(cin>>num)
nums.push_back(num);
int ans=rob(nums);
cout<