归属专栏:深夜咖啡配算法
个人主页:Jammingpro
记录一句:摆烂一天后,写的第一篇博客
标签:贪心、动态规划、数组
给定一个长度为 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]
我们可以创建一个dp表,用于存储到达当前台阶需要的最少步数。初始时,除dp[0]等于0以外,其余均初始化为无穷大。当我们知道nums[i]
及dp[i]
时,也就是知道当前位置能跨出的最多的台阶数及到达当前台阶最少的步数。我们可以更新从i
位置到i+nums[i]
台阶对应的dp
值。如果dp[j] > dp[i] + 1
,则更新dp[j]
为dp[i]+1
,也就是说,从我当前的第i个台阶走向下标为j所需要的步数更少,因此需要更新对应台阶的dp值。
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
vector<int>dp(n, INT_MAX);
dp[0] = 0;
for(int i = 0; i < n - 1; i++)
for(int j = 1; j <= nums[i] && i + j < n; j++)
dp[i + j] = min(dp[i + j], dp[i] + 1);
return dp[n - 1];
}
};
上面的动态规划算法虽然能够解决这道题,但其空间复杂度为O(N),时间复杂度(最坏情况下)为O(N^2)。解决这道题还可以使用贪心算法,这个算法挺巧妙的,让我娓娓道来->我们初始设置变量maxpos
,用于记录当前能够到达的最远台阶的下标;设置变量steps
,用于记录走到最后一个台阶的最少步数;还需设置一个end
,end的用途需要用例子说明,文字描述说不大清
以示例1的[2,3,1,1,4]为例,先将steps、end、maxpos初始化为0。此时nums[0] = 2,则当前能到达的最大下标为2,即maxpos等于2;此时因为i == end,因此steps需要加1,end更新为maxpos。nums[1] == 3,则当前最大能到达的最大下标为4,即maxpos等于4;此时因为i < end,因此无需更新steps和end。nums[2] == 1,此时因为i + nums[i] = 3,小于maxpos,maxpos无需更新;此时因为i == end,因此steps需要加1,end更新为maxpos…也就是说,end记录的是maxpos
的旧值,只有当i == end
时才会更新end
。这么做的目的是为了实现最少次数更新steps的数值。
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
int maxpos = 0;
int end = 0;
int steps = 0;
for(int i = 0; i < n - 1; i++)
{
maxpos = max(maxpos, i + nums[i]);
if(i == end)
{
end = maxpos;
steps++;
}
}
return steps;
}
};
文章结语:这道题,我一开始想到的算法是动态规划,贪心算法挺牛的,值得细细品。
欢迎进入深夜咖啡配算法专栏,查看更多文章。
如果上述内容有任何问题,欢迎在下方留言区指正b( ̄▽ ̄)d