LeetCode/跳跃游戏

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

1. 回溯法

纯粹当做练手,运行不仅超时,还超内存
使用递归的方式,从当前位置做选择,选择为当前位置能跳的距离,然后转换到下一位置,到达目的结束递归

回溯法
class Solution {
public:
    bool flag = false; //设定初始判断值为否
    bool canJump(vector<int>& nums) {
        trackback(nums,0);//进入递归寻路
        return flag; //返回结果
    }
    void trackback(vector<int>& nums,int start){
        if(start==nums.size()-1){ //边界条件,如果达到最后位置,则取真
            flag=true; return; 
    }
        if(flag==true||nums[start]==0) return;//减少递归运算
        for(int i=start+1;i<=start+nums[i];i++){
           trackback(nums,i);//从能跳的长度中做选择
           //出递归,相当于撤销选择
        }
    }
};

2. 贪心算法

记录当下一跳的范围,下一次在该范围中遍历,得到下一跳的范围
当某一跳范围大于数组范围,为真,若下一跳范围边界没有发生改变,则为假,性能为线性

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int buff;
        int maxpos = 0; //记录当前跳跃最远距离
        int start = 0;  //记录当前跳跃开始位置
        while(true){    
        buff = maxpos;  //缓存上一跳范围
        for(int i = start;i<=buff;i++){//在当前范围内遍历,算出下一跳范围
            maxpos = max(maxpos,i+nums[i]); //计算当前一跳最远位置
        }
        if(maxpos>=nums.size()-1) return true; //若能达到最后一个位置,为真
        else if(maxpos==buff) return false;   //下一跳范围不变,为假
        start = buff+1;  //下一跳开始位置为上一跳极限位置的后一位
        }
    }
};

官方写法直接顺序推进,遍历范围为初始位置到维护的一个最大位置,
最大位置在遍历的时候实时更新,若遍历结束没有达到末端则返回假
每次遍历都做一次判断,而自己写的算法每一跳范围做一次判断,故官方写法耗时更长

官方写法
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size();
        int rightmost = 0;
        for (int i = 0; i < n; ++i) { //顺序遍历,维护一个最远位置即可
            if (i <= rightmost) {  //
                rightmost = max(rightmost, i + nums[i]);  //算出当下最远位置
                if (rightmost >= n - 1) {//判断该最远位置是否满足要求
                    return true;
                }
            }
        }
        return false; //遍历完也没满足即返回假
    }
};

更简洁的写法
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;
    }
};


3. 动态规划

将问题规模不断缩小,终点位置的可达性转换为前面某个位置的可达性,直至转换到起点,证明可达

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size();
        int end = n-1; //当前终点位置
        for(int i =end -1;i>=0;i--){ //从终点前一位置从后往前遍历
            if(end-i<=nums[i])  end = i;  //如果当前节点到终点距离符合,则转移终点
        }
        return end==0;//将终点转移至起点,说明路径可达
    }
};
posted @ 2022-05-12 20:00  失控D大白兔  阅读(39)  评论(0编辑  收藏  举报