122.买卖股票的最佳时机 II
这题感觉还是偏简单的,主要是要理解一点:本题中股票能当天买入当天卖出且能得知明天的股票价格
这个设定省去了很多麻烦,每天先无脑买入即可,如果第二天价格更高就第二天卖出,如果第二天价格更低则买入当日就卖出。
以这种策略,如果股价持续走高能吃到所有利润,如果股价持续走低也不会有任何亏损
对这种思路进行抽象,画出价格变化的折线图,累计所有上坡即可
int maxProfit(vector<int>& prices) {int pre = prices[0];int cur;int ans = 0;for (int i = 1; i < prices.size(); ++i) {cur = prices[i];if (cur > pre)ans += cur - pre;pre = cur;}return ans;
}
55.跳跃游戏
思索良久还是用递归做了(战胜了5%的用户,我真是太棒了)
递归写法:
如果一个节点能直接跳到终点,就将其作为新的终点,判断其他节点能否跳到该节点。不断将“终点”前推,如果能到达起点,说明存在起点到终点的完整路径
bool canJumpSub(vector<int>& nums, int back, vector<bool>& used) {// 终止条件:如果递归到了起点,说明连成了一条起点到终点的完整路径,返回trueif (back == 0)return true;vector<int> sub;// 如果从节点能直接跳到终点,则存入数组for (int i = 0; i < back; ++i) {if (back - i <= nums[i] && !used[i])sub.push_back(i);}for (int backIndex : sub) {// 一个节点只进行一次判断used[backIndex] = true;// 递归判断前面是否有节点能到达该节点if (canJumpSub(nums, backIndex, used)) {return true;}}return false;
}bool canJump(vector<int>& nums) {vector<bool> used(nums.size(), false);bool ans = canJumpSub(nums, nums.size() - 1, used);return ans;
}
贪心写法:
(真没想到啊,这也太简洁了)
思路:从起点开始逐步扩大覆盖范围,最后判断能否覆盖到终点
bool canJump(vector<int>& nums) {int cover = 0;for (int i = 0; i <= cover; ++i) {// 更新当前节点能覆盖到的最大范围cover = std::max(cover, i + nums[i]);if (cover >= nums.size() - 1)return true;}return false;
}
45.跳跃游戏 II
用递归做完上一题后这题一眼回溯,思路是相同的,多一步用回溯记录最小步数即可
int ans;void canJumpSub(vector<int>& nums, int back, vector<bool>& used, int count) {if (back == 0) {if (count < ans)ans = count;return;}vector<int> sub;for (int i = 0; i < back; ++i) {if (back - i <= nums[i] && !used[i])sub.push_back(i);}for (int backIndex : sub) {used[backIndex] = true;// 使用++count在回溯过程中记录步数canJumpSub(nums, backIndex, used, ++count);}return;
}
贪心写法:
思路与上一题的贪心有点类似,但写了半天一直出小问题,老笨比了
这题的重点是理清楚什么时候需要增加步数:到达当前步数下的最大覆盖范围,但尚未到达终点时需要增加步数
int jump(vector<int>& nums) {if (nums.size() == 1)return 0;int count = 0;int cover = 0; // 实时更新的最大覆盖范围(比当前多走一步能到达的最大范围)int pre = 0; // 当前步数下能到达的最大范围for (int i = 0; i < nums.size(); ++i) {cover = std::max(i + nums[i], cover);// 增加步数的时机:到达当前步数下的最大覆盖范围,但尚未到达终点时增加步数(想要到达之后的元素,步数必须+1)if (i == pre) {++count;// 步数+1后,更新当前步数下的最大范围pre = cover;// 如果多走一步后能到达终点了,直接退出并返回结果if (pre >= nums.size() - 1)break;}}return count;
}
(贪心难道真的是没套路的吗,做了两天完全理不清楚,甚至感觉每题都是不一样的题型)