小白学算法:买卖股票的最佳时机!

作者 | 王磊

来源 | Java中文社群(ID:javacn666)

转载请联系授权(微信ID:GG_Stone)

本文已收录至 Github《小白学算法》系列:https://github.com/vipstone/algorith

今天蚂蚁集团(支付宝)正式上市了,毫无疑问这一举措又造就了一大批富豪,然而作为局外人的我们,也只有羡慕的份了。明明可以靠运气吃饭,咱非得靠实力,你说亏不亏啊?

但话又说回来,能进蚂蚁的人也都是牛人,那咱也赶紧提升一下技能吧,好为下一个“蚂蚁”做足准备。

今天的这道题比较有意思,是关于「买卖股票」的,题目如下。

题目描述

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

注意:你不能在买入股票前卖出股票。

示例 1:

输入: [7,1,5,3,6,4]

输出: 5

解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。    注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入: [7,6,4,3,1]

输出: 0

解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:LeetCode

剑指 offer 64:https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/submissions/难度:中

leetcode 121:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/难度:简单

解题思路

根据题目的意思我们知道,我们只有一次交易的机会,也就是买一次再卖一次,但同时要保证收益最大化。那我们本能的直觉是在最低的价格买入,再在最高的价格卖出就好了,如下图所示:


但这有一个问题,就是我们要保证最高价格要在最低的价格之后,因为我们必须在购买了股票之后才能卖出,而不是相反的顺序,这就让问题变的复杂了。

但此刻我们想到了一个最直接也是最笨的一个方法,那就是用暴力穷举法,我们使用两层循环,依次在每个节点买入,然后再在之后的所有节点卖出,这样来计算节点间的差值(收益),如果此差值大于当前最高收益,就将此值设置为当前最高收益,这样循环完,我们就能获得最大收益了。如下图所示:


方法一:暴力法

有了上面的思路,接下来我们用代码实现一下:

class Solution {public int maxProfit(int[] prices) {int mp = 0; // 最高收益for (int i = 0; i < prices.length; i++) {for (int j = i + 1; j < prices.length; j++) {int item = prices[j] - prices[i];if (item > mp) mp = item;}}return mp;}
}

可以看出代码还是很简单的,但别高兴得太早,我们来看它在 leetcode 上的表现:

复杂度分析

  • 时间复杂度:O(n^2),循环运行 n(n-1)/2 次。

  • 空间复杂度:O(1),只使用了常数位的变量。

真是一顿操作猛如虎,最终击败百分之五!如果用这种代码去面试的话,估计只能回去等通知了。那有没有更好的方法呢?答案是肯定的,继续往下看。

方法二:遍历一次

对于这道题我们其实可以使用一次循环来实现,先来看下面的这张折线图:


从上面的图片我们可以看出,我们在每个节点其实只会做两件事(第一个节点除外,只能买入不能卖出),这两件事分别是:买入或卖出。那么我们其实可以用一个循环来计算出最大的利润,我们只需要依次对于每个节点做以下两个判断:

  • 判断当前节点是不是相对最低价,如果是,则将它设置为最低价(也就是买入);

  • 如果当前节点不是最低价,那我们就将它卖出,然后计算卖出的收益(当前节点减去相对最低价),如果卖出的收益大于目前的最高收益,则将此值设置为最高收益。

这样循环完成之后最高收益就出来了,实现代码如下:

class Solution {public int maxProfit(int prices[]) {if (prices == null || prices.length == 0) return 0;int mp = 0; // 最高收益int min = prices[0]; // 最低价for (int i = 1; i < prices.length; i++) {if (prices[i] < min) {// 设定相对最低价min = prices[i];} else if (mp < (prices[i] - min)) {// 设定最高盈利mp = prices[i] - min;}}return mp;}
}

以上代码在 leetcode 中的结果如下图所示:

复杂度分析

  • 时间复杂度:O(n),只需要遍历一次。

  • 空间复杂度:O(1),只使用了常数个变量。

从以上的执行的结果可以看出,这段代码还算是比较理想的,这样面试官也会对你竖起大拇指了。

总结

本文我们计算了单次(一次买入和卖出)股票的最高收益,刚开始我们使用的是最简单粗暴的暴力枚举法,使用两层循环依次相减来求出最高收益值,但这种方法的执行效率太低。

然后我们经过观察折线图发现,只需要一次循环也能找出最高的收益值。我们只需要在每个节点做两个判断,第一:判断此节点是否为相对最小值,如果是,则记录下来;如果不是,则计算此值和相对最小值是否为当前最高收益,如果是,则记录下来。那么循环一圈之后,我们就能得出最高的收益了,并且执行的效率也很高。

你学会了吗?有不懂的地方或者更好的方法,欢迎评论区留言~


往期推荐

算法图解:如何用两个栈实现一个队列?

2020-10-26

Java中的5大队列,你知道几个?

2020-10-24

一文详解「队列」,手撸队列的3种方法!

2020-10-21

关注我,每天陪你进步一点点!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第十一章并发控制

第十一章并发控制11.1_并发控制概述11.2_封锁11.1_并发控制概述 事务是并发控制的基本单位 并发操作带来的数据不一致性包括丢失修改、不可重复读、读“赃”数据 11.2_封锁 两种封锁协议&#xff1a;排他锁&#xff08;写锁&#xff09;和共享锁&#xff08;读锁&#xff09…

《APUE》第6章笔记

这一章主要介绍了口令文件和组文件的结构和一些围绕这些结构的函数。 口令文件即passwd就是在/etc/passwd中可以查阅。其结构是&#xff1a; 上图四个平台能支持的就用黑点表示。 因为加密口令这一项放在passwd这个人人可读的文件中&#xff0c;可能会有安全问题。所以现在的Li…

Oracle笔记:备份还原

--------------备份还原-------------------- --物理备份 --逻辑备份 1&#xff09;传统工具&#xff1a; exp导出、imp导入 实质&#xff1a;调用sql指令&#xff0c;导入\导出数据&#xff0c;速度较慢 可以运行在客户端&#xff0c;也可以运行在服务器端&#xff0c; 在cmd窗…

Java DataOutputStream writeByte()方法与示例

DataOutputStream类writeByte()方法 (DataOutputStream Class writeByte() method) writeByte() method is available in java.io package. writeByte()方法在java.io包中可用。 writeByte() method is used to write the given value as one-byte value to the basic stream a…

聊聊近期的感受和10月文章精选!

先来看本月的原创文章汇总&#xff0c;其中算法部分也有少量 9 月份的文章&#xff0c;这样汇总起来大家看起来更方便&#xff0c;目录如下。算法系列小白学算法第1篇&#xff1a;一文详解「栈」和手撸栈的两种方法&#xff01;小白学算法第2篇&#xff1a;JDK 竟然是这样实现栈…

第六章关系数据理论

第六章关系数据理论6.1_问题的提出&#xff08;略&#xff09;6.2_规范化6.2.1_函数依赖6.2.2_码6.2.3_范式6.2.4_2NF6.2.5_3NF6.2.6_BCNF6.2.7_多值依赖6.2.8_4NF6.2.9_规范化小结6.3_Armstrong公理系统6.3.1_函数依赖闭包6.3.2_最小依赖集6.3.3_转换为3NF的保持函数依赖的分解…

Oracle数据字典

--用户信息 select * from dba_users; --角色信息 select * from dba_roles; --权限信息 select * from dba_role_privs;--方案(Schema)是数据库对象的集合&#xff0c;每个用户都对应一个方案。用户是各种对象的所有者&#xff0c; --方案是对象的组织形式。 --用户与方案是一…

Github上的热门iOS开源项目:AFNetworking、MagicalRecord、BlocksKit以及XVim

1. AFNetworking AFNetworking是一个非常受欢迎的轻量级的iOS、Mac OS X网络通信类库。它建立在NSURLConnection、NSOperation以及其技术的基础上&#xff0c;有着精心设计的模块结构和功能丰富的API&#xff0c;让很多网络通信功能的实现变得十分简单。 附件&#xff1a;/c…

队列实现栈的3种方法,全都击败了100%的用户!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;本文已收录至 Github《小白学算法》系列&#xff1a;https://github.com/vipstone/algorith之前我们讲过《用两个栈实现一个…

Java类类getConstructor()方法及示例

类的类getConstructor()方法 (Class class getConstructor() method) getConstructor() method is available in java.lang package. getConstructor()方法在java.lang包中可用。 getConstructor() method is used to return a Constructor object that reflects the given pub…

where、having、group by、order by、count的使用注意

where、having、group by、order by、count的使用注意1_where、having、group by、order by的顺序2_group by的作用3_where和group by的组合4_group by和having的组合5_where、having、group by的组合使用6_count与group by的组合使用1_where、having、group by、order by的顺序…

Oracle备份还原

Oracle有两类备份方式&#xff1a; &#xff08;1&#xff09;物理备份&#xff1a;是将实际组成数据库的操作系统文件从一处拷贝到另一处的备份过程&#xff0c;通常是从磁盘到磁带。物理备份又分为冷备份、热备份&#xff1b; &#xff08;2&#xff09;逻辑备份&#xff1…

Eclipse快捷键-方便查找

【Ct rlT】 搜索当前接口的实现类 1. 【ALT /】 此快捷键为用户编辑的好帮手&#xff0c;能为用户提供内容的辅助&#xff0c;不要为记不全方法和属性名称犯愁&#xff0c;当记不全类、方法和属性的名字时&#xff0c;多体验一下【ALT /】快捷键带来的好处吧。 2. 【Ct rlO】…

很实用的21个SQL小技巧!

前言每一个好习惯都是一笔财富&#xff0c;本文基于MySQL&#xff0c;分SQL后悔药&#xff0c; SQL性能优化&#xff0c;SQL规范优雅三个方向&#xff0c;分享写SQL的21个好习惯&#xff0c;谢谢阅读&#xff0c;加油哈~1. 写完SQL先explain查看执行计划&#xff08;SQL性能优化…

Java ByteArrayOutputStream size()方法与示例

ByteArrayOutputStream类size()方法 (ByteArrayOutputStream Class size() method) size() method is available in java.io package. size()方法在java.io包中可用。 size() method is used to return the current size of the buffer exists. size()方法用于返回缓冲区当前存…

Oracle备份文件名获取系统时间的做法(windows)

在对数据库进行备份时&#xff0c;用数据泵的方法&#xff0c;需要执行一段代码&#xff1a; --建目录 create directory dir as d:\bak;--给用户授权使用目录 grant read,write on directory dir to scott;--在cmd中输入以下代码 expdp scott/tigerXE directorydir dumpfileab…

java getmonth_Java LocalDateTime类| 带示例的getMonth()方法

java getmonthLocalDateTime类getMonth()方法 (LocalDateTime Class getMonth() method) getMonth() method is available in java.time package. getMonth()方法在java.time包中可用。 getMonth() method is used to get the field value month-of-year based on the enum Mon…

阿里最喜欢问的多线程顺序打印的5种解法!

Keeper导读大家在换工作面试中&#xff0c;除了一些常规算法题&#xff0c;还会遇到各种需要手写的题目&#xff0c;所以打算总结出来&#xff0c;给大家个参考。全文 2929 字&#xff0c;剩下的是代码&#xff0c;P6 及以下阅读只需要 8 分钟&#xff0c;高 P 请直接关闭第一篇…

CSS入门

CSS入门1_CSS概要1.1_CSS引入方式2_CSS选择器3_字体样式3.1_字体属性3.2_字体类型&#xff1a;font-family3.3_字体大小&#xff1a;font-size3.4_字体粗细&#xff1a;font-weight3.5_字体颜色&#xff1a;color3.6_总结4_文本样式4.1_文本样式属性4.2_首行缩进&#xff1a;te…

Oracle笔记:数据库启动的三个阶段

数据库的启动可分为三个阶段&#xff1a;1、startup nomount -- 启动实例&#xff0c;不加载数据库 nomount&#xff1a;在这一阶段&#xff0c;只需要读取initSID.ora文件&#xff0c;启动数据库实例&#xff0c;创建后台进程。在initSID.ora文件中&#xff0c;可以定位…