【力扣】hot100系列(三)贪心(多解法+时间复杂度分析)
本专栏文章持续更新,新增内容使用蓝色表示。
121. 买卖股票的最佳时机 - 力扣(LeetCode)
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
示例 2:输入:prices = [7,6,4,3,1]
输出:0
解法一:暴力【超时】
最简单直接的一种想法,但是时间复杂度O()会超时,无法通过全部案例。
class Solution {
public:int maxProfit(vector<int>& prices) {int res=0;for (int i = 0; i < prices.size(); i++) {for (int j = i + 1; j < prices.size(); j++) {res = max(prices[j] - prices[i], res);}}return res;}
};
时间复杂度:O()。
空间复杂度:O(1)。
解法二:一次遍历
可以以买水果为例理解,你作为一个果贩,需要记录市场行情价,想通过一次买卖赚最多钱。
天数 | 第1天 | 第2天 | 第3天 | 第4天 | 第5天 | 第6天 |
---|---|---|---|---|---|---|
价格 | 7元 | 1元 | 5元 | 3元 | 6元 | 4元 |
第1天:价格7元
- 最低价 = 7元
- 今天利润 = 0(不能卖)第2天:价格1元
- 最低价 = 1元(更新!比7元便宜)
- 今天利润 = 0(不能卖)第3天:价格5元
- 最低价 = 1元(保持)
- 今天利润 = 5-1 = 4元 ← 记录第4天:价格3元
- 最低价 = 1元(保持)
- 今天利润 = 3-1 = 2元第5天:价格6元
- 最低价 = 1元(保持)
- 今天利润 = 6-1 = 5元 ← 新的最佳!第6天:价格4元
- 最低价 = 1元(保持)
- 今天利润 = 4-1 = 3元
class Solution {
public:int maxProfit(vector<int>& prices) {int minprice = prices[0];int profit = 0;for (auto& price : prices) {if (price < minprice) {minprice = price;} else {profit = max(profit, price - minprice);}}return profit;}
};
时间复杂度:O(n)。
空间复杂度:O(1)。
55. 跳跃游戏 - 力扣(LeetCode)
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
示例 2:输入:nums = [3,2,1,0,4]
输出:false示例 3:
输入:nums = [0]
输出:true
解法一
能否到达最后一个下标,关键在于可达的最长长度能否大于数组大小。以下实现此想法(贪心)最直观的实现:(注意循环条件)
class Solution {
public:bool canJump(vector<int>& nums) {if (nums.size() == 1)return true;int maxlen = 0;for (int i = 0; i < nums.size() - 1 && i <= maxlen; i++) {for (int j = i; j < i + nums[j] && j < nums.size(); j++) {maxlen = max(maxlen, j + nums[j]);if (maxlen >= nums.size() - 1)return true;}}return false;}
};
时间复杂度:O()。
空间复杂度:O(1)。
解法二
算法思想相同均为贪心,但在解法一的基础上优化了一点,仅使用单层循环,时间复杂度从O()降为O(n)。
class Solution {
public:bool canJump(vector<int>& nums) {if (nums.size() == 1)return true;int maxlen = nums[0];for (int i = 0; i < nums.size() && i <= maxlen; i++) {maxlen = max(maxlen, i + nums[i]);if (maxlen >= nums.size() - 1)return true;}return false;}
};
时间复杂度:O(n)。
空间复杂度:O(1)。
补充:评论区看到的更简洁的实现方法
不断更新能跳到的最远位置,如果某个位置超过最远位置,说明不可达,就返回false,能走完全程返回true。
class Solution {
public:bool canJump(vector<int>& nums) {int k = 0;for (int i = 0; i < nums.size(); i++) {if (i > k) return false;k = max(k, i + nums[i]);}return true;}
};// 作者:Ikaruga
// 链接:https://leetcode.cn/problems/jump-game/solutions/24322/55-by-ikaruga/
// 来源:力扣(LeetCode)
时间和空间复杂度和解法二一致。
45. 跳跃游戏 II - 力扣(LeetCode)
给定一个长度为 n 的 0 索引整数数组 nums。初始位置在下标 0。
每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在索引 i 处,你可以跳转到任意 (i + j) 处:0 <= j <= nums[i] 且 i + j < n
返回到达 n - 1 的最小跳跃次数。测试用例保证可以到达 n - 1。
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
示例 2:输入: nums = [2,3,0,1,4]
输出: 2
解法
edge:当前这"一跳"能到达的最远边界
maxlen:在所有已访问的格子中,能跳到的最远距离
num:已经跳了多少次
class Solution {
public:int jump(vector<int>& nums) {if (nums.size() == 1)return 0;int num = 0;int maxlen = 0;int edge = 0;for (int i = 0; i < nums.size(); i++) {maxlen = max(maxlen, i + nums[i]);if (i == edge) {num++;edge = maxlen;if (edge >= nums.size() - 1)break;}}return num;}
};
时间复杂度:O(n)。
空间复杂度:O(1)。
763. 划分字母区间 - 力扣(LeetCode)
10.12号更新。
如有问题或建议,欢迎在评论区中留言~