java_leetcode_1971. 寻找图中是否存在路径_dfs(链式前向星,邻接表),并查集

传送门:https://leetcode.cn/problems/find-if-path-exists-in-graph/

开一篇简单的题目用来复习以前c++ 的一些基础知识并用java实现。

题面:
在这里插入图片描述
题目很简单,就单纯判断起点是否有路径到终点,下面给出了三种方法去回顾了做题过程遇到(遗忘)的一些知识点。

邻接表建图 + DFS

不同于c++ 可以直接用verctor<verctor<>> 的建图方式,在java 中一般多采用 HashMap + List的方式来搭建, 这里的list 在创建的时候根据需求使用LinkedList 或者ArrayList: ArrayList 相当于动态数组,根据下标查询时间较快;LinkedList 相当于双向链表,插入较快,两种方式都有contains的方法去判断是否有元素在列表中。

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class e_1971 {
    public static void main(String[] args) {
        int n = 10;
        int s = 5,d = 9;
        int [][] edges = {{4,3},{1,4},{4,8},{1,7},{6,4},{4,2},{7,4},{4,0},{0,9},{5,4}};
        if ( validPath(n,edges,s,d) )
            System.out.println("true");
        else System.out.println("false");
    }
    public static boolean validPath(int n, int[][] edges, int source, int destination) {
        Map<Integer, List<Integer>> mp = new HashMap<>();
        for(int i=0;i < n; ++i)
            mp.put(i,new LinkedList<>());
        for(int i=0;i < edges.length; ++i){
            mp.get(edges[i][0]).add(edges[i][1]);
            mp.get(edges[i][1]).add(edges[i][0]);
        }
        if(source == destination) return true;
        boolean vis[] = new boolean[n];
        return dfs(source, destination ,mp, vis);
    }
    public static boolean dfs(int s, int d, Map<Integer, List<Integer>> mp, boolean vis[]){
        if(mp.get(s).contains(d)) return true;
        if(vis[s]) return false;
        vis[s] = true;
        for(int i=0;i < mp.get(s).size(); i++)
            if(dfs(mp.get(s).get(i),d,mp,vis)) return true;
        return false;
    }
}

时空对比:
在这里插入图片描述

链式前向星 + DFS

好久没用这个了,很多槽点都忘记了。
关于无向图:

  • 所需要的数组空间都开2倍
  • vis数组判断边是否访问过,由于是双向边,需要通过把cnt设置成1,在用异或取到反边,保证正向反向都被判断是否走过;当然根据个人喜好,也可以把cnt 是设置成0,然后在add函数最后写cnt++,也能起到一样的效果。
int cnt = 1;  
// int cnt = 0;
public void add(int u, int v){
   ver[++cnt] = v;             //ver[cnt] = v;
   nex[cnt] = head[u];     //nex[cnt++] = head[u];
   head[u] = cnt;
}
.
.
.
if(mp.vis[i^1] == 0){
   mp.vis[i] =  mp.vis[i^1] = 1;
   if(dfs(mp.ver[i], d, mp)) return true;
}
  • 不同于c++, java 一般用类来保存这种结构。
public class e1971 {
    static class Edge{
        int N = 200007,cnt = 1;
        int [] vis = new int [2*N];
        int [] head = new int [N];
        int [] nex = new int [2*N];
        int [] ver = new int [2*N];
        public void add(int u, int v){
            ver[++cnt] = v;
            nex[cnt] = head[u];
            head[u] = cnt;
        }
    }
    public static void main(String[] args) {
        int n = 10,s = 5,d = 9;
        int [][] edges = {{4,3},{1,4},{4,8},{1,7},{6,4},{4,2},{7,4},{4,0},{0,9},{5,4}};
        if ( validPath(n,edges,s,d) )
            System.out.println("true");
        else System.out.println("false");
    }
    public static boolean validPath(int n, int[][] edges, int source, int destination) {
        Edge mp = new Edge();
        for(int i=0;i < edges.length; ++ i){
            mp.add(edges[i][1], edges[i][0]);
            mp.add(edges[i][0], edges[i][1]);
        }
        return dfs(source,destination, mp);
    }
    public static  boolean dfs(int s, int d, Edge mp){
        if(s == d) return true;
        for(int i = mp.head[s]; i != 0 ; i = mp.nex[i])
            if(mp.vis[i^1] == 0){
                mp.vis[i] =  mp.vis[i^1] = 1;
                if(dfs(mp.ver[i], d, mp)) return true;
            }
        return false;
    }
}

时空对比:在这里插入图片描述

并查集

模板题,操作统统写到类里面,值得注意的是,在构建find() 函数的时候,若使用三目运算符并且是JDK7 的情况下,需要把基础类型进行装箱Integer.valueOf()

public class e_1971_3 {
    public static void main(String[] args) {
        int n = 10;
        int s = 5,d = 9;
        int [][] edges = {{4,3},{1,4},{4,8},{1,7},{6,4},{4,2},{7,4},{4,0},{0,9},{5,4}};
        if ( validPath(n,edges,s,d) )
            System.out.println("true");
        else System.out.println("false");
    }
    public static boolean validPath(int n, int[][] edges, int source, int destination) {
        andcheck mp = new andcheck(n);
        for(int i=0;i < edges.length; i++)
            mp.merge(edges[i][0], edges[i][1]);
        return mp.issame(source,destination);
    }
    static class andcheck{
        int size;
        int [] par;
        public andcheck(int size){
            this.size = size;
            par = new int[size];
            for(int i=0;i < size; i++)
                par[i] = i;
        }
        public int find(int a){
        //装箱
            return (par[a] == a )?a:Integer.valueOf(par[a] = find(par[a]));
        }
        public void merge(int a, int b){
            int fa = find(a);
            int fb = find(b);
            if(fa == fb) return;
            par[fa] = fb;
        }
        public boolean issame(int a, int b){
            return find(a) == find(b);
        }
    }
}

时空对比:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值