题意整理
- 给定一个有向无环图,每个节点都有一个权值。
- 求所有路径中,节点权值和最大的路径。
方法一(记忆化递归)
1.解题思路
- 递归终止条件:跟新完所有的节点。
- 递归如何推进:每跟新完一个后置节点,就将当前后置节点作为新的起点进行递归。
2.代码实现
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param potatoNum int一维数组 依次表示序号为1,2,3..的节点的权值 * @param connectRoad int二维数组 每个一维数组[x,y]表示从第x号到第y号有路 * @return string */ int n; //权值数组 int[] w; //路径数组 String[] path; int[] potatoNum; //邻接矩阵 int[][] graph; public String digSum (int[] potatoNum, int[][] connectRoad) { //初始化 this.n=potatoNum.length; this.w=new int[n+1]; this.path=new String[n+1]; this.potatoNum=potatoNum; this.graph=new int[n+1][n+1]; //给邻接矩阵赋值 for(int[] road:connectRoad){ graph[road[0]][road[1]]=1; } for(int i=1;i<=n;i++){ //跟新对应节点,小于说明没有跟新过 if(w[i]<potatoNum[i-1]){ w[i]=potatoNum[i-1]; path[i]=String.valueOf(i); dfs(i); } } int max=0; String res=""; //求最大权值对应的路径 for(int i=1;i<=n;i++){ if(max<w[i]){ max=w[i]; res=path[i]; } } return res; } private void dfs(int i){ //遍历后置节点 for(int j=1;j<=n;j++){ //跟新以j结尾的路径 if(graph[i][j]==1&&w[j]<w[i]+potatoNum[j-1]){ w[j]=w[i]+potatoNum[j-1]; path[j]=path[i]+"-"+String.valueOf(j); dfs(j); } } } }
3.复杂度分析
- 时间复杂度:递归的最大深度是n,递归外面还有一层遍历,其他循环都是线性的,所以时间复杂度为。
- 空间复杂度:需要额外大小为的权值数组和路径数组,以及大小为的邻接矩阵,所以空间复杂度为。
方法二(动态规划)
1.解题思路
- 首先初始化权值数组和路径数组。
- 然后初始化图的邻接矩阵,记录每个节点可达的后置节点。
- 从后往前依次确认起点为该节点的对应路径中权值最大的,这一步,遍历所有后置节点,找权值最大的进行拼接,再跟新权值数组和路径数组。
- 最后取权值最大的路径。
动图展示:
2.代码实现
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param potatoNum int一维数组 依次表示序号为1,2,3..的节点的权值 * @param connectRoad int二维数组 每个一维数组[x,y]表示从第x号到第y号有路 * @return string */ public String digSum (int[] potatoNum, int[][] connectRoad) { //初始化权值数组和路径数组 int n=potatoNum.length; int[] w=new int[n+1]; String[] path=new String[n+1]; //初始化图的邻接矩阵 int[][] graph=new int[n+1][n+1]; for(int[] road:connectRoad){ graph[road[0]][road[1]]=1; } //从后往前依次确认起点为该节点的对应路径中权值最大的 for(int i=n;i>=1;i--){ w[i]=potatoNum[i-1]; path[i]=String.valueOf(i); int max=0; int id=0; //遍历所有后置节点,找权值最大的进行拼接 for(int j=1;j<=n;j++){ if(graph[i][j]==1&&max<w[j]){ max=w[j]; id=j; } } //跟新权值数组和路径数组 if(max==0) continue; w[i]+=w[id]; path[i]=path[i]+"-"+path[id]; } int max=0; String res=""; //取权值最大的路径 for(int i=1;i<=n;i++){ if(max<w[i]){ max=w[i]; res=path[i]; } } return res; } }
3.复杂度分析
- 时间复杂度:寻找后置节点时,需要一层遍历,外面还有一层遍历,其他循环都是线性的,所以时间复杂度为。
- 空间复杂度:需要额外大小为的权值数组和路径数组,以及大小为的邻接矩阵,所以空间复杂度为。