当青训营遇上码上掘金
今天是在掘金写文章的第二天。记录的是两道算法题
- 寻友之旅--二分法
- 攒青豆--单调栈
寻亲之旅
题目描述
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
输入
两个整数 N 和 K
输出
小青到小码家所需的最短时间(以分钟为单位)
解析
可以考虑的情况:
- 公交不能后退
- 小码原地不动
第一种情况
小青在小码前面
由于公交不能后退,只能步行这种情况,所以时间就是N-K分钟
第二种情况
小码在小青前面
当 N<K 时,小青的位置为N,小码的位置为K。假设N在k/2 和K 之间,那N要么到K位置,要么到K/2位置。进行丢比,到K/2的代价为N-K/2+1(k若为奇数则再加1),到K的代价为K-N。
攒青豆
题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
输入
height = [5,0,2,1,4,0,1,0,3]
输出
17。上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
解析
记录青豆可以分为两种方式,而这两种方式又有不同的方法
- 列记录(每列宽一米)
- 行记录(按行来记录)
方法:
- 双指针
- 动态规划
- 单调栈
双指针
此方法是按照列计算来的,每列宽1,我们可以寻找一列的最左边最高的高度,在寻找此列最右边最高的高度
int lheight = height[i];
int rheight = height[i];
for(int j=i+1;j<height.length;j++){
rheight = Math.max(height[j],rheight);
}
for(int k=i;k>=0;k--){
lheight = Math.max(height[k],lheight);
}
左右最高的高度都找到后, h = Math.min(rheight,lheight)-height[i] 可以得出青豆数量。
需要注意的是:
- 计算的h又可能为负数
- 第一行和最后一行的青豆数量不用计算
动态规划
在上面的双指针中,我们计算了大量重复的左右最高高度,我们可以利用动态规划,记录在一个数组上,这样就可以避免重复技术。
最后的技术公式: min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度。 当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值。
即从左向右遍历:maxLeft[i] = max(height[i], maxLeft[i - 1]);
从右向左遍历:maxRight[i] = max(height[i], maxRight[i + 1]);
单调栈
用单调栈之前,先要知道这几点:
- 单调栈是按照行来计算的
- 单调栈内的元素是有序的
- 栈内遇到相同元素扔弃旧元素,push新元素
- 栈内保存的值是下标