Leetcode面试经典150题-188.买卖股票的最佳时机IV

2024-08-28 12:52

本文主要是介绍Leetcode面试经典150题-188.买卖股票的最佳时机IV,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 解法都在代码里,不懂就留言或者私信,这个稍微难点,我提供了两种解法

/**基本的动态规划求解的过程 */public static int maxProfit2(int k, int[] prices) {/**题目给的数组不会为null,这里习惯性的健壮性判断如果交易日小于2,不可能获得任何的利润 */if(prices == null || prices.length < 2) {return 0;}/**思路分析:本题只限制了一个交易数量,我们可以原地买卖,也就是说如果还没有凑够k的话,我们可以当天当天卖虽然这没有任何的意义,我们使用动态规划求解:dp数组的含义是dp[i][j]代表在0~i上做j次交易可以获得最大利润i的变化范围0~prices.length-1,j的变化范围0~k有一点需要注意:如果k大于prices.length/2,那就可以无限次买卖了,那就是题目2https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii毕竟我们的动态规划时间复杂度比较高,所以能不用还是不用了*/if(k >= prices.length / 2) {int max = 0;for(int i = 1; i < prices.length; i++) {max += Math.max(0, prices[i]-prices[i-1]);}return max;} else {int[][] dp = new int[prices.length][k+1];/**根据dp数组含义,最后我们要的是0~prices.length-1上做k次交易所能获得的最大利润*//**我们先初始化第一行,也就是在0~0上做0~k次交易,同一天买同一天卖不可能有任何利润*/for(int j = 0; j <= k; j++) {dp[0][j] = 0;}/**第一列也可以先初始化了,也就是0~i上不做交易,不做交易当然是0了,其实int默认是0,第一行和第一列都不用初始化这样写看起来比较清晰*/for(int i = 0; i < prices.length; i++) {dp[i][0] = 0;}/**对于一般的情况,i和j的下标都从1开始 */for(int i = 1; i < prices.length; i++) {for(int j = 1; j <= k; j++) {/**0~i上做j次交易有两种情况:1.前面0~i-1已经做了j次交易,这里直接等于dp[i-1][j]*/int p1 = dp[i-1][j];/**第二种情况;前面0~0,0~1...0~i-1做了j-1次交易,然后前面最后一次交易的那天买入,当前卖出 */int p2 = 0;for(int pre = 0; pre < i; pre ++) {p2 = Math.max(p2, dp[pre][j-1] + prices[i] - prices[pre]);}dp[i][j] = Math.max(p1, p2);}}return dp[prices.length - 1][k];}}/**动态规划+斜率优化的解法,最优解*/public static int maxProfit(int k, int[] prices) {/**题目给的数组不会为null,这里习惯性的健壮性判断如果交易日小于2,不可能获得任何的利润 */if(prices == null || prices.length < 2) {return 0;}/**思路分析:本题只限制了一个交易数量,我们可以原地买卖,也就是说如果还没有凑够k的话,我们可以当天当天卖虽然这没有任何的意义,我们使用动态规划求解:dp数组的含义是dp[i][j]代表在0~i上做j次交易可以获得最大利润i的变化范围0~prices.length-1,j的变化范围0~k有一点需要注意:如果k大于prices.length/2,那就可以无限次买卖了,那就是题目2https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii毕竟我们的动态规划时间复杂度比较高,所以能不用还是不用了*/if(k > prices.length) {int max = 0;for(int i = 1; i < prices.length; i++) {max += Math.max(0, prices[i]-prices[i-1]);}return max;} else {int[][] dp = new int[prices.length][k+1];/**根据dp数组含义,最后我们要的是0~prices.length-1上做k次交易所能获得的最大利润*//**我们先初始化第一行,也就是在0~0上做0~k次交易,同一天买同一天卖不可能有任何利润*/for(int j = 0; j <= k; j++) {dp[0][j] = 0;}/**第一列也可以先初始化了,也就是0~i上不做交易,不做交易当然是0了,其实int默认是0,第一行和第一列都不用初始化这样写看起来比较清晰*/for(int i = 0; i < prices.length; i++) {dp[i][0] = 0;}/**对于一般的情况,i和j的下标都从1开始 */for(int j = 1; j <= k; j++) {int preMax = 0;for(int i = 1; i < prices.length; i++) {/**0~i上做j次交易有两种情况:1.前面0~i-1已经做了j次交易,这里直接等于dp[i-1][j],和基本动态规划相比,p1没变*/int p1 = dp[i-1][j];/**第二种情况;前面0~0,0~1...0~i-1做了j-1次交易,然后前面最后一次交易的那天买入,当前卖出普通动态规划的解法我们有个枚举的过程,这里使用斜率优化给它省略了dp[2][3]=Math.max(dp[0][2] + prices[2]-prices[0], dp[1][2]+price[2]-prices[1],dp[2][2]+price[2]-prices[2])dp[3][3]=Math.max(dp[0][2] + prices[3]-prices[0], Math.max(dp[1][2]+price[3]-prices[1])), dp[2][2]+price[3]-prices[2])),dp[3][2]+prices[3]-prices[3])这里我们可以发现的规律是dp[0][2]-prices[0]和dp[1][2]-prices[1]对于dp[2][3]和dp[3][3]都有而dp[3][3]多出了dp[3][2]+prices[3]-prices[3]这一项(就是dp[3][2])所以如果我们算dp[2][3]的时候知道dp[0][2]-prices[0]和dp[1][2]-prices[1]谁比较大,算dp[3][3]的时候直接用这个结果就行那这个结果存在哪里了呢?dp[2][3]是这两个值的最大值+prices[2]算出来的,那这个值不就是dp[2][3]-prices[2]吗所以我们可以得到的是dp[3][3]=Math.max(dp[2][3]-prices[2] +prices[3], dp[3][2])抽象成一般位置dp[i][j]=Math.max(dp[i-1][j]-prices[i-1]+prices[i], dp[i][j-1])这个其实也可以写成max(dp[i-1][j]-price[i-1],dp[i][j-1]-prices[i]) + prices[i]前面的部分max(dp[i-1][j]-price[i-1],dp[i][j-1]-prices[i])我们叫它preMax正常这么处理是没有什么问题的这里举个特殊的例子,dp[2][1] = dp[0][0]+prices[2]-prices[0]  dp[1][0]+ prices[2]-prices[1] dp[2][0]dp[1][1] = dp[0][0]+prices[1]-prices[0] dp[1][0]+prices[1]-prices[1]dp[2][1] = Math.max(dp[i-1][j]-price[i-1],dp[i][j-1]-prices[i]) + prices[i]但是对于dp[1][1]呢,它能等于max(dp[i-1][j]-price[i-1],dp[i][j-1]-prices[i]) + prices[i]吗肯定不能啊,因为这里dp[0][j]-prices[0]+prices[1]也就是在0~0上交易了1次?然后又减去了prices[1]和prices[0]的差价,这不是交易两次吗*/int p2 = Math.max(i == 1? prices[i]-prices[i-1]: preMax+prices[i], dp[i][j-1]);preMax = p2 - prices[i];dp[i][j] = Math.max(p1, p2);}}return dp[prices.length - 1][k];}}

运行结果

e6860088515a469ea16c235c484b1351.jpg

这篇关于Leetcode面试经典150题-188.买卖股票的最佳时机IV的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1114817

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

java面试常见问题之Hibernate总结

1  Hibernate的检索方式 Ø  导航对象图检索(根据已经加载的对象,导航到其他对象。) Ø  OID检索(按照对象的OID来检索对象。) Ø  HQL检索(使用面向对象的HQL查询语言。) Ø  QBC检索(使用QBC(Qurey By Criteria)API来检索对象。 QBC/QBE离线/在线) Ø  本地SQL检索(使用本地数据库的SQL查询语句。) 包括Hibern