其他分享
首页 > 其他分享> > leetcode题库学习系列——LCP 07. 传递信息

leetcode题库学习系列——LCP 07. 传递信息

作者:互联网

原题地址:
https://leetcode-cn.com/problems/chuan-di-xin-xi/

原题如下:

小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下:

有 n 名玩家,所有玩家编号分别为 0 ~ n-1,其中小朋友 A 的编号为 0
每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传信息的关系是单向的(比如 A 可以向 B 传信息,但 B 不能向 A 传信息)。
每轮信息必须需要传递给另一个人,且信息可重复经过同一个人
给定总玩家数 n,以及按 [玩家编号,对应可传递玩家编号] 关系组成的二维数组 relation。返回信息从小 A (编号 0 ) 经过 k 轮传递到编号为 n-1 的小伙伴处的方案数;若不能到达,返回 0。

示例 1:

输入:n = 5, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3

输出:3

解释:信息从小 A 编号 0 处开始,经 3 轮传递,到达编号 4。共有 3 种方案,分别是 0->2->0->4, 0->2->1->4, 0->2->3->4。

示例 2:

输入:n = 3, relation = [[0,2],[2,1]], k = 2

输出:0

解释:信息不能从小 A 处经过 2 轮传递到编号 2

限制:

2 <= n <= 10
1 <= k <= 5
1 <= relation.length <= 90, 且 relation[i].length == 2
0 <= relation[i][0],relation[i][1] < n 且 relation[i][0] != relation[i][1]



循环、遍历、递归,这是这题给我的第一想法,当着手去做的时候才发现,脑中虽然能生成几阶的树结构,比如0->2,0>4等,再从这一阶往下进行,会发现这一阶的每一个尾数,作为头数的时候,也会对应一个列表,这导致之后的思路密密麻麻的乱。
着手去做,刚开始尝试用递归去做,做到一半放弃了,因为我发现递归的结束条件没有办法写,也或者是我自己掉入了一个心里死循环。
我发现条件中k是有限制的,心里很开心,还有一个默认条件,就是开头和结尾的两个数字,是确定的,比如上面示例1中,开头0结尾4是确定的,并且总的步数也是确定的,我心想这应该就是一个循环查找并对比的题吧,结果我做了循环查找并对比,针对5种K值做了switch,结果代码如下:

class Solution {
private ArrayList<Integer> findEndList(int[][] relation,int startNum){
		ArrayList<Integer> integers = new ArrayList<>();
		for (int i = 0; i < relation.length; i++) {
			if (relation[i][0]==startNum) {
				integers.add(relation[i][1]);
			}
		}
		return integers;
	}
	private ArrayList<Integer> findStartList(int[][] relation,int endNum){
		ArrayList<Integer> integers = new ArrayList<>();
		for (int i = 0; i < relation.length; i++) {
			if (relation[i][1]==endNum) {
				integers.add(relation[i][0]);
			}
		}
		return integers;
	}
	private boolean isContainNums(int[][] relation,int[] array){
		return isContainNums(relation,array[0],array[1]);
	}
	private boolean isContainNums(int[][] relation,int start,int end){
		for (int i = 0; i < relation.length; i++) {
			if (relation[i][0]==start&&relation[i][1]==end) {
				return true;
			}
		}
		return false;
	}

	//输入:n = 5, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3
	public int numWays(int n, int[][] relation, int k) {
		int startIndex=0;
		int endIndex=n-1;
		int lunci=k;

		int[] resultLine=new int[lunci+1];
		resultLine[0]=startIndex;
		resultLine[resultLine.length-1]=endIndex;

		switch (k) {
			case 1:
				for (int i = 0; i < relation.length; i++) {
					if (relation[i][0]==resultLine[0]&&relation[i][1]==resultLine[resultLine.length-1]) {
						return 1;
					}
				}
				return 0;
			case 2:
				ArrayList<Integer> tempList_2_1 = new ArrayList<>();
				ArrayList<Integer> tempList_2_2 = new ArrayList<>();
				for (int i = 0; i < relation.length; i++) {
					if (relation[i][0]==resultLine[0]) {
						tempList_2_1.add(relation[i][1]);
					}
					if (relation[i][1]==resultLine[resultLine.length-1]) {
						tempList_2_2.add(relation[i][0]);
					}
				}
				int resultNum_2=0;
				for (Integer temp1 :
						tempList_2_1) {
					for (Integer temp2 :
							tempList_2_2) {
						if (temp1==temp2) {
							resultNum_2++;
							break;
						}
					}
				}
				return resultNum_2;
			case 3://[0,X1,X2,4]
				ArrayList<Integer> tempList_3_1 = new ArrayList<>();
				ArrayList<Integer> tempList_3_2 = new ArrayList<>();
				for (int i = 0; i < relation.length; i++) {
					if (relation[i][0]==resultLine[0]) {
						tempList_3_1.add(relation[i][1]);
					}
					if (relation[i][1]==resultLine[resultLine.length-1]) {
						tempList_3_2.add(relation[i][0]);
					}
				}
				int resultNum_3=0;
				for (int i = 0; i < relation.length; i++) {
					int i1 = relation[i][0];
					boolean finded=false;
					for (Integer temp1 :
							tempList_3_1) {
						if (i1==temp1) {
							for (Integer temp2 :
									tempList_3_2) {
								int i2 = relation[i][1];
								if (temp2==i2) {
									resultNum_3++;
									finded=true;
									break;
								}
							}
							if (finded) {
								break;
							}
						}
					}
				}
				return resultNum_3;
			case 4://[0,X1,X2,X3,4]
				ArrayList<Integer> tempList_4_1 = new ArrayList<>();
				ArrayList<Integer> tempList_4_2 = new ArrayList<>();
				for (int i = 0; i < relation.length; i++) {
					if (relation[i][0]==resultLine[0]) {
						tempList_4_1.add(relation[i][1]);
					}
					if (relation[i][1]==resultLine[resultLine.length-1]) {
						tempList_4_2.add(relation[i][0]);
					}
				}
				int resultNum_4=0;
				for (int temp1 :
						tempList_4_1) {
					ArrayList<Integer> endList = findEndList(relation, temp1);
					for (int temp2 :
							tempList_4_2) {
						ArrayList<Integer> startList = findStartList(relation, temp2);

						for (int end :
								endList) {
							for (int start :
									startList) {
								if (end==start) {
									resultNum_4++;
								}
							}
						}

					}
				}
				return resultNum_4;
			case 5://[0,X1,X2,X3,X4,4]
				ArrayList<Integer> tempList_5_1 = new ArrayList<>();
				for (int i = 0; i < relation.length; i++) {
					if (relation[i][0]==resultLine[0]) {
						tempList_5_1.add(relation[i][1]);
					}
				}
				int resultNum_5=0;

				for (int temp1 :
						tempList_5_1) {
					ArrayList<Integer> endListX2 = findEndList(relation, temp1);
					for (int tempX2 :
							endListX2) {
						ArrayList<Integer> endListX3 = findEndList(relation, tempX2);
						for (int tempX3 :
								endListX3) {
							ArrayList<Integer> endListX4 = findEndList(relation, tempX3);
							for (int tempX4 :
									endListX4) {
								ArrayList<Integer> endListX5 = findEndList(relation, tempX4);
								for (int tempX5 :
										endListX5) {
									if (tempX5==resultLine[resultLine.length-1]) {
										resultNum_5++;
									}
								}

							}
						}
					}
				}
				return resultNum_5;
		}

		return 0;

	}
}

结果是对了,但N层嵌套循环实在太折磨人,消耗的内存和耗时也是异常的高,以至于我虽然知道这个多层嵌套循环改写一下,可以用递归来总结,可以让代码看起来少一些,但我也并不想这么做了,因为我觉得我的思路是麻烦的,我还是应该抱着学习的态度,而不是把他做出来的态度来做题。

我看了一下大神的代码:

class Solution {
    public int numWays(int n, int[][] relation, int k) {
        int [][] dp=new int[k+1][n];
        dp[0][0]=1;
        for(int i=0;i<k;i++){
            for(int []edge:relation){
                int src=edge[0],dst=edge[1];
                dp[i+1][dst]+=dp[i][src];
            }
        }
        return dp[k][n-1];
    }
}

简直是天壤之别,我在验证他的算法时,在思考他为什么会这么写,他为什么能想到,而我为什么想不到这个思路。

经过思考,我将他的思路捋顺了一下,
使用这组数据:
n = 5, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3
用一个图示表示了出来:
在这里插入图片描述
用图表示出来感觉清晰了很多,问题转变为:
在确定的步数(纵坐标格数)内,有几种方式从startNum走向endNum,这样理解是没错的,但是如果考虑到这个图了,也未必写得出代码,是个很大的问题。
而大神用了一个巧妙的方式,将确定的步数作为最外循环,每循环一次相当于走一步,每走一步,通过二维数组的遍历,都能读到“当前的这一步作为起始数字,下一步为终点数字,的信息”,然后为下一步的数字格增加当前步有几条路能到达,
比如图中的[k=3,n=4]的格子之所以填3,是因为加了三次1,
假如[k=2,n=3]的格子数字是2(意味着到达这个格子的路有两条),那么[k=3,n=4]的格子就会填写4了。

然后反观原题,解题思路重点有2条对于我来说,
第一条就是,能不能构造出这样易于理解题意的模型;
第二条就是,构建出这样的模型后,能不能根据模型写出高效的代码。

标签:07,LCP,int,ArrayList,resultLine,length,relation,题库,tempList
来源: https://blog.csdn.net/qq_14873525/article/details/118405243