题意整理
- 给定一颗有n个节点的树,每个节点的值初始为0或1。
- 求有多少条从根节点到叶子节点的路径(要求路径上节点值得累加和小于等于2)。
方法一(DFS)
1.解题思路
- 首先建立邻接表,用于访问某个节点的所有子节点。
- 从根节点开始递归,并且初始化一个num为2,每到一个节点,num减去对应节点值。如果num小于0,直接终止掉这条路径。否则,遍历当前节点得所有子节点,继续递归,同时判断是否是叶子节点,如果是叶子节点,路径数加一。
2.代码实现
import java.util.*; /* * public class Point { * int x; * int y; * public Point(int x, int y) { * this.x = x; * this.y = y; * } * } */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 一个整数,表示路径数 * @param n int * @param Edge Point一维数组 * @param f int一维数组 * @return int */ //邻接表 List<List<Integer>> graph; //节点个数 int n; //标记数组 boolean[] v; //序列数组 int[] f; //结果变量 int res; public int solve (int n, Point[] Edge, int[] f) { //初始化节点个数和邻接表 this.n=n; this.graph=new ArrayList<>(); for(int i=0;i<n;i++){ graph.add(new ArrayList<>()); } for(Point point:Edge){ int u=point.x; int v=point.y; graph.get(u-1).add(v-1); graph.get(v-1).add(u-1); } //初始化标记数组、序列数组、结果变量 this.v=new boolean[n]; v[0]=true; this.f=f; this.res=0; //递归 dfs(0,2); return res; } private void dfs(int i,int num){ //如果路径上不止两个值为1,直接返回 num-=f[i]; if(num<0) return; //看是否是叶子节点 boolean isLeaf=true; for(Integer j:graph.get(i)){ //遍历未访问的子节点 if(!v[j]){ v[j]=true; isLeaf=false; //往叶子节点递归 dfs(j,num); } } //如果是叶子节点,res加一 if(isLeaf){ res++; } } }
3.复杂度分析
- 时间复杂度:最坏情况下,需要访问所有的节点,所以时间复杂度为。
- 空间复杂度:最坏情况下,需要额外深度为n的递归栈、大小为n的标记数组以及大小为的邻接表,所以空间复杂度为。
方法二(BFS)
1.解题思路
- 首先建立邻接表,用于访问某个节点的所有子节点。
- 将根节点入队,累加和初始为2.
- 每次从队列取出当前节点,累加和减去当前节点的值,遍历当前节点的所有子节点,如果子节点未被访问过,将其打上标记,并将当前节点置为非叶子节点,同时将该子节点入队,继续遍历。如果当前节点是叶子节点,并且累加和大于等于0,说明是满足条件的路劲,将路径数加一。
动图展示:
2.代码实现
import java.util.*; /* * public class Point { * int x; * int y; * public Point(int x, int y) { * this.x = x; * this.y = y; * } * } */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 一个整数,表示路径数 * @param n int * @param Edge Point一维数组 * @param f int一维数组 * @return int */ //邻接表 List<List<Integer>> graph; //节点个数 int n; //标记数组 boolean[] v; //序列数组 int[] f; //结果变量 int res; public int solve (int n, Point[] Edge, int[] f) { //初始化节点个数和邻接表 this.n=n; this.graph=new ArrayList<>(); for(int i=0;i<n;i++){ graph.add(new ArrayList<>()); } for(Point point:Edge){ int u=point.x; int v=point.y; graph.get(u-1).add(v-1); graph.get(v-1).add(u-1); } //初始化标记数组、序列数组、结果变量 this.v=new boolean[n]; v[0]=true; this.f=f; this.res=0; //初始化队列 Queue<int[]> queue=new LinkedList<>(); //根节点入队,同时节点值累加和初始化为2 queue.offer(new int[]{0,2}); while(!queue.isEmpty()){ int[] node=queue.poll(); //当前节点和对应累加和 int i=node[0]; int num=node[1]; //减去当前节点值 num-=f[i]; boolean isLeaf=true; for(Integer j:graph.get(i)){ //遍历当前节点未访问的子节点 if(!v[j]){ v[j]=true; isLeaf=false; queue.offer(new int[]{j,num}); } } //如果是叶子节点,并且num大于等于0,则路径数加一 if(isLeaf&&num>=0){ res++; } } return res; } }
3.复杂度分析
- 时间复杂度:最多访问n个节点,所以时间复杂度为。
- 空间复杂度:最坏情况下,需要额外大小为n的队列、大小为n的标记数组以及大小为的邻接表,所以空间复杂度为。