17年网易笔试-跳石板:广度优先搜索
来源:互联网 发布:知乎周刊kindle推送 编辑:程序博客网 时间:2024/06/05 03:58
前言
17年网易笔试有一道编程题目《跳石板》,newcoder OJ链接如下:
跳石板-牛客网
题目描述如下:
小易来到了一条石板路前,每块石板上从1挨着编号为:1、2、3…….
这条石板路要根据特殊的规则才能前进:对于小易当前所在的编号为K的 石板,小易单次只能往前跳K的一个约数(不含1和K)步,即跳到K+X(X为K的一个非1和本身的约数)的位置。 小易当前处在编号为N的石板,他想跳到编号恰好为M的石板去,小易想知道最少需要跳跃几次可以到达。
例如:
N = 4,M = 24:
4->6->8->12->18->24
于是小易最少需要跳跃5次,就可以从4号石板跳到24号石板
没有实战过图搜索的题,考试中没啥思路,下来赶紧看看了解答,随后总结为此文。
广度优先搜索
Breadth First Search (BFS)是一种图搜索算法,BFS首先从源定点s开始,沿着s节点的宽度遍历节点,当所有跟s节点临接的节点都被访问过以后,再继续向下一层访问。
如下图所示
遍历顺序即为:1-2-3-4-5-6-7-8-9-10-11-12
想法一
首先最朴素的想法就是枚举N的所有约数(除了1和其本身),然后将所有约数与X的和作为N的子孙,构建一棵树以后,第一个值等于M的叶子节点的深度,即为最小跳跃次数。
节点可以通过一个类来定义,比如:
class Node{ int val; Node parent;}
或者
class Node{ int val; int depth; }
这样通过一个队列Q一步步广搜即可,但是实现想法以后,不论如何增加限制条件都Timeout,当M大于1000以后就基本上GG了,速度非常非常慢,为什么呢?OK,我们换个思路,继续。
想法二
既然简单的使用构建搜索树的方法行不通,我们换个思路。既然是广度搜索,每次遍历一层,那么我们就尝试每次循环记录一层的数字进行计算。
1、声明一个List curr存储一层节点,通过约数,计算下一层节点(比如一开始List只有一个数字N=4,通过计算约数,下一层就是有一个数字4+2=6)。
2、通过一个临时List tmp来存储计算的加过约数的和。
3、下一个循环用tmp替换curr。
类似于一下结构
List curr = new ArrayList<>();curr.add(N);while(flag){ List tmp = new ArrayList<>(); tmp.add(所有求得的约数); curr = tmp;}
这时输出每一次循环的curr发现,每一层有很多重复数值的节点,显然这些重复数值的节点再次计算是很浪费时间的。比如:
从n=4开始,第三层:
[8, 9, 8]
这就有两个8,那么这两个8继续分别向下计算,显然重复,因此可以合并一层中所有重复的值。
[8, 9]
OK,让我们上传OJ运行试试看…Sad,仍然Timeout。这是为什么呢~
想法三
在想法二的基础上,把M设置的大一些,不断地输出每一层的值就会发现,除了一层中可能出现的重复情况,各个层之间也会出现很多的相同值得节点,对呀,这就像题目中说的上楼梯,每一层楼梯都是固定的,到每一层阶梯的最小值通过广搜已经计算过了,再重复计算并没有什么用啊!这就回归到了DP的思想了。
因此最终改良版本,只需定义一个合适大小的数组,这个数组大小大于M,初始值设置为-1,表示没有到过,对所有没有到过的,只记录一次首次到达的前进次数(层数)即可。随后这个位置的儿子节点都无需再遍历了!
OK,最终代码如下,终于通过,感人,TAT
import java.util.LinkedList;import java.util.Queue;import java.util.Scanner;public class Main { public void run(){ Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int m = sc.nextInt(); int[] dst = new int[2*m]; for(int i=0;i<dst.length;i++) dst[i] = -1; dst[n] = 0; Queue<Integer> Q = new LinkedList<>(); Q.offer(n); while(!Q.isEmpty()){ int x = Q.poll(); for(int i=2; i*i <= x ; i++){ if(x%i == 0){ if(x+i<= m && dst[x+i] == -1) { Q.offer(x + i); dst[x+i] = dst[x] + 1; } if(x+x/i <= m && dst[x+x/i] == -1){ Q.offer( x + x/i); dst[x+ x/i] = dst[x] + 1; } } } } System.out.println(dst[m]); sc.close(); } public static void main(String[] args){ new Main().run(); }}
约数的计算
通过上一节的程序我们可以看到,计算x的约数无需从1遍历到x,而是只需从1遍历到sqrt(x)。
随后,x的约数就是2~sqrt(x)之间的i,还有对应的x/i。
这样就降低了搜索空间。
总结
1、算法复杂度太高,首先一点就是能不能减少无谓的重复计算?
2、减少重复计算的方式就是拿空间换时间,通过记录来避免重复部分的计算。
- 17年网易笔试-跳石板:广度优先搜索
- 网易笔试题:跳石板
- 网易笔试题--跳石板
- 网易2017校园招聘笔试题 跳石板
- 2017网易秋招笔试题 跳石板 C/C++
- 网易---跳石板
- 跳石板_网易编程
- 网易2017 跳石板问题
- 网易编程题--跳石板
- 2018校招笔试题——网易编程题跳石板
- 广度优先搜索算法
- 双向广度优先搜索
- 广度优先搜索法
- pku2251(广度优先搜索)
- POJ1184Clerver_Writer:广度优先搜索
- Java广度优先搜索
- [AI]广度优先搜索
- 广度优先搜索-BFS
- Python测试框架--nose
- mysql添加、删除索引
- 2016.09.10【初中部 NOIP提高组 】模拟赛C 总结
- 16.9.10 C:3059. 【NOIP2012模拟10.26】雕塑
- POJ 3691 DNA repair AC自动机+DP -
- 17年网易笔试-跳石板:广度优先搜索
- java接口相关
- 第3周项目4-顺序表应用(1)
- 初中OJ1994【普及组模拟赛】小口口矩阵
- centos 6.7安装xgboost
- 神奇的9种UML图
- Maven学习
- 赛码网笔试总结
- 操作系统常见面试题总结!!!!