每日一题:
696,计数二进制子串
’想用栈,但是没用明白
官方的解法很好,还很好理解,统计相邻的相同字符的频数,把频数当做元素形成数组,然后根据相邻两个元素中的最小值,就可以知道原来的这两个字符串能形成的符合条件子串数量了。
记录一下大佬的指点
121.股票买卖
1.
虽然是想做动态规划,但是这道题还有个解法是单调栈,虽然有些强行
单调栈可以用来高效率得到一个元素左右两侧比他大或小的元素,
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/c-li-yong-shao-bing-wei-hu-yi-ge-dan-diao-zhan-tu-/
2.
本题的思想是可以由动态规划得到的
public int maxProfit(int[] prices) {
int minPrice = Integer.MAX_VALUE;
int maxProfit = 0;
for(int i = 0;i<prices.length;i++) {
if(prices[i]<minPrice) {
minPrice = prices[i];
}else if(prices[i]-minPrice > maxProfit) {
maxProfit = prices[i] - minPrice;
}
}return maxProfit;
}
这是优化过得思想,只进行一次遍历,要是碰到更小的,就更新最小值,要是碰到更大的,能让maxProfit发生变化的,就更新最大利润,从前往后的顺序,也避免了卖出在买入之前的不合法情况。
如果根据dp来分析
开始这道题我一直在想是不是01背包问题,只取其中两项为1,其余为0,后来发现不会用01背包的状态表示来类推这个题的,(就是说,不选第i个物品的情况可以由f{i-1}表示,但是选了第i个物品的如何表示我没有想好)他的这个状态递推方程就好描述了,终究还是要记录最小值的。
122.买卖股票二:
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/
liweiwei大佬写的太好了,暴力,贪心,动态规划三种方法,
贪心开始能想到,但是不知道对不对,看了他的证明发现是对的,其实就是只要第二天比今天价钱高,就算是能获得利润,就累加,要是不能获得利润,就加零,即没有进行买卖操作。
但不是简单地找最大值和最小值的差。见利就上,亏损就跑。
为了怕我以后看不懂,我找了两个更清晰地解释,
官方说的这个峰谷法,C恒小于A+B是对的。
这个大佬说的也很对
而且此题贪心很明显快于dp,下面只是学习一下如何用dp思想解决。
用动态规划的解决方法没想明白,本来想向第一个买卖股票问题靠拢,后来没靠上去。他的解决方法就很精彩了,状态fij的j用0和1分别代表第i天的时候,到底手里有股票还是有可以用来买股票的钱,而不是单纯的要买股票还是不买,我当时的想法就很难描述出来,以下为复制粘贴。
第 1 步:定义状态
状态 dp[i][j] 定义如下
第一维 i 表示索引为 i 的那一天(具有前缀性质,即考虑了之前天数的收益)能获得的最大利润;
第二维 j 表示索引为 i 的那一天是持有股票,还是持有现金。这里 0 表示持有现金(cash),1 表示持有股票(stock)。
第 2 步:思考状态转移方程
状态从持有现金(cash)开始,到最后一天我们关心的状态依然是持有现金(cash);
每一天状态可以转移,也可以不动。状态转移用下图表示:
image.png
(状态转移方程写在代码中)
说明:
因为不限制交易次数,除了最后一天,每一天的状态可能不变化,也可能转移;
写代码的时候,可以不用对最后一天单独处理,输出最后一天,状态为 0 的时候的值即可。
第 3 步:确定起始
起始的时候:
如果什么都不做,dp[0][0] = 0;
如果买入股票,当前收益是负数,即 dp[0][1] = -prices[i];
第 4 步:确定终止
终止的时候,上面也分析了,输出 dp[len - 1][0],因为一定有 dp[len - 1][0] > dp[len - 1][1]。
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。