贪心
[1- 买卖股票的最佳时机](#1- 买卖股票的最佳时机)
[2- 跳跃游戏](#2- 跳跃游戏)
[3- 跳跃游戏Ⅱ](#3- 跳跃游戏Ⅱ)
[4- 划分字母区](#4- 划分字母区)
1- 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
var maxProfit = function(prices) {
// 贪心算法
// 在历史最低点买入,在之后的最高点卖出(注意顺序:先买入后卖出)
// 1.minPrice记录当前出现的最低价格
// 2.maxProfit记录当前最大利润,初始化为0,没有交易完成的情况下最大利润是0
// 3.先更新最低价格,再利用最低价格更新最大利润
let minPrice = prices[0]
let maxProfit = 0
for(let i = 0; i < prices.length; i++){
if(prices[i] < minPrice){
minPrice = prices[i]
}else{
maxProfit = Math.max(maxProfit, prices[i] - minPrice)
}
}
return maxProfit
};
2- 跳跃游戏
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。
var canJump = function(nums) {
// 贪心算法:维护最远边界
// 不关心具体的跳跃路径,只关心从每一个点出发,最远能到哪里,不断更新这个最远边界
// farthest:目前能跳到的最远索引值
let farthest = 0
for(let i = 0; i < nums.length; i++){
// 如果当前位置比最远能走的位置还远,说明永远走不到当前位置
if(i > farthest){
return false
}
// 更新
// 从当前位置出发,能跳到的最远索引位置
farthest = Math.max(farthest, i+nums[i])
// 能到的最远位置已经覆盖了终点
if(farthest >= nums.length-1){
return true
}
}
};
3- 跳跃游戏Ⅱ
给定一个长度为 n 的 0 索引 整数数组 nums。初始位置在下标 0。
每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在索引 i 处,你可以跳转到任意 (i + j) 处:
0 <= j <= nums[i]且i + j < n
返回到达 n - 1 的最小跳跃次数。测试用例保证可以到达 n - 1。
var jump = function(nums) {
// 在上一题的基础上修改
// 贪心算法:区间边界,分段跳
// end表示当前这一跳的边界,在还未到end时不用增加次数
// 走到end时必须跳跃了,step+1,更新边界为farthest
let farthest = 0 // 能够跳到的最远位置
let end = 0 // 当前跳跃步数能覆盖到的边界
let step = 0 // 跳跃次数
// 不需要遍历最后一个元素,最后一个元素是终点,不是跳板
for(let i = 0; i < nums.length-1; i++){
farthest = Math.max(farthest, nums[i]+i)
// 已经走到这一条的边界位置,需要更新跳跃次数,重新跳
if(i === end){
step++
end = farthest //下一跳的边界就是之前攒下的"最远位置"
// // 如果此时边界已经覆盖终点,可以提前结束
if(end >= nums.length-1) break
}
}
return step
};
4- 划分字母区间
给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 "ababcc" 能够被分为 ["abab", "cc"],但类似 ["aba", "bcc"] 或 ["ab", "ab", "cc"] 的划分是非法的。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
var partitionLabels = function(s) {
// 和跳跃游戏类似,寻找最远边界
// 先遍历字符串,记录字符串中每个字母最后一次出现的索引位置,这个就是当前片段的最远边界
// 使用一个长度为 26 的数组记录每个字母最后出现的下标
let last = new Array(26)
const base = 'a'.charCodeAt(0)
for(let i = 0; i < s.length; i++){
last[s.charCodeAt(i)-base] = i
}
let start = 0 // 片段的起始位置
let end = 0 // 当前片段需要的最小结束位置
let result = []
for(let i = 0; i < s.length; i++){
// 更新当前片段中所有字符的最远结束位置
end = Math.max(end, last[s.charCodeAt(i)- base])
// 到达最远边界,将当前区间的长度存入数组
if(i === end){
result.push(end-start+1)
// 更新下一个片段的起点
start = i +1
}
}
return result
};