【深度优先】1306. 跳跃游戏 III

题目描述

这里有一个非负整数数组arr,你最开始位于该数组的起始下标start处。当你位于下标1处时,你可以跳到i + arr[i]或者i - arr[i]
请你判断自己是否能够跳到对应元素值为0的 任一 下标处。
注意,不管是什么情况下,你都无法跳到数组之外。

示例:

输入:arr = [4,2,3,0,3,1,2], start = 5
输出:true
解释:
到达值为 0 的下标 3 有以下可能方案: 
下标 5 -> 下标 4 -> 下标 1 -> 下标 3 
下标 5 -> 下标 6 -> 下标 4 -> 下标 1 -> 下标 3 

解题思路

对于本题,无论是使用广度优先还是深度优先都可以得到很好的解决,鉴于官方已经提供广度优先的题解,故本文给出对应的深度优先模板。

相较于传统的图遍历题目,本体在图的连接关系上稍作改动。既不是矩阵类的相邻单元具有连接,也没有给出邻接矩阵或邻接链表,需要根据跳跃规则,理清各结点的连接关系。

start结点开始深度遍历,方法的返回值类型为bool,退出递归条件:1. 访问重复结点立即返回;2. 访问元素值为0的结点返回true。每一层递归逻辑,标记当前结点已访问,递归遍历能跳跃的结点。

代码实现

通过邻接链表显示表示各结点的连接关系,

class Solution {
public:
    bool canReach(vector<int>& arr, int start) {
        //构建graph,邻接链表
        int n = arr.size();
        vector<vector<int>> graph(n);
        for(int i = 0; i < n; i++){
            if(arr[i] == 0) continue;
            if(arr[i] + i < n) graph[i].push_back(arr[i] + i);
            if(i - arr[i] >= 0) graph[i].push_back(i - arr[i]);
        }

        return dfs(graph, arr, start);
    }

    bool dfs(vector<vector<int>>& graph, vector<int>& arr, int start){
        if(arr[start] == -1) return false;
        if(arr[start] == 0) return true;
        bool res = false;
        arr[start] = -1;
        for(int i : graph[start]){
            res |= dfs(graph, arr, i);
        }
        return res;
    }
};

运行结果:
result

这惨不忍睹的performance,初步猜想是构建graph影响的。

优化掉构建邻接链表的过程,基于跳跃规则利用原arr[],大幅提高性能与内存开销。

class Solution {
public:
    bool canReach(vector<int>& arr, int start) {
        //判断重复访问
        if(arr[start] == -1) return false;
        //抵达目标结点,return true
        if(arr[start] == 0) return true;
        bool res = false;
        int step = arr[start];
        //标记当前start已访问
        arr[start] = -1;
        //只能向左/右跳跃,i = 0时左跳,i = 1右跳。
        for(int i = 0; i < 2; i++){
            int temp = start + pow(-1, i) * step;
            if(temp >= 0 && temp < arr.size()){
                // 与运算符,只要能够访问到目标结点即为true!
                res |= canReach(arr, temp);
            }
        }
        return res;
    }
};

运行结果:

run result

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值