ARTS第五周
ARTS第五周
ARTS是什么?
Algorithm:每周至少做一个leetcode的算法题;
Review:阅读并点评至少一篇英文技术文章;
Tip/Techni:学习至少一个技术技巧;
Share:分享一篇有观点和思考的技术文章。
Algorithm
题目:买卖股票的最佳时机 IV
解题思路
这是LeetCode上买卖股票系列的最后一题,也是难度最大的一题。这里我们用标准的动态规划算法来解这道题,既然是用动态规划的办法,那就要先定义出动态规划的状态和状态转移方程。
状态:根据题意,我们需要定义个三维的状态,分别是:天数, 交易次数,是否拥有股票的状态保持不动,买入一股,卖出一股)
状态转移方程:如果当前手里没有股票,方程为:今天的利润 = Max(昨天的利润, 昨天的利润 + 今天卖出股票的钱);如果当前手里有股票,方程为:今天的利润 = Max(昨天的记录,昨天的利润 - 今天买入股票的钱)
代码
实际的代码就是把上面的状态转移方程用代码表达出来,再加上一些边界问题或特殊场景的判断即可。此题值得一提的是,当k大于数组长度的时候,其实题目就变成了“买卖股票的最佳时机II”,只要一直把利润相加就行了。
class Solution {
public int maxProfit(int k, int[] prices) {
if (prices.length <= 0 || k <= 0){
return 0;
}
int maxProfit = 0;
//k大于数组长度的时候,其实题目就变成了“买卖股票的最佳时机II”
if (k > prices.length){
for(int i=1;i<prices.length;i++){
if(prices[i] > prices[i-1]){
maxProfit += prices[i] - prices[i-1];
}
}
return maxProfit;
}
//三维分别表示:天数, 交易次数,拥有股票的状态(不动,买入一股,卖出一股)
int[][][] mp = new int[prices.length][k+1][2];
/**
* 初始化数据
*/
for (int i=0;i<=k;i++){
//状态:第一天、交易次数i、无股票
mp[0][i][0] = 0;
//状态:第一天、交易次数i、有股票
mp[0][i][1] = - prices[0];
}
//第二天开始
//天数
for (int i = 1; i < prices.length; i++) {
//交易次数
for (int j = 0; j<= k; j++){
if (j == 0){
//当前没有股票,买入算一次交易,卖出不算
mp[i][j][0] = Math.max(mp[i-1][j][0], 0);
//当前拥有股票
mp[i][j][1] = Math.max(mp[i-1][j][1], 0);
}else{
//当前没有股票,买入算一次交易,卖出不算,1:前一天没有股票,2:前一天有股票今天卖出
mp[i][j][0] = Math.max(mp[i-1][j][0], mp[i-1][j][1] + prices[i]);
//当前拥有股票,1:前一天有股票,2:前一天没有股票今天买入
mp[i][j][1] = Math.max(mp[i-1][j][1], mp[i-1][j-1][0] - prices[i]);
}
int[] all = new int[]{maxProfit, mp[i][j][0], mp[i][j][1]};
maxProfit = Arrays.stream(all).max().getAsInt();
}
}
return maxProfit;
}
}
Review
本次review的文章比较有意思,文章名为A faster alternative to Java Reflection,顾名思义是Java反射的一种更快的替代方案。作者在文中使用invokedynamic技术实现了一个自制的JavaBeanUtil。并且和Apache BeanUtils、 Jodd BeanUtil进行了性能比较,从作者展示的结果来看自制BeanUtil性能是最好的,他在放了源码在github上,感兴趣的话可以自己下载下来测试一下。最后,作者也提醒读者,自制BeanUtil只用来做实验展示invokedynamic的可能性,不建议用在生产环境。
Tip/Techni
Java实现获取最大数方法,包括int、double、char三种类型,其关键是调用max方法,它是一个重载方法,有无参方法可以直接获取int、long和double类型数组的最大值,也有接受一个参数的方法可以指定“比较方法”,具体示例如下:
int[] all = {1, 2, 3};
int max = Arrays.stream(all).max().getAsInt();
double[] doubles = {1.2, 2, 3.62};
double maxDouble = Arrays.stream(doubles).max().getAsDouble();
Character[] chars = {'c', 'z', 'j'};
Character character = Arrays.stream(chars).max(Character::compareTo).get();
Share
这周分享两个学习方法:
- 打怪升级学习法
- 沉淀学习法
打怪升级学习法
在平时的学习过程中,给自己设立一个切实可行的目标,就像打怪升级一样。
这个方法的原理很简单,就是获取一定的成就感,然后支持你继续学习下去。
具体的做法很多,比如写博客(就像我这篇文章这样_)当我看到你在文章下面留言或点赞,我就会为了每次都能写一篇好的文章而得到你的留言或点赞而努力,再比如在学习交流群里和别人交流你刚学到的知识、在某个帖子下面评论回复等等。
沉淀学习法
原理也同样很简单:知识需要沉淀,不要想试图一下子掌握所有,学习的过程是反复迭代、不断沉淀的过程。
如果在学习的过程中碰到了“拦路虎”,可以尽可能地去想办法找答案也可以先沉淀一下,过几天再重新学一遍,说不定就会豁然开朗,所谓书读百遍其义自见也就是这个道理。