范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

程序员算法实现买卖股票的最佳时机系列问题

  LeetCode 121. 买卖股票的最佳时机#
  主要思路:因为只有一股可以交易,所以我们可以枚举必须以i位置作为卖出时机的情况下,得到的最大收益是多少。如果我们得到每个i位置的最大收益,那么最大收益必是所有位置的最大收益的最大值。
  使用两个变量:
  min变量:表示遍历到的位置之前的最小值是什么。
  max变量:表示当前收集到必须以i位置卖出的最大收益是多少。
  遍历数组一遍,在遍历到i位置的时候,min和max的更新逻辑如下:min = Math.min(arr[i], min); // 每次遍历到的arr[i]和全局min进行比较,看能否刷新min的值 max = Math.max(arr[i] - min, max); // arr[i] - min 表示必须以i位置卖出时候的最大收益是什么,和全局的max值pk的最大值赋予max
  遍历完数组,返回max的值就是最终答案。完整代码见:public class LeetCode_0121_BestTimeToBuyAndSellStock {     public int maxProfit(int[] arr) {         int max = 0;         int min = arr[0];         for (int i = 1; i < arr.length; i++) {             min = Math.min(arr[i], min);             max = Math.max(arr[i] - min, max);         }         return max;     } } LeetCode 122. 买卖股票的最佳时机 II#
  主要思路:由于可以进行任意次的交易,但是任何时候最多只能持有一股股票,所以我们可以把股票曲线的所有上升段都抓取到,累加收益就是最大收益。遍历数组,遍历到的位置减去前一个位置的值,如果是正数,就收集,如果是负数,就把本次收益置为0(就等于没有做这次交易),这样遍历一遍数组,就不会错过所有的收益。
  设置一个变量max,初始为0,用于收集最大收益值,来到i位置,max更新逻辑如下:max += Math.max((prices[i] - prices[i - 1]), 0);
  完整代码如下:public int maxProfit(int[] prices) {    int max = 0;    for (int i = 1; i < prices.length; i++) {         // 把所有上坡都给抓到         max += Math.max((prices[i] - prices[i - 1]), 0);    }    return max; }
  由本题可以简单得出一个结论:如果数组元素个数为N,则最多执行N/2次交易就可以抓取所有的上升段的值(极端情况下,当前时刻买,下一个时刻卖,保持这样的交易一直到最后,执行的交易次数就是N/2)。LeetCode 188. 买卖股票的最佳时机 IV#
  主要思路:如果k的值大于等于数组长度的二分之一,就等于有无限次交易,在这样的情况下,可以直接用问题二的解法来做。如果k的值小于数组长度的二分之一,就需要单独考虑了。
  在第2种情况下,我们定义int[][] dp = new int[N][k+1]
  其中dp[i][j]表示[0...i]范围内交易j次获得的最大收益是多少。如果可以把dp这个二维表填好,那么返回dp[N-1][k]的值就是题目要的答案。
  dp这个二维矩阵中,
  第一行的值表示数组[0..0]范围内,交易若干次的最大收益,显然,都是0。
  第一列的值表示数组[0...i]范围内,交易0次获得的最大收益,显然,也都是0。
  针对任何一个普遍位置dp[i][j]的值,
  我们可以枚举i位置是否参与交易,如果i位置不参与交易,那么dp[i][j] = dp[i-1][j],如果i位置参与交易,那么i位置一定是最后一次的卖出时机。
  那最后一次买入的时机,可以是如下情况:
  最后一次买入的时机在i位置,那么dp[i][j] = dp[i][j-1] - arr[i] + arr[i]
  最后一次买入的时机在i-1位置,那么dp[i][j] = dp[i-1][j-1] - arr[i-1] + arr[i]
  最后一次买入的时机在i-2位置,那么dp[i][j] = dp[i-2][j-1] - arr[i-2] + arr[i]
  ...
  最后一次买入的时机在0位置,那么dp[i][j] = dp[0][j-1] - arr[0] + arr[i]// i位置不参与交易,则dp[i][j]至少是dp[i-1][j] dp[i][j] = dp[i - 1][j]; for (int m = 0; m <= i; m++) {     // 枚举每次买入的时机     dp[i][j] = Math.max(dp[m][j - 1] - arr[m] + arr[i] , dp[i][j]); }
  完整代码如下:public class LeetCode_0188_BestTimeToBuyAndSellStockIV {     public static int maxProfit(int k, int[] arr) {         if (arr == null || arr.length < 2) {             return 0;         }         int N = arr.length;         if (k >= N >> 1) {             return infinityMax(arr);         }         int[][] dp = new int[N][k + 1];         for (int i = 1; i < N; i++) {             for (int j = 1; j <= k; j++) {                 // i位置不参与交易,则dp[i][j]至少是dp[i-1][j]                 dp[i][j] = dp[i - 1][j];                 for (int m = 0; m <= i; m++) {                     // 枚举每次买入的时机                     dp[i][j] = Math.max(dp[m][j - 1] - arr[m] + arr[i], dp[i][j]);                 }             }         }         return dp[N - 1][k];     }       public static int infinityMax(int[] arr) {         int ans = 0;         for (int i = 1; i < arr.length; i++) {             ans += Math.max(arr[i] - arr[i - 1], 0);         }         return ans;     } }
  上述代码中包含一个枚举行为dp[i][j] = dp[i - 1][j] + arr[i] - arr[i]; for (int m = 0; m <= i; m++) {    // 枚举每次买入的时机    dp[i][j] = Math.max(dp[m][j - 1] - arr[m] + arr[i], dp[i][j]); }
  增加了时间复杂度,我们可以优化这个枚举。
  我们可以举一个具体的例子来说明如何优化,
  比如,
  当我们求dp[5][3]这个值,我们可以枚举5位置是否参与交易,假设5位置不参与交易,那么dp[5][3] = dp[4][3],假设5位置参与交易,那么5位置一定是最后一次的卖出时机。那最后一次买入的时机,可以是如下情况:
  最后一次买入的时机在5位置,那么dp[5][3] = dp[5][2] - arr[5] + arr[5]
  最后一次买入的时机在4位置,那么dp[5][3] = dp[4][2] - arr[4] + arr[5]
  最后一次买入的时机在3位置,那么dp[5][3] = dp[3][2] - arr[3] + arr[5]
  最后一次买入的时机在2位置,那么dp[5][3] = dp[2][2] - arr[2] + arr[5]
  最后一次买入的时机在1位置,那么dp[5][3] = dp[1][2] - arr[1] + arr[5]
  最后一次买入的时机在0位置,那么dp[5][3] = dp[0][2] - arr[0] + arr[5]
  我们求dp[4][3]这个值,我们可以枚举4位置是否参与交易,假设4位置不参与交易,那么dp[4][3] = dp[3][3],假设4位置参与交易,那么4位置一定是最后一次的卖出时机。那最后一次买入的时机,可以是如下情况:
  最后一次买入的时机在4位置,那么dp[4][3] = dp[4][2] - arr[4] + arr[4]
  最后一次买入的时机在3位置,那么dp[4][3] = dp[3][2] - arr[3] + arr[4]
  最后一次买入的时机在2位置,那么dp[4][3] = dp[2][2] - arr[2] + arr[4]
  最后一次买入的时机在1位置,那么dp[4][3] = dp[1][2] - arr[1] + arr[4]
  最后一次买入的时机在0位置,那么dp[4][3] = dp[0][2] - arr[0] + arr[4]
  比较dp[5][3]和dp[4][3]的依赖关系,可以得到如下结论:
  假设在求dp[4][3]的过程中,以下递推式的最大值我们可以得到
  dp[4][2] - arr[4]
  dp[3][2] - arr[3]
  dp[2][2] - arr[2]
  dp[1][2] - arr[1]
  dp[0][2] - arr[0]
  我们把以上式子的最大值定义为best,那么
  dp[5][3] = Math.max(dp[4][3],Math.max(dp[5][2] - arr[5] + arr[5], best + arr[5]))
  所以dp[5][3]可以由dp[4][3]加速得到,
  同理,
  dp[4][3]可以通过dp[3][3]加速得到,
  dp[3][3]可以通过dp[2][3]加速得到,
  dp[2][3]可以通过dp[1][3]加速得到,
  dp[1][3]可以很简单得出,dp[1][3]有如下几种可能性:
  可能性1,1位置完全不参与,则int p1 = dp[0][3]
  可能性2,1位置作为最后一次的卖出时机,买入时机是1位置int p2 = dp[1][2] + arr[1] - arr[1]
  可能性3,1位置作为最后一次的卖出时机,买入时机是0位置int p3 = dp[0][2] + arr[1] - arr[0]
  此时,best的值为int best = Math.max(p2 - arr[1], p3 - arr[1])
  然后通过dp[1][3]加速dp[2][3],通过dp[2][3]加速dp[3][3]......,所以二维dp的填写方式是按列填,
  先填dp[1][0],dp[1][2]一直到dp[1][k],填好第一列;
  然后填dp[2][0],dp[2][1]一直到dp[2][k],填好第二列;
  ...
  依次填好每一列,直到填完第N-1列。
  枚举行为被优化,优化枚举后的完整代码如下:public class LeetCode_0188_BestTimeToBuyAndSellStockIV {      public static int maxProfit(int k, int[] arr) {         if (arr == null || arr.length < 2) {             return 0;         }         int N = arr.length;         if (k >= N >> 1) {             return infinityMax(arr);         }         int[][] dp = new int[N][k + 1];         for (int j = 1; j <= k; j++) {             int p1 = dp[0][j];             int best = Math.max(dp[1][j - 1] - arr[1], dp[0][j - 1] - arr[0]);             dp[1][j] = Math.max(p1, best + arr[1]);             for (int i = 2; i < N; i++) {                 p1 = dp[i - 1][j];                 best = Math.max(dp[i][j - 1] - arr[i], best);                 dp[i][j] = Math.max(p1, best + arr[i]);             }         }         return dp[N - 1][k];     }      public static int infinityMax(int[] arr) {         int ans = 0;         for (int i = 1; i < arr.length; i++) {             ans += Math.max(arr[i] - arr[i - 1], 0);         }         return ans;     } } LeetCode 123. 买卖股票的最佳时机 III#
  主要思路:上一个问题中,令k=2就是本题的答案。LeetCode 309. 最佳买卖股票时机含冷冻期#
  主要思路:因为有了冷冻期,所以每个位置的状态有如下三种:冷冻期持有股票不持有股票,不在冷冻期
  定义三个数组,分别表示i位置这三种情况下的最大值是多少// 处于冷冻期 int[] cooldown = new int[N]; // 持有股票 int[] withStock = new int[N]; // 不持有股票,也不处于冷冻期 int[] noStock = new int[N];
  显然有如下结论:// 0位置需要处于冷冻期,说明0位置买了又卖掉,收益是0 cooldown[0] = 0;  // 0位置需要持有股票,只有可能在0位置买了一股,这个时候收益为0-arr[0] withStock[0] = -arr[0]; // 0位置没有股票,也不在冷冻期,说明在0位置就没有做任何决策。此时收益也是0 noStock[0] = 0;
  针对一个普遍位置i// 如果i位置要处于冷冻期,那么前一个位置必须持有股票,且在当前位置卖掉,处于cooldown状态 cooldown[i] = withStock[i - 1] + arr[i]; // 如果i位置要持有股票,那么前一个位置可以持有股票,到当前位置不做决策,或者前一个位置没有股票,当前位置买入一股 withStock[i] = Math.max(withStock[i - 1], noStock[i - 1] - arr[i]); // 如果i位置没有股票,那么前一个位置可能也没股票,或者前一个位置是冷冻期,到当前位置也没有进行买入动作 noStock[i] = Math.max(noStock[i - 1], cooldown[i - 1]);
  最大收益就是如上三种方式的最大值。完整代码见:public class LeetCode_0309_BestTimeToBuyAndSellStockWithCooldown {     public static int maxProfit(int[] arr) {         if (arr.length < 2) {             return 0;         }         int N = arr.length;         // 处于冷冻期         int[] cooldown = new int[N];         // 持有股票         int[] withStock = new int[N];         // 不持有股票,也不处于冷冻期         int[] noStock = new int[N];         cooldown[0] = 0;         withStock[0] = -arr[0];         noStock[0] = 0;         for (int i = 1; i < arr.length; i++) {             withStock[i] = Math.max(withStock[i - 1], noStock[i - 1] - arr[i]);             cooldown[i] = withStock[i - 1] + arr[i];             noStock[i] = Math.max(noStock[i - 1], cooldown[i - 1]);         }         return Math.max(cooldown[N - 1], Math.max(withStock[N - 1], noStock[N - 1]));     } }
  由于三个数组有递推关系,所以可以用三个变量替换三个数组,做空间压缩,优化后的代码如下:public class LeetCode_0309_BestTimeToBuyAndSellStockWithCooldown {         // 空间压缩版本     public static int maxProfit(int[] arr) {         if (arr.length < 2) {             return 0;         }         // 处于冷冻期         int cooldown = 0;         // 持有股票         int withStock = -arr[0];         // 不持有股票,也不处于冷冻期         int noStock = 0;          for (int i = 1; i < arr.length; i++) {             int next1 = Math.max(withStock, noStock - arr[i]);             int next2 = withStock + arr[i];             int next3 = Math.max(noStock, cooldown);             withStock = next1;             cooldown = next2;             noStock = next3;         }         return Math.max(cooldown, Math.max(withStock, noStock));     } } LeetCode 714. 买卖股票的最佳时机含手续费#
  主要思路:由于没有冷冻期,所以在i位置的时候,状态只有两种// withStock[i]表示:i位置有股票的状态下,最大收益 int[] withStock = new int[arr.length]; // noStock[i]表示:i位置没有股票的状态下,最大收益 int[] noStock = new int[arr.length];
  针对0位置// 0位置持有股票,最大收益,只可能是0位置买入一股 withStock[0] = -arr[0]; // 0位置不持有股票,最大收益,只能是0位置不做交易,收益为0,如果0位置做交易,收益就是(0 - arr[i] + arr[i] - fee),显然小于0 noStock[0] = 0;
  针对普遍位置i// i位置需要有股票,说明i位置的股票可以是i-1位置到现在不交易获得的,也可以是i-1位置没有股票,买下当前这一股获得的 withStock[i] = Math.max(withStock[i - 1], noStock[i - 1] - arr[i]); // i位置没有股票,说明i位置的股票可以由i-1位置上有股票的状态到当前位置卖出一股(含手续费),也可以是沿用上一个位置没有股票的最大收益 noStock[i] = Math.max(withStock[i - 1] + arr[i] - fee, noStock[i - 1]);
  完整代码如下:public class LeetCode_0714_BestTimeToBuyAndSellStockWithTransactionFee {     public static int maxProfit1(int[] arr, int fee) {         if (arr.length < 2) {             return 0;         }         int[] withStock = new int[arr.length];         int[] noStock = new int[arr.length];         // 持有股票         withStock[0] = -arr[0];         // 不持有股票         noStock[0] = 0;         for (int i = 1; i < arr.length; i++) {             withStock[i] = Math.max(withStock[i - 1], noStock[i - 1] - arr[i]);             noStock[i] = Math.max(withStock[i - 1] + arr[i] - fee, noStock[i - 1]);         }         return Math.max(withStock[arr.length - 1], noStock[arr.length - 1]);     } }
  同样的,两个数组都有递推关系,可以做空间压缩,简化后的代码如下:public class LeetCode_0714_BestTimeToBuyAndSellStockWithTransactionFee {      public static int maxProfit(int[] arr, int fee) {         if (arr.length < 2) {             return 0;         }         // 持有股票         int withStock = -arr[0];         // 不持有股票         int noStock = 0;         for (int i = 1; i < arr.length; i++) {             int next1 = Math.max(withStock, noStock - arr[i]);             int next3 = Math.max(withStock + arr[i] - fee, noStock);             withStock = next1;             noStock = next3;         }         return Math.max(withStock, noStock);     } }
  原文链接:买卖股票的最佳时机系列问题 - Grey Zeng - 博客园

汽车狂人李书福,闯入手机腹地伯虎点睛醉翁之意不在酒。李书福造手机。这6个字,从左到右一个一个地看了几遍,个人的震惊程度不亚于今年3月,雷军宣布造车。不管是李书福造手机还是雷军造车,都有异曲同工之妙都让人摸不着130亿美元打水漂,Facebook非死不可?Facebook的丑闻迎来新套餐!两周前,华尔街日报等媒体开始发布针对Facebook相关的一系列报道,通过Facebook公司的内部调查报告文件,列举了世界上最大的社交网络上出现只用一根线就解决Mac与4K显示器互联绿联USBCtoHDMI线体验前言上个月帮表弟选购了台ViewSonicVX24194KHD4K显示器,他的MacBookPro2020(Intel处理器)用起来还是挺好的。没用到1个月就跟我说还是想用大屏幕了5G杀手级应用在哪儿?世界互联网大会热议商业化落地2021世界互联网大会乌镇峰会进入第二天,多场分论坛围绕着当前的前沿技术展开。在5G赋能创新驱动经济高质量发展上,多位行业专家企业高层就5G的商业化落地展开热议。能够推动5G快速商MIUI13要来了!新功能真刺激,怎么用怎么爽小雷看了眼时间,手持小米骁龙865骁龙888机型的小伙伴,应该都顺利用上了MIUI12。5增强版。至于第二批还得等到10月底才能全量推送,这种更新速度放在行业内不算慢。但对于小米自5G演进已开始,6G研究正进行在2021年世界互联网大会乌镇峰会世界互联网领先科技成果发布活动上,记者就5G6G相关技术发展现状及进展情况,专访了中国工程院院士北京邮电大学教授张平。作为无线移动通信专家,张平院该来的还是来了!美要求台积电上缴代工数据,意味着什么?受全球性缺芯问题的影响,最近这一年来,各大芯片代工厂都遭受了一定的损失。为了维持自身的营收和利润,这些代工厂先后提高了晶圆生产的价格,其客户在进行芯片代工业务时,需要付出更多的成本华为nova再添新星,nova9系列哪些提升?nova之路如何前进华为虽然被美国一纸禁令限制了手机移动端的发展,随着今年四五轮制裁的不断加强,本来华为业内领先的5G技术却因为这一纸禁令无法在自家手机上应用。无论是华为P50系列还是此次的nova9孟晚舟传奇两段结果截然不同的婚姻在加拿大被拘禁的孟晚舟,如今已回到祖国怀抱。2018年年底,孟晚舟案一出,震惊了无数国人。曾经,外媒爆出孟晚舟在被迫居家在温哥华的期间,曾经收到多封带有子弹的匿名死亡威胁信件!她的任正非的三个子女为啥不同姓手机大佬任正非先生,中共党员,1944年生于贵州省安顺市镇宁县,祖籍浙江省金华市浦江县。华为技术有限公司主要创始人兼总裁。任先生有三个子女。大女儿叫孟晚舟,华为副董事长,1972年互联网拆墙先过支付关消息属实,会继续与其他平台一起面向未来,相向而行。9月28日,面对市场上阿里旗下多应用接入微信支付的传言,阿里给出了肯定的回答。据悉,阿里旗下饿了么优酷大麦考拉海购书旗等应用均已接
2698元的vivoiQOONeo3真香!最便宜的骁龙865手机iQOONeo3是Neo系列的首款5G产品,将从各个方面提升使用体验。不过最吸引人的是其价格,6G128G2698元,8G128G2998元,12G128G3298元,8G256G微易客安徽女子跳河事件解析12月4日安徽女子跳河寻死事件发生之后,网络上一直存在着红黑两种声音。黑方的观点是警察或有错或有责或有罪,红方则认为警察既没错也没责更没罪。红黑双方至今依然在争吵不休,争赢了又能怎一带一路北斗产业应用平台建设项目成果展示交流会成功举办2020年12月29日,由中国卫星导航定位协会主办的主题为北斗产业新格局数字底座新时空的一带一路北斗产业应用平台建设项目成果展示交流会成功在京举行,汇聚了北斗领域相关领导行业专家和文昌国际航天城航天超算大数据服务项目推介会成功举办2021年3月13日下午,由文昌国际航天城管理局文昌市人民政府联合主办,海南现代科技集团有限公司承办的发展航天数据产业,服务智慧海南建设文昌国际航天城航天超算大数据服务项目推介会在名企头条中国40岁以下商界精英榜发布,京东一季度净收入1462亿中国40岁以下商界精英榜张一鸣程维等上榜财富(中文版)发布了2020年中国40位40岁以下商界精英榜,字节跳动创始人兼首席执行官张一鸣滴滴出行创始人兼首席执行官程维快手创始人兼首席名企头条再招5000人!阿里云大规模引进顶级科技人才再招5000人!阿里云大规模引进顶级科技人才6月9日,在2020阿里云峰会上,阿里云智能总裁张建锋表示,阿里云今年再招5000人,大规模引进顶级科技人才,重点吸引服务器网络芯片数据罗永浩锤子科技是一次严重的高考失利,还完6亿债重振锤子科技7月9日消息,一年一度的高考刚刚结束,高考也被成为是一次人生的转折点。7月8日晚间,锤子科技创始人罗永浩发表了主题为人生,不止一次高考的演讲。罗永浩表示,作为一个高考辍学生,没想到秦皇岛男子五次被处罚,每一次都与酒有关近日,秦皇岛一男子因醉酒驾驶机动车被交警支队二大队民警查获,在对其进行信息核查时民警发现该男子涉嫌严重交通违法条数众多,而且条条都与酒驾醉驾有关。民警将驾驶员带至路边,该人走路摇晃石头科技的扫地机器人值得买吗?这个问题,首先得从我们对扫地机器人的需求和石头科技本身说起。随着生活水平的提高,我们可以说是越来越懒了,能交给机器的工作绝不自己亲手上(比如我),据调查,人们对于扫地机器人的要求,牛听听读书牛早教机能读绘本会说话,功能强大去年逛东盟博览会的时候,看到起码有几十家摆有早教机产品,让我意识到不论是线上还是线下,早教机产品已经相当常见了。因为家里有两个小宝贝,我接触过的早教机产品也有不少款,这些产品功能上魅族16s和OPPOR17Pro拍照细节对比,结果可能让你难以接受前言618的时候,下单了2399元的魅族16s和1999元的OPPOR17Pro。618大幅跳水的手机很多,之所以选择这两款,无外乎是觉得它们性价比高。今年旗舰机魅族16s官降50