【跳跃游戏汇总】

(以下题库源自leetcode,题解部分源自代码随想录

跳跃游戏Ⅰ

[题]

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。

[例]

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

1. 贪心

[思路]:

每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。到了范围边界了就结束遍历返回fasle,最大覆盖范围大于数组范围就返回true.
在这里插入图片描述

[代码]:
bool canJump(vector<int>& nums) {
        int cover =0; 
        if(nums.size()==1) return true;
        for(int i = 0; i<=cover;i++)//遍历可达范围内的所有元素
        {
            cover = max(i+nums[i], cover);//取可达的最大范围
            if(cover>=nums.size()-1) return true;//可达范围大于数组范围就返回true
        }
        return false;
    }

跳跃游戏Ⅱ

[题]

给定一个长度为 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]。

[例]

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

1.贪心

[思路]:

移动下标只要遇到当前覆盖最远距离的下标,直接步数加一.
当移动下标指向nums.size - 2时:

  • 如果移动下标等于当前覆盖最大距离下标, 需要再走一步(即res++),因为最后一步一定是可以到的终点。(题目假设总是可以到达数组的最后一个位置);
  • 如果移动下标不等于当前覆盖最大距离下标,说明当前覆盖最远距离就可以直接达到终点了,不需要再走一步。

所以当走到nums.size - 2就可。

[代码]:
nt jump(vector<int>& nums) {
        int res=0;
        int cover =0;//当前可达的最远距离
        int next_cover = 0;//下一步可达的最远距离
        for(int i=0; i<nums.size()-1; i++)//走到倒数第二个元素就行,如果大于当前可以走的最远距离再走一步一定可以走到
        {
            next_cover = max(nums[i]+i, next_cover);//下一步可达的最远距离
            if(i==cover)//当前可达的最远距离=当前距离,步数加1,跟新当前可达距离为下一步可达的最远距离
            {
                res++;
                cover = next_cover;//走完一步后下一步可到达的最远距离
            }
        }
        return res;
    }

待跟新·······

跳跃游戏Ⅲ

跳跃游戏Ⅳ

跳跃游戏Ⅴ

跳跃游戏Ⅵ

跳跃游戏Ⅶ

---------------------------------跳跃游戏变体-----------------------------

划分字母区间

[题]

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。

  • 1 <= s.length <= 500
  • s 仅由小写英文字母组成
[例]

输入:s = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”、“defegde”、“hijhklij” 。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 这样的划分是错误的,因为划分的片段数较少。

贪心

[思路]:

在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。
可以分为如下两步:

  • 统计每一个字符最后出现的位置
  • 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点。
[代码]:
class Solution {
public:
    vector<int> partitionLabels(string s) {
        int hash[26] = {0};
        for(int i=0; i<s.size(); i++)//遍历字符串,记录每个字符的最大边界
        {
            hash[s[i] - 'a'] =i;
        }
        vector<int> res;
        int left = 0;//分割区间的头
        int right = 0;//分割区间的尾
        for(int j=0; j<s.size(); j++)//遍历字符串
        {
            right = max(right, hash[s[j]-'a']);//实时跟新已遍历的字符的最大边界
            if(j==right)//如果当前已经到了最大边界,说明之前遍历的字符的最大边界都在这个范围内。该点即为分割点
            {
                res.push_back(right-left+1);//保存分割区间的长度
                left = right+1;//下一个分割区间的头即为当前分割区间的下一位
            }
        }
        return res;
    }
};

合并区间

[题]

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

[例]

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

贪心

[思路]:
  • 先排序,让所有的相邻区间尽可能的重叠在一起。
  • 按照左边界从小到大排序之后,如果 intervals[i][0] <= intervals[i - 1][1] 即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。
  • 如果有重叠合并区间后左边界和右边界,作为一个新的区间,加入到result数组里就可以了。如果没有合并就把原区间加入到result数组。
[代码]:
class Solution {
    static bool cmp(const vector<int> & a, const vector<int> & b)
    {
        return a[0] < b[0];
    }
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(), cmp);//按区间左边界排序
        vector<vector<int>> res;
        res.push_back(intervals[0]);//先将第一个区间存入
        for(int i=1; i<intervals.size(); i++)//遍历区间
        {
            if(intervals[i][0]<= res.back()[1])//如果当前区间与上一区间有重叠
            {
                res.back()[1] = max(intervals[i][1], res.back()[1]);//合并当前区间至上一个区间
            }
            else//如果没有重叠
            {
                res.push_back(intervals[i]);//直接存入
            }
        }
        return res;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值