面试题 04.01. 节点间通路-一题多解DFS-Java

1.题目

2.思路

方法一

注意题目中的提示,需要去重,这里BFS 和 DFS 都可以,主要选取DFS进行讲解。

1.建立邻接表,这里采取哈希表map存储。注意有重复边,比如[1,2],[1,2]

2.使用vis[]矩阵记录是否访问过该节点,剪枝和避免有环

2.建立dfs()函数,因为题目中要求返回true 或者 false,这里方便期间,返回值定义为boolean(当然也可以定义为void)

疑问:如何遍历HashSet中的每个元素?

通过for迭代的方式遍历即可,for(int key : set)

如果需要保证大小顺序的话,可以去重后使用一个List<Integer>来操作, 然后排序。

时间复杂度 ——O(N + E)

这里采取的是用邻接表来存储图,所以访问节点的时间为O(N), 访问边的时间复杂度为O(E),最终时间复杂度为O(N + E)。(如果是用邻接矩阵来存储图的话,那么时间复杂度为O(N * N))

空间复杂度

因为这里的空间为哈希表,其中有O(N)的空间,同时DFS是一个递归的思想,需要借助栈,所以这里也有O(N),所以最终是O(N)的时间复杂度。

class Solution {
    boolean ans = false;
    public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
        // 邻接表
        Map<Integer, Set<Integer>>map = new HashMap<>(); 
        for(int[]g : graph){
            int source = g[0], des = g[1];
            Set<Integer>set = map.getOrDefault(source, new HashSet());
            set.add(des);
            map.put(source, set);
        }
        // 定义是否访问过
        int[]vis = new int[n];
        return dfs(start, target, map, vis);
    }

    public boolean dfs(int x, int target, Map<Integer, Set<Integer>>map, int[]vis){
        if(x == target){
            return true;
        }
        // 代表已经被访问过
        if(vis[x] == 1) return false; 
        vis[x] = 1;
        Set<Integer>set = map.getOrDefault(x, new HashSet());
        // 遍历HashSet
        for(int key : set){
            if(dfs(key, target, map, vis)) return true;
        }
        return false;
    }
}

方法二(采用原生的函数进行DFS)

如果直接原生函数DFS, 从start 遍历到target,会显示超时。

但是反过来DFS的话,时间大大的减少!!!主要原因是官方测试用例设计不合理。如果设计的用例从target出发的错误边很多,也照样会超时。因为时间复杂度其实并没有变化,所以这里相当于是一种取巧的做法。

class Solution {
    boolean ans = false;
    public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
        if(start == target) return true;
        for(int[]g : graph){
            if(g[1] == target) // 这里从target 往 start dfs不会超时,因为用例设计的原因。不然会超时。
                return findWhetherExistsPath(n, graph, start , g[0]);
            
        }
        return false;
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值