前段时间连续工作加上连续大强度锻炼,有点颓了,几乎丧失了斗志。注意矫枉过正,注意不走极端。
714. Best Time to Buy and Sell Stock with Transaction Fee
第一思路(废弃)
最近有个倾向就是硬套动态规划模板,作茧自缚,算是刷题的弊端。一开始思路是找合适的节点把数组割裂开来,将数组的长度缩小来动态规划。但是,无论是最高点和最低点,或者相邻差异大于手续费的点都不合理。
第二思路
参考了别人的想法,隔一天再复述看看。用了一个让我觉得惊艳的想法:即将买入卖出这一组动作分开,只考虑当前位置的收益,豁然开朗。具体思路如下:
每到一个时刻,共有两个选择会影响此时的收益
1. 买入操作,即前一时刻收益减去此时的股票价格
2. 卖出操作,即前一时刻收益加上此时的股票价格,并减去手续费
这样做的好处在于,不用成对考虑买入卖出的相互关系,只需要考虑每一次的状态是持股或者空仓,再考虑对应操作即可,降低了思维的复杂度。赞!
代码
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int s0 = 0, s1 = -prices[0];
for (int i = 1; i < prices.size(); i++) {
s1 = max(s1, s0 - prices[i]);
s0 = max(s0, s1 + prices[i] - fee);
}
return s0;
}
};
总结
在明白思路的时候,实现起来仍然遇到了极大的困难。直到领悟了动态规划极其重要的一点:状态转移。
说白了动态规划就是从一个状态转移到另一个状态,找到转移的模式就能由简至繁。
650. 2 Keys Keyboard
思路
本体核心就是数字可以通过乘数因子来组成,从而自底向上依次计算操作次数。边界条件为
n=1
时,返回0
。而对于其他的数字N,当考虑N的乘数因子M时,需要拷贝M一次,加上N/M-1
次粘贴。
代码
class Solution {
public:
int minSteps(int n) {
vector<int> dp(1,0);
for (int i = 2; i <= n; i++) {
if (n % i) {
dp.push_back(-1);
continue;
}
int min_steps = INT_MAX;
for (int j = 1; j < i; j++) {
if (0 == i % j) {
min_steps = min(min_steps, dp[j-1] + i/j);
}
}
dp.push_back(min_steps);
}
return dp.back();
}
};