Day32 代码随想录算法训练营 第八章 贪心算法 part02|122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II
今日内容
- 122.买卖股票的最佳时机II
- 55. 跳跃游戏
- 45.跳跃游戏II
122.买卖股票的最佳时机Ⅱ (简单)
问题:
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。

该数组为由大到小的降序数组,则隔天抛售会亏本,最大获益为0
该数组为由小到大的升序数组,则首位两端交易,获益最大为nums[nums.length-1] - nums[0]
将该题看成序列,则两相邻的峰谷和峰顶之间交易,叠加起来,获益最大
情况一:单调升序坡:数组收尾两端交易=前后两两局部交易,全部叠加:if(prediff>0 && curdiff >0) res+=curdiff
情况二:单调降序坡:不交易,最大获益为0;
情况三:摆动序列:① if((prediff<=0 && curdiff >0)){res+=curdiff}
情况一、三合并:if(curdiff>0) res+=curdiff;
1 // @lc code=start 2 /** 3 * @param {number[]} prices 4 * @return {number} 5 */ 6 var maxProfit = function(prices) { 7 let curdiff = 0; // 如果大于0,则也代表局部利润 8 let res = 0; // 记录总利润 9 10 for (let i = 0; i < prices.length - 1; i++) { 11 curdiff = prices[i + 1] - prices[i]; 12 if (curdiff > 0) { 13 res += curdiff; 14 } 15 } 16 return res; 17 };
55.跳跃游戏
问题:
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

提示:
1 <= nums.length <= 1040 <= nums[i] <= 105
思路:用回溯的思想帮助遍历每一种可能性(但是时间会超时)
局部贪心:遇到一条可以走对的路径就不需要再继续了
转换成:① 是否每一步均可跳跃,② 最后跳跃的位置是否是数组的最优一个下标
下面代码不确定对错,自己的思路,纯当记录,时间超时了!!!
1 // @lc code=start 2 /** 3 * @param {number[]} nums 4 * @return {boolean} 5 */ 6 var canJump = function(nums) { 7 let sumStep = 0; //记录总跳跃数; 8 let res = false; 9 let path = []; //记住路径 10 11 backtracking(0, nums[0]); // 12 return res; 13 14 15 function backtracking(startIndex, maxstep) { 16 // 终止条件 17 if (startIndex === nums.length - 1) { //有一条路径走对了则可以返回true,如何在这一步就不往下走了呢? 18 res = true; 19 return true; 20 } 21 if (startIndex < nums.length - 1 && maxstep === 0) { //永远走不过去了 22 res = false; 23 return false; 24 } 25 if (startIndex >= nums.length) //已经走过了 26 { 27 res = false; 28 return false; 29 } 30 31 for (let step = 1; step <= maxstep; step++) { 32 if (res) break; //有一条路径走对了则可以返回true,后面无须判断 33 path.push(startIndex + step); 34 backtracking(startIndex + step, nums[startIndex + step]); 35 path.pop() 36 } 37 } 38 };
贪心策略:
这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。
注意:最小步数是1,所以只需要找最大跨几步即可!
代码实现:
1 // @lc code=start 2 /** 3 * @param {number[]} nums 4 * @return {boolean} 5 */ 6 var canJump = function(nums) { 7 if (nums.length === 1) return true 8 let cover = 0 //覆盖范围 9 for (let i = 0; i <= cover; i++) { 10 cover = Math.max(cover, i + nums[i])// 更新最大覆盖范围 11 if (cover >= nums.length - 1) {//只要覆盖范围开始大于数组最后一个下标,则可以返回了!!! 12 return true 13 } 14 } 15 return false 16 };
45.跳跃游戏Ⅱ
问题:
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。
每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:
0 <= j <= nums[i]i + j < n
返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。

提示:
1 <= nums.length <= 1040 <= nums[i] <= 1000- 题目保证可以到达
nums[n-1]
要从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最少步数!
这里需要统计两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖。
如果移动下标达到了当前这一步的最大覆盖最远距离了,还没有到终点的话,那么就必须再走一步来增加覆盖范围,直到覆盖范围覆盖了终点。

图中覆盖范围的意义在于,只要红色的区域,最多两步一定可以到!(不用管具体怎么跳,反正一定可以跳到)
因为题目保证一定可以到达下标,则其精髓在于控制移动下标 i 只移动到 nums.size() - 2 的位置,所以移动下标只要遇到当前覆盖最远距离的下标,直接步数加一,不用考虑别的了。
1 // @lc code=start 2 /** 3 * @param {number[]} nums 4 * @return {number} 5 */ 6 var jump = function(nums) { 7 let curdistance = 0; //记录最远下标 8 let nextdistance = 0; //记录下一个最远下标 9 let step = 0; //记录最少步数 10 11 for (let i = 0; i < nums.length - 1; i++) { 12 nextdistance = Math.max(nextdistance, nums[i] + i); 13 if (curdistance === i) { 14 curdistance = nextdistance; 15 step++; 16 } 17 } 18 return step; 19 };

浙公网安备 33010602011771号