目录
2. 买卖股票的最佳时机 II(LeetCode 122 题)
1. 买卖股票的最佳时机(LeetCode 121 题)
1.1题目
1.2思路
方法一
暴力解法当然是二重循环,一个指针从头开始逐个遍历为i。另一个指针为i+1到末尾。找到最大的距离。
但是非常不幸,这段代码超时了。不过基本解题思路是明确的。被卡住的测试用例我截图在上面……分析一下时间复杂度为什么会超时。
我们循环两层,那么我们内层循环从n-1(近似看为n次)开始到1。总共有n次 。也就是n(n+1)/2次,为n2。
class Solution {
public int maxProfit(int[] prices) {
if(prices.length<=1) return 0;
int maxout = 0;
for(int i =0;i<prices.length-1;i++){
for(int j =i+1;j<prices.length;j++){
if(prices[j]>prices[i]) maxout=maxout>prices[j]-prices[i]?maxout:prices[j]-prices[i];
}
}
return maxout;
}
}
方法二
我们采用时间复杂度为n的方法来解决这个问题。具体应该如何入手呢?
我们看一下官方给的方法并加以补充解释。
我们来假设自己来购买股票。随着时间的推移,每天我们都可以选择出售股票与否。那么,假设在第 i 天,如果我们要在今天卖股票,那么我们能赚多少钱呢?
显然,如果我们真的在买卖股票,我们肯定会想:如果我是在历史最低点买的股票就好了!太好了,在题目中,我们只要用一个变量记录一个历史最低价格 minprice,我们就可以假设自己的股票是在那天买的。那么我们在第 i 天卖出股票能得到的利润就是 prices[i] - minprice。
因此,我们只需要遍历价格数组一遍,记录历史最低点,然后在每一天考虑这么一个问题:如果我是在历史最低点买进的,那么我今天卖出能赚多少钱?当考虑完所有天数之时,我们就得到了最好的答案。[1]
官方的方法是建议我们每次从历史最低价格开始,这里写的其实不够明确容易让人误解,准确的说法是当前的历史最低价,而不是整体的历史最低价。
如果我们出现了当前的历史最低价,我们把历史最低价放入minprice,否则不是当前的最低价(也就是暂时没有出现比我们之前的最低值还要低的)。
后面凡是出现高于最低价的值必然高于这之间的值,也就是我们N2方法的重复计算值,这种思路可以有效的舍去这些多余的部分。
接着我们可能会出现这样的情况,
如果我们最后的走势是一路下跌,我们不管怎么更新最小值都不会影响整体的最大收入。
同时即使l2的起点低于l1,但每次比较最大的收入即可得到最大的值,简化计算并不会影响的到正确结论。
1.3代码
class Solution {
public int maxProfit(int[] prices) {
int minprice =prices[0];
int maxout = 0;
for(int i =0;i<prices.length;i++){
if(prices[i]<minprice){
minprice = prices[i];
}else if(prices[i]-minprice>maxout){
maxout = prices[i]-minprice;
}
}
return maxout;
}
}
2. 买卖股票的最佳时机 II(LeetCode 122 题)
2.1题目
2.2思路
接上题的思路,我们可以把本题拆成很多段最大抛售的和的结果。
这也是本题的核心思想。那么我们怎么找到这些最大抛售的拆分点呢?也很简单,如果股票跌了,我们都想有特异功能,回到昨天抛掉之前的股票。
那么在本题中,如果[i+1]值小于[i]我们实现抛售操作即可。同时小心指针超范围哦。
抛售操作具体做什么,更新最大抛售额为0(实现本质的抛售操作),就是局部最小值至为当前的第一个点的值,同时更新总值(首先判断我们后面是否还有数据,也就是判断数组指针是否合法)。
本解法的时间复杂度为N,空间复杂度为1。
2.3代码
class Solution {
public int maxProfit(int[] prices) {
int minprice =prices[0];
int maxout = 0;
int maxp = 0;
for(int i =0;i<prices.length;i++){
if(prices[i]<minprice){
minprice = prices[i];
}else if(prices[i]-minprice>maxp){
maxp = prices[i]-minprice;
}
if(i+1<prices.length&&prices[i]>prices[i+1]){
maxout += maxp;
maxp = 0;
minprice = prices[i+1];
continue;
}
}
if(maxp!=0) maxout += maxp;
return maxout;
}
}
3. 二叉树中的最大路径和(LeetCode 124题)
3.1题目
3.2思路
本题为求得最大路径和。也就是说我们求得的路径除了首部可以连接左右子树,其左右子树必须为单链子树。
我们可以通过递归的方法解答这道题。同时采用max的变量来记录最大的路径值。
从根部出发,遍历左右子树的val值,选择子树的最大路径。之后计算左右子树的最大路径以及根的和。同时刷新max。遍历完整棵树即可得到最大路径的值、
如果左右子树求得的val为负,我们可以直接将左子树或者右子树值赋值为0。
当我们向下遍历时应该注意我们的return值只能是单链的,因此我们返回root.val+Math.max(leftval+rightval)。而我们向下遍历的同时也可以顺便求得子树的最大路径值。
一个递归两个作用。这样就有了以下的代码,非常巧妙。[2]
3.3代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxPathSum1(root) ;
return maxSum;
}
public int maxPathSum1(TreeNode root) {
if(root == null) return 0;
int leftval = Math.max(maxPathSum1(root.left),0);
int rightval = Math.max(maxPathSum1(root.right),0);
int maxp = leftval+rightval+root.val;
maxSum = Math.max(maxSum,maxp);
// 这里为子路径,子路径和根路径的计算有所不同,
//如果根路径可以算入任意位置为起点,但是子路径只能选择其中一颗子树。
//这里如果需要递归,就不能包含其中子节点的所有左右节点,只能选择其中的路径。
return root.val+Math.max(leftval,rightval);
}
}