当前位置:   article > 正文

记2019.9.7华为机试_华为机考 location

华为机考 location

昨天参加了华为机考,今天将其记录一下,顺便总结一下不足。
第一题:给一个数组,从位置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<Integer> record_now=new HashSet<>();   //用来记录当前到达的状态
	HashSet<Integer> record_next=new HashSet<>();  //用来记录下一步的状态
	
	//第一步,跳到i
	for(int i=1;i<arr.length/2;i++){
		record_now.add(i);
	}
	int step=1;   //当前跳的步数
	//接着跳
	while(!record_now.isEmpty()){
		//location:当前位置,跳到下一次位置 location+arr[location]
		for(Integer location:record_now){
			//如果下一步可达,记录下一步的状态
			if(location+arr[location]<arr.length){
				record_next.add(location+arr[location]);
			}
		}
		//将下一次的状态设置为当前状态,当前状态清空,步数+1
		record_now.clear();
		record_now.addAll(record_next);
		record_next.clear();
		
		step++;
		//判断是否有直接跳到终点的
		if(record_now.contains(arr.length-1)){
			return step;
		}
	}
	//当所有状态都结束,但是没有到达终点的,return -1;
	return -1;		
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

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

public static int getMinStep(int []arr){
	int min=arr.length;  //最大步数
	//第一步,跳到i,判断从i要几步到终点
	for(int i=1;i<arr.length/2;i++){
		int tmp=minSearch(i,arr);
		if(tmp<min){
			min=tmp;
		}
	}
	//如果min值被改变,说明有的点到达了最后,而且此时的min值为最少步数,返回
	if(min!=arr.length){
		return min;
	}
	else{
		return -1;
	}
}

public static int minSearch(int i,int []arr){
	int step=1;
	int location=i;    //当前位置
	
	//还在数组中
	while(location<arr.length){
		location=location+arr[location];
		step++;
		//如果到达终点
		if(location==arr.length-1){
			return step;
		}
	}
	//如果没有到达终点,返回原始min值
	return arr.length;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

通过了!??

分析:
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)
  • 1
  • 2

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

考试结束,我又想了一下,既然没有把F(M,N)=f(M,N)算出来,要不如,画个表,找找规律,结果,果然发现了一些规律。
在这里插入图片描述
于是我大胆猜测:F(M,N)=F(M-1,N)+F(M,N-1)
证明:以F(2,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<N+1;j++){
   		 record[1][j]=1;
   	 }
   	 //列初始化
   	 for(int i=1;i<M+1;i++){
   		 record[i][1]=i;
   	 }
   	 //赋值
   	 for(int i=2;i<M+1;i++){
   		 for(int j=2;j<N+1;j++){
   			 record[i][j]=record[i-1][j]+record[i][j-1];
   		 }
   	 }
   	 //返回结果
   	 return record[M][N];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/919093
推荐阅读
相关标签
  

闽ICP备14008679号