记2019.9.7华为机试

昨天参加了华为机考,今天将其记录一下,顺便总结一下不足。
第一题:给一个数组,从位置0开始,求第一步可到达跳【1,length/2)步,接着每一步的步数是当前数组元素的的大小,问跳到数组的最后一个元素最少要多少步?
eg
[1,2,3,4,5,6,7,8]
第一步:从1跳3步到arr[3]
第二步:3+arr[3]=3+4=7 到达末尾
结果:最少两步

当时的解题思路:还挺简单,直接用暴力,求第一个位置到终点所需的步数求,再求第二个到终点所需的步数,一直求到length/2-1时,所需的步数,然后比较最小不就好了吗?不对,这可是华为!一定不会这么简单,让我再想一想。嗯,既然求最小,那一定是要考察动态规划了,要用到动态规划,那一定是要求状态转移了,既然状态转移,一定要用集合来存储当前的状态和下一步的状态了,嗯,对,一定是这样。我用record_now集合来存储当前状态,用record_next集合存储下一个状态,这样只要在每次跳之前看看有没有当前的终点就好了?于是我写出了如下代码:

public static int getMinStep(int []arr){
	HashSet record_now=new HashSet<>();   //用来记录当前到达的状态
	HashSet record_next=new HashSet<>();  //用来记录下一步的状态
	
	//第一步,跳到i
	for(int i=1;i

测试结果:通过60%,部分测试用例因为耗时太长,通不过???
想不通原因,那我还是用暴力法来看看吧:

public static int getMinStep(int []arr){
	int min=arr.length;  //最大步数
	//第一步,跳到i,判断从i要几步到终点
	for(int i=1;i

通过了!??

分析:
1.为什么第一次没通过,而用暴力法直接通过了呢?我分析了可能的原因是:第一次我使用的动态规划思想在可能在本题中并不适用,因为动态规划和暴力法在时间复杂度上是一样的O(N^2)。可是至于为什么会这么耗时,动态规划不就是空间换时间吗?时间不应该更低吗?我也弄不清楚了。其实我反而觉得用动态规划是更好的。可能是个玄学问题???

2.使用动态规划的好处是能够提前终止(发现有到达终点的状态就终止),同一个状态不会多次计算(比如arr[3]=2,arr[4]=1都到达5,5在HashSet中只会存储一次),而暴力需要计算所有的结果比较一遍。其实就像图的遍历一样,动态规划用的是BFS,而暴力使用的是DFS,关键是DFS并不能记录重复的路径,它可能一条路走N次;而BFS不会走重复路径,而且有到了终点就停止。

事后反思:由于动态规划没有通过所有的测试用例,所以在这道简单题上花费了一个多小时,直接导致后面的题目都没做出来,唉······

第二题:给两个数M,N,M表示M中元素(1,2,3…),N表示N个成环,元素可重复使用,要求顺序和逆序都算同一种,如{(1,2,3)(2,3,1)(3,1,2)(3,2,1) (2,1,3)(1,3,2)}都算同一种,问有多少种组成的环?

给出样例 M=3 N=3    结果:10
(1,1,1)(1,1,2)(1,1,3)(1,2,2)(1,2,3)(1,3,3)(2,2,2)(2,2,3)(2,3,3)(3,3,3)

当时的解题思路:这既然是一个排列组合问题,那么结果和M,N之间一定有某种数学关系,难道华为要考察我的数学水平?凭借我高中数学的水平,我应该能把这种数学关系求出来,结果,时间结束了,我还是没把这个关系算出来。。。

考试结束,我又想了一下,既然没有把F(M,N)=f(M,N)算出来,要不如,画个表,找找规律,结果,果然发现了一些规律。
记2019.9.7华为机试_第1张图片
于是我大胆猜测:F(M,N)=F(M-1,N)+F(M,N-1)
证明:以F(2,2)为例
记2019.9.7华为机试_第2张图片
分析:首先F(2,2)肯定是包含F(1,2)这种情况的,然后对于F(2,1)->F(2,2)其实是环增加一个元素,然后不要与F(1,2)冲突,不与F(1,2)冲突,环就必须增加一种不与F(1,2)中M种元素相同的元素才可以保证。对于加入的位置,由于成环,并且正逆序算作同一种,其实对于F(2,1)中的某个环,无论加到哪个位置,得到的N种最后都是同一种,所以F(2,1)中全新的(2,2)环,加上之前的(1,2)环,总共可以得到F(2,2)=F(1,2)+F(2,1)种(2,2)环。
同理:可得F(M,N)=F(M-1,N)+F(M,N-1)。(F(M,1)=M;F(1,N)=1)
理清思路,代码就很好写了:

public static int getResult(int M,int N){
   	 int [][]record=new int[M+1][N+1];
   	 
   	 //行初始化
   	 for(int j=1;j

算法时间复杂度(O(M*N))

第三题:我题目都没来得及看(菜的真实),希望有谁能分享一下第三题的问题和解题思路。

总体来说,这次笔试并不是很顺利,主要问题还是在第一题上花费了太多时间,没有将时间分配好;至于为什么在第一题上花费了太多时间,还是经验不够,需要多加练习。

你可能感兴趣的:(算法题)