目录
线性DP
股票系列
总结:根据题意确定好股票的状态,列出状态转移方程即可
121. 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:输入:prices = [7,6,4,3,1]
输出:0
#include "bits/stdc++.h"
using namespace std;
class Solution {
public:
int maxProfit_dp(vector<int>& prices) {
if (prices.size() == 0)
return 0;
//dp[i]在[0--i]天交易取得的最大值
int dp[prices.size()] = {0}, min = prices[0];
for(int i = 1; i < prices.size(); i++)
{
dp[i] = dp[i - 1] > prices[i] - min ? dp[i - 1] : prices[i] - min;
min = min < prices[i] ? min : prices[i];
}
return dp[prices.size() - 1];
}
int maxProfit_greedy(vector<int>& prices) {
//记录最低价格,若当前价格大于最低价格,说明可以交易
//否则则更新最低价格
int min_price = prices[0], ans = 0;
for(int i = 1; i < prices.size(); i++){
if(prices[i] > min_price)
//卖出股票
ans = max(ans, prices[i] - min_price);
else
//更新最低价
min_price = prices[i];
}
return ans;
}
};
122. 买卖股票的最佳时机 II
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。
示例 2:输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
示例 3:输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
#include "bits/stdc++.h"
using namespace std;
class Solution {
public:
int maxProfit(vector<int>& prices) {
//贪心算法在局部最低买入,在局部最高卖出
//实际上是在所有涨价期间买入卖出即可
int sum = 0;
for(int i = 1; i < prices.size(); i++){
if(prices[i] > prices[i-1])
sum += (prices[i] - prices[i-1]);
}
return sum;
}
int maxProfit_dp(vector<int>& prices) {
/*动态规划解法:
dp[i][0]:在第i天交易完成之后持有股票的最大收入
dp[i][1]:在第i天交易完成之后没有股票的最大收入
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + nums[i])//前一天本身就没有股票或者当天卖了股票之后没有股票
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - nums[i])//前一天本身就有股票或者当天买入股票
*/
int n = prices.size();
vector<vector<int>> dp(n, vector<int>(2, 0));
dp[0][0] = -prices[0], dp[0][1] = 0;
for(int i = 1; i < n; i++){
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]);
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]);
}
return max(dp[n-1][0], dp[n-1][1]);
}
};
123. 买卖股票的最佳时机 III
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:输入:prices = [7,6,4,3,1]
输出:0
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
示例 4:输入:prices = [1]
输出:0
#include "bits/stdc++.h"
using namespace std;
class Solution {
public:
int maxProfit(vector<int>& prices) {
/*拆分为两个动态规划问题
dp1[i]:第一次交易获取的最大值(第[0,i]天)
dp1[i] = max(max_profit, price[i]-min_price)
max_profit = max(dp1[i], max_profit)
min_price = min(min_price, price[i])
dp2[i]:第二次交易获取的最大值(倒过来看从第i天到最后一天的最大利润)
dp2[i] = max(max_profit, max_price - price[i])
max_profit = max(dp2[i], max_profit)
max_price = max(max_price, price[i])
res = max(dp1+dp2)[i]
*/
int n = prices.size();
vector<int> dp1(n, 0);
vector<int> dp2(n, 0);
int max_profit = INT_MIN, min_price = prices[0], max_price = prices[n-1];
for(int i = 0; i < n; i++){
dp1[i] = max(max_profit, prices[i]-min_price);
max_profit = max(max_profit, dp1[i]);
min_price = min(min_price, prices[i]);
}
max_profit = INT_MIN;
for(int i = n-1; i >= 0; i--){
dp2[i] = max(max_profit, max_price-prices[i]);
max_profit = max(max_profit, dp2[i]);
max_price = max(max_price, prices[i]);
}
max_profit = INT_MIN;
for(int i = 0; i < n; i++)
max_profit = max(max_profit, dp1[i]+dp2[i]);
return max_profit;
}
int maxProfit_dp(vector<int>& prices) {
/*
另解
dp[i][j]:i代表天数、j代表状态后所剩金额最大值
每个状态表示的都是到目前为止的状态
0:到目前为止无任何交易
dp[i][0] = dp[i-1][0]
1:买入第一支股票的状态:前一天就买入了或者现在买入
dp[i][1] = max(dp[i-1][0]-prices[i], dp[i-1][1])
2:卖出第一支股票:现在卖出的,前一天就卖出了
dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
3:买入第二支股票:前一天就买入了或者现在买入
dp[i][3] = max(dp[i-1][3], dp[i-1][2]-prices[i])
4:卖出第二支股票:前一天就卖出或者现在卖出
dp[i][4] = max(dp[i-1][4], dp[i-1][3]+prices[i])
*/
int n = prices.size();
vector<vector<int>> dp(n, vector<int>(5, 0));
dp[0][1] = -1 * prices[0];
dp[0][3] = dp[0][1];
for(int i = 1; i < n; i++){
dp[i][0] = dp[i-1][0];
dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i]);
dp[i][2] = max(dp[i-1][2], dp[i-1][1]+prices[i]);
dp[i][3] = max(dp[i-1][3], dp[i-1][2]-prices[i]);
dp[i][4] = max(dp[i-1][4], dp[i-1][3]+prices[i]);
}
return dp[n-1][4];
}
};
309. 最佳买卖股票时机含冷冻期
给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。示例 1:
输入: prices = [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
示例 2:输入: prices = [1]
输出: 0
一些题解思路:根据题目可知,如果采用动态规划的话,肯定要枚举第i天的一些状态(买入、卖出、是否冻结等等),同时第i天的状态肯定又能用第i-1天的状态来表示。
class Solution {
public:
int maxProfit(vector<int>& prices) {
/**动态规划:多个状态,上一次选择的一些状态会构成本次操作的一些状态
dp[i][0]:拥有股票=max(dp[i-1][0], dp[i-1][2]-nums[i]) 维持上一天拥有或者在今天买入
dp[i][1]:不拥有股票,且接下来处于冷冻期=dp[i-1][0]+nums[i] 今天必须卖出股票
dp[i][2]:不拥有股票,且接下来不是冷冻期=max(dp[i-1][2], dp[i-1][1])
同时可以对状态进行压缩
**/
vector<vector<int>> dp(2, vector<int>(3, 0));
dp[0][0] = -prices[0];
for(int i = 1; i < prices.size(); i++){
dp[1][0] = max(dp[0][0], dp[0][2]-prices[i]);
dp[1][1] = dp[0][0] + prices[i];
dp[1][2] = max(dp[0][2], dp[0][1]);
dp[0][0] = dp[1][0];
dp[0][1] = dp[1][1];
dp[0][2] = dp[1][2];
}
return max(dp[1][0], max(dp[1][1], dp[1][2]));
}
};
其他系列
百度笔试题
#include "bits/stdc++.h"
using namespace std;
// # 百度12号第二题
# define MAX_VAL 10000000
int main(){
int N;
cin >> N;
int total = N;
vector<int> vec_a;
while(total--){
int a;
cin >> a;
vec_a.push_back(a);
}
vector<int> vec_b;
total = N;
while(total--){
int a;
cin >> a;
vec_b.push_back(a);
}
/*
动态规划:dp[i][0]:不对nums[i]进行魔法变换的最大操作次数
dp[i][1]:对nums[i]进行魔法变换的最大操作次数
dp[i][0] = dp[i-1][0] iff : nums_a[i] > nums_a[i-1]
= dp[i-1][1] iff : nums_a[i] > nums_b[i-1]
取最小值
dp[i][1] = dp[i-1][0] + 1 iff : nums_b[i] > nums_a[i-1]
= dp[i-1][1] + 1 iff : nums_b[i] > nums_b[i-1]
取最小值
*/
vector<vector<int>> dp(N, vector<int>(2, MAX_VAL));
dp[0][1] = 1;
dp[0][0] = 0;
for(int i = 1; i < N; i++){
if(vec_a[i] > vec_a[i-1])
dp[i][0] = min(dp[i][0], dp[i-1][0]);
if(vec_a[i] > vec_b[i-1])
dp[i][0] = min(dp[i][0], dp[i-1][1]);
if(vec_b[i] > vec_a[i-1])
dp[i][1] = min(dp[i][1], dp[i-1][0]+1);
if(vec_b[i] > vec_b[i-1])
dp[i][1] = min(dp[i][1], dp[i-1][1]+1);
}
int num = min(dp[N-1][0], dp[N-1][1]);
if (num == MAX_VAL)
cout << -1 << endl;
else
cout << num << endl;
}
1143. 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。示例 1:
输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace" ,它的长度为 3 。