最大数字序列和问题,买卖股票问题,以及最长公共字串问题
2016-04-19 18:25
423 查看
最大数字序列和问题
最大数字序列和原理
给定由n个整数(可能为负整数)组成的序列A1,A2,A3,...,An,求该序列的连续子段的和的最大值。当所有整数均为负整数时定义其最大子段和为0
例如 {-4, 11,-2, 13,-7,-3,12} 的最大子段和为22
int MaxSum(int[] array,int n)
{
int b=0;
int sum=0;
for(int i=1;i<=n;i++)
{
if(b>0)
{
b+=array[i];
}
else
{
b=array[i];
}
if(b>sum)
{
sum=b;
}
}
return sum;
}
买卖股票问题:
点击打开链接
1,一次买卖股票受益最大
分析:此题就是选择买入卖出股票的最大收益,对于第i天卖出的最大收益即为第i天的股市价格减去[0,i-1]天内的最小股市价格,当第i天的股市价格比漆面最低股市价格还低,则更新最低股市价格。然后取最大的股市收益,为DP问题。用profit[i]表示第i天的收益,则minBuyPrice = min(minBuyPrice, prices[i]),并且profit[i] = prices[i]-minBuyPrice. 然后取profit中的最大值。
class Solution {
public:
int maxProfit(vector<int> &prices) {
int n = prices.size();
if(n == 0) return 0;
int maxPro = 0;
int minBuyPrice = prices[0];
for(int i = 1; i < n; i++){
minBuyPrice = min(minBuyPrice, prices[i]); // 用于记录当前天买进的最小值 minBuyPrice[i+1] = min(minBuyPrice[i], nums[i])
if(maxPro < (prices[i]- minBuyPrice)){ // 全局最大利益是否小于当天的利益
maxPro = prices[i]- minBuyPrice;
}
}
return maxPro;
}
};
2,不限制买卖次数,收益最大问题
此题是上题的变形,买入卖出的次数没有限制,但是第二次买入必须在第一次卖出的时间节点之后,,此时存在一个局部最优,即 2 4 5 3 6 8,此时8-2一定小于5-2+8-3,,因此就有取数组每次递增的收益即为局部最优,然后所有的局部最优加起来就是全局最优
法一(最简洁,干净,利落):
class Solution {
public:
int maxProfit(vector<int> &a) {
int profit = 0;
for (int i = 1; i < a.size(); ++i) {
if (a[i] > a[i-1]) {
profit += a[i]-a[i-1];
}
}
return profit;
}
};
法二:
class Solution {
public:
int maxProfit(vector<int> &prices) {
int n = prices.size();
if(n == 0) return 0;
int minBuyPrice = prices[0];
int sumResult = 0;
/*for(int i = 0; i < n; i++){
if(i+1 < n && prices[i] >= prices[i+1]){ // 局部最优在于当prices[i] >= prices[i+1]
sumResult += prices[i]-minBuyPrice; //既可用prices[i]-minBuyPrices了找到局部最优了--全部加起来就是全局最优解了
minBuyPrice = prices[i+1];
}else{
if(i+1 == n) sumResult += prices[i]-minBuyPrice;
}
}*/
for(int i = 1; i < n; i++){
if(prices[i] < prices[i-1]){ // 在i处有一个局部最优,所有的局部最优和就是全局最优
sumResult += prices[i-1]- minBuyPrice;
minBuyPrice = prices[i];
}
}
sumResult += prices[n-1]- minBuyPrice;
return sumResult;
}
};3,最多买卖两次股票受益最大问题
此题亦即变形,也就是求交易次数最多为两次。当然有两种方法,第一种暴力,对于每个i,我们求[0,i]与[i,n-1]两次收益,然后求和,遍历i,可以取其中的最大值,需要O(N^2)的时间。第二种方法是动态规划,用两个数组,第一个数组f1[i]用来表示在[0,i]内进行买入卖出的最大收益,用f2[i]表示在[i,n-1]内进行买入卖出的最大收益。然后最大收益即为max(f1[i]+f2[i]),如何求f1[i]和f2[i],,可参考上面的一次买卖股票问题。
class Solution {
public:
int maxProfit(vector<int> &prices) {
int n = prices.size();
if(n <= 1) return 0;
vector<int> f1(n); // 表示在[0,i]内进行买入卖出所能获得的最大profit
vector<int> f2(n); // 表示在[i, n-1]内进行买入卖出所能获得的最大profit 结果就为max(f1[i]+f2[i])
int minPrice = prices[0];
for(int i = 1; i < n; i++){
minPrice = min(minPrice, prices[i]);
f1[i] = max(f1[i-1], prices[i]- minPrice);
}
int maxPrice = prices[n-1];
for(int i = n-2; i >=0; i--){ // 这里要从后往前遍历
maxPrice = max(maxPrice, prices[i]);
f2[i] = max(f2[i+1], maxPrice - prices[i]);
}
int maxResult = 0;
for(int i = 0; i < n; i++)
maxResult = max(maxResult, f1[i]+f2[i]);
return maxResult;
}
};4,最多买卖k次股票问题
分析:此题为较难的动态规划问题。首先要第一步就是要转化成动态规划问题, 其次是要写出递归式。我们用local[i][j]表示第i天最多交易j次并且最后一次卖出在第j天所获得的最大利润;global[i][j]用来表示第i天最多交易j次所获得的最大利润。
那么local[i][j]的递归式为:
local[i][j] = max(global[i-1][j-1]+ max(diff, 0), local[i-1][j]+diff).
其中diff = prices[i] - prices[i-1]; global[i-1][j-1]表示第i-1天最多进行j-1次交易获得的最大利润,如果diff大于0,那么那么就加上今天获得利润,diff<0,那么最后一次就可以看做是当天买入并卖出。local[i-1][j]表示第i-1天最多进行j次交易获得的利润,加上diff就等于local[i][j]。 取两者最大值。
global[i][j]的递归式为:
global[i][j] = max(global[i-1][j], local[i][j]);
也就是取第i-1天最多进行j次交易和第i天交易并且最多交易j次且最后一次交易在第i天的利润的最大值。
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
if(k >= n/2) return maxProfit2(prices);
vector<int> lp(k+1);
vector<int> gp(k+1);
for(int i = 1; i < n; i++){
int diff = prices[i]- prices[i-1];
for(int j = k; j>0; j--){
lp[j] = max(gp[j-1]+max(diff, 0), lp[j]+diff);
gp[j] = max(gp[j], lp[j]);
}
}
return gp[k];
}
int maxProfit2(vector<int> &prices){
int ans = 0;
for(int i = 1; i < prices.size(); i++){
ans += max(prices[i]-prices[i-1], 0);
}
return ans;
}
};
最长公共子串问题:
点击打开链接 点击打开链接
动态规划:如果X[i]==Y[j],那么dp[i][j]=dp[i-1][j-1]+1;
如果X[i]!=Y[j],那么dp[i][j]=0;
相关文章推荐
- 谷歌Android各版本源码托管
- Swift 闭包页面传值
- Linux下利用双网卡构建网关截获数据包
- IOS 中block结构的简单用法
- javabean总结
- 设计模式(5)之原型模式
- Java正则表达式(Regular Expression) 邮箱验证
- 深入浅出: Java回调机制(异步)
- Extjs使用:
- SQLyog管理Mysql数据库
- 一.前端初识
- spring注解区别
- 编译wpa_supplicant,提示关于nl80211的错误
- Android AsyncTask完全解析,带你从源码的角度彻底理解
- 软件设计模式——观察者模式(Observer)
- 麒麟开源堡垒机集中管控平台软件简介
- 简单后缀表达式转nfa 正则匹配 Python
- 始于移动端网页布局
- jQuery Validation用法示例
- web.py的两种更新Mysql数据的方法