算法沉淀——贪心算法五
- 01.跳跃游戏 II
- 02.跳跃游戏
- 03.加油站
- 04.单调递增的数字
01.跳跃游戏 II
题目链接:https://leetcode.cn/problems/jump-game-ii/
给定一个长度为 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 = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
- 题目保证可以到达
nums[n-1]
思路
这里我们可以利用层序遍历的思想进行数组遍历,从第一步开始,计算每一步能跨出的范围内最大的那个数字的步数,这样我们就可以找到需要使用的最小的跳跃步数。
代码
class Solution {
public:
int jump(vector<int>& nums) {
int left=0,right=0,maxPos=0,count=0,n=nums.size();
while(left<=right){
if(maxPos>=n-1) return count;
for(int i=left;i<=right;i++) maxPos=max(maxPos,nums[i]+i);
left=right+1;
right=maxPos;
count++;
}
return -1;
}
};
02.跳跃游戏
题目链接:https://leetcode.cn/problems/jump-game/
给你一个非负整数数组 nums
,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true
;否则,返回 false
。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 105
思路
这道题可以借用上面的思想,只需修改返回值即可。
代码
class Solution {
public:
bool canJump(vector<int>& nums) {
int left=0,right=0,maxPos=0,count=0,n=nums.size();
while(left<=right){
if(maxPos>=n-1) return true;
for(int i=left;i<=right;i++) maxPos=max(maxPos,nums[i]+i);
left=right+1;
right=maxPos;
count++;
}
return false;
}
};
03.加油站
题目链接:https://leetcode.cn/problems/gas-station/
在一条环路上有 n
个加油站,其中第 i
个加油站有汽油 gas[i]
升。
你有一辆油箱容量无限的的汽车,从第 i
个加油站开往第 i+1
个加油站需要消耗汽油 cost[i]
升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas
和 cost
,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1
。如果存在解,则 保证 它是 唯一 的。
示例 1:
输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。
示例 2:
输入: gas = [2,3,4], cost = [3,4,3]
输出: -1
解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。
我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油
开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油
开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油
你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。
因此,无论怎样,你都不可能绕环路行驶一周。
提示:
gas.length == n
cost.length == n
1 <= n <= 105
0 <= gas[i], cost[i] <= 104
思路
枚举所有起点,模拟加油的流程,但在这里做一个优化,就是贪心思想,我们在枚举每一个点时,若该点不成功,就直接跳过中间所有点,这样我们可以做很大的优化。
代码
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int n=gas.size();
for(int i=0;i<n;i++){
int rest = 0, step = 0;
while(step<n){
int index=(i+step)%n;
rest+=gas[index]-cost[index];
if(rest<0) break;
step++;
}
if(rest>=0) return i;
i+=step;
}
return -1;
}
};
04.单调递增的数字
题目链接:https://leetcode.cn/problems/monotone-increasing-digits/
当且仅当每个相邻位数上的数字 x
和 y
满足 x <= y
时,我们称这个整数是单调递增的。
给定一个整数 n
,返回 小于或等于 n
的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10
输出: 9
示例 2:
输入: n = 1234
输出: 1234
示例 3:
输入: n = 332
输出: 299
提示:
0 <= n <= 109
思路
为了方便处理数字,我们可以先将整数转换成字符串,然后从左往右扫描,找到第一个递减的位置,然后从这个位置往前推,推到相同数字的最前端,该位置-1,后面所有数都改成9,这样就得到最终结果
代码
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string s=to_string(n);
int i=0,m=s.size();
while(i+1<m&&s[i]<=s[i+1]) i++;
if(i+1==m) return n;
while(i-1>=0&&s[i]==s[i-1]) i--;
s[i]--;
for(int j=i+1;j<m;j++) s[j]='9';
return stoi(s);
}
};