码上掘金题目思路分享

77 阅读5分钟

当青训营遇上码上掘金

首先我这次方向选的是后端方向,所以我选的是主题三和四。

那废话少说,就直接开始分析题目吧!

主题三:寻友之旅

题目:

小青要找小码去玩,他们的家在一条直线上,

当前小青在地点 N ,小码在地点 K (0≤N , K≤100000),并且小码在自己家原地不动等待小青。

小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久?

输入: 两个整数 N 和 K

输出: 小青到小码家所需的最短时间(以分钟为单位)

分析:

通过题目我们知道,小青和小码家位置可以分两种情况:

  • 小青家在小码前面:这时,小青可以选择公交+步行方式,不过这里就有两种方式了
    • 可以坐公交到快到的站点
    • 也可以“坐过站”然后再走回来(在我理解下这里应该有一个条件:站点位置不能超过1000000)
  • 小码家在小青前面:这时,小青只能通过步行方式抵达目的地,因为公交不能往后走

通过上面的分析我们就很容易就写出来基本的代码

int MinLoad(int n,int k){
	if(n>=k){//判断小青和小码家位置
		return n-k;
	}else{
		int ni =0;//记录坐公交的时间
		int nv =n;//记录公交站点位置
		while(nv<k){
			nv*=2;
			ni++;
		}
		if(nv<=100000){//判断公交站点是否超出1000000
			return nv-k>=k-nv/2?ni-1+k-nv/2:ni+nv-k;//总计算
		}else{
			return k-nv/2+ni-1;	
		}
	}
}

主题四:攒青豆

题目:

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,

此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

攒青豆.png 以下为上图例子的解析: 输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

分析:

这个题目我还是想了挺久的,也运行了好几个案例,还是一边做一边修修补补,所以代码实现有点小丑

总之我先来讲一下我的实现思路吧!

首先我注意到在每一次运算的时候都需要记住之前的值,这就让我想到了动态规划,而且深一点研究案例发现,我之后要得到结果的话就得先记录每一个可以盛水的柱子位置

然后就得考虑如何记录下每个可以盛水的柱子位置

我的想法就是在遍历柱子高度的过程中,先将第一个的位置和高度记录下来,然后后面的值有两种情况:

  • 当后面的值小于目前的值时:这时,高度跌下来了,这就意味着可以接豆子了,所以就可以找下一个需要记录的柱子了,这时还得做一个往前看的动作,就是如果前面记录下的值比刚刚记录下的值要小的话,就一直往前“吞”(替换),不过得做一个防误吞的操作,因为只有当前柱子的高度既小于目前的高度又小于前前柱子的高度时,才可以“吞”

  • 当后面的值大于目前的值时:这时,我们就可以把目前这个值替换掉(高度和位置一起),然后还得把之前记录下来的柱子看一遍(除了第一个柱子),看能不能“吞”,当然也要做防误吞处理

int beanNum(vector<int> Blist){
	int top=0,ans=0;
	//top:栈顶指针(因为我忘记用js的栈了,所以手动实现的,后面改成js方便些)
	//ans:用来存储挡住豆子的柱子的总高度
	int alist[50]={0},aIndex[50]={0};
	//alist:用来存最后留下来的柱子的高度
	//aIndex:用来存储柱子位置信息的
	
	//这里先放一个值进去做初始值
	alist[0] = Blist[0];
	aIndex[0] = 0;
	
	for(int i=1;i<Blist.size();i++){
		if(Blist[i]>=alist[top]){
			if(top!=0)ans+=alist[top];//统计减少豆子的柱子的高度
			while(Blist[i]>=alist[top-1]){
				if(top-1==0)break;
				if(alist[top-1]>alist[top-2])break;
				ans+=alist[top-1];
				alist[top]=0;
				top--;
			}
			alist[top] = Blist[i];
			aIndex[top] = i;
		}else{
			//这个是和上面while作用一样
			while(Blist[i]>=alist[top]){
				if(top==0)break;//防止吞掉第一个柱子
				if(alist[top]>alist[top-1])break;//防止误吞 如1 3 3 1 4 0 6 0 2 如果少掉这个if,6就会一直往前吞数据直到3,最后结果数组就会变成362,而实际上应该是3462
				ans+=alist[top];
				alist[top]=0;
				top--;
			}
			alist[++top] = Blist[i];
			aIndex[top] = i;
		}
	}
	//计算出结果(忽略减少豆子的柱子)
	int result = 0;
	for(int i=1;i<=top;i++){
		result+=min(alist[i],alist[i-1])*(aIndex[i]-aIndex[i-1]-1);
	}
	return result-ans;
}

实际效果:

我写算法的时候一般都喜欢用C++写,但是掘金的那个代码平台的新建项目我玩不来它基于C++的网页模板 所以我就用了js呈现代码效果,具体效果如下:

image.png

image.png