当青训营遇上码上掘金
寻友之旅
问题描述
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
解题思路
对于这题我写完后搜索了下其他人的解答,但似乎和我的想法不太一样,也不知道是不是我理解错题了,所以,以下仅供参考
小青和小码家在一条直线上如下(每个-符合代表一个节点):
-----小青--------. . . .-----小码----
对于移动有两个选择:
- 坐公交
- 走路
当小青还没到小码时,由于需要尽快到达,选择移动路程最多的方案
现在会出现一些情况:
-
当选择移动后恰好到达小码所在地点
-
当移动后会超过小码所在地点
这是需要具体考虑的情况,由于此时移动距离太大,所以考虑换成步行一步一步走到小码处,但是步行也可以后退,所以当(坐公交移动+后退步行消耗的时间)< (直接步行时间)时,选择坐公交然后后退,反之选择直接步行
代码实现(Java版)
public class FindFriend {
public int fastest(int N, int K) {
int time = 0;
while (N != K) {
if (N == 0) {
N = walkF(N);
time++;
continue;
}
// 当小青还没到小码时,由于需要尽快到达,选择移动路程最多的方案
if (bus(N) >= walkF(N) && bus(N) <= K) {
N = bus(N);
time++;
} else {
//bus(N) > K 当移动后会超过小码所在地点
//单纯走过去耗时
int onlyWalkTime = K - N;
//先坐车过去然后向后步行耗时, 公交车做一次用时1分钟
int busAndWalk = 1 + (bus(N) - K);
time += Math.min(onlyWalkTime, busAndWalk);
N = K;
}
}
return time;
}
private int bus(int x) {
return x * 2;
}
//go forward
private int walkF(int x) {
return x + 1;
}
//go backward
// private int walkB(int x) {
// return x - 1;
// }
}
样例输入
N K
0 1000
3 29
输出
35
8
其他语言代码实现
GO: code.juejin.cn/api/raw/718…
Python: code.juejin.cn/api/raw/718…
攒青豆
问题描述
现有 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,然后向右开始寻找第一个大于等于左边界的柱子,同时计算这个过程中遇到的柱子的总高度,因为找到右边界后这些低于左右边界的占位柱子就需要减去,但是存在一种情况就是右边没有一个柱子高度大于等于左边界,所以还需要一个变量,记录在寻找右边界过程中遇到的最高的柱子,同时还需要一个变量记录这个过程中占位柱子总高度,当大于等于左边界的右边界不存在时,将这个最高柱子作为右边界。
代码实现(Java)
public class GreenBean {
public int maxWater(int[] pillars) {
int total = 0;
int left = 0;
int right = 1;
while (right < pillars.length) {
//寻找右边界,右边界为除左边界外第一个大于等于右边界的柱子,
//如果没有则这选择右边第一高度的柱子
int[] rightAndTotal = rightBorder(left, pillars);
right = rightAndTotal[0];
int needToClear = rightAndTotal[1];
total += Math.min(pillars[left], pillars[right]) * (right - left - 1) - needToClear;
left = right++;
}
return total;
}
//寻找右边界,返回由右边界下标和桶内需要去除的占位所组成的二元数组
// return {右边界下标, 占位数}
private int[] rightBorder(int left, int[] pillars) {
//最大柱子下标
int maxIndex = left + 1;
int right = left + 1;
//桶内需要去除的柱子所占位置
int needToClear = 0;
//左边界与右边最大柱子之间占位柱子所耗空间
int betweenMax = 0;
while (right < pillars.length) {
//记录最大高度柱子的下标
if (pillars[maxIndex] <= pillars[right]) {
betweenMax = needToClear;
maxIndex = right;
}
if (pillars[left] <= pillars[right]) {
return new int[]{right, needToClear};
} else {
// right++;
needToClear += pillars[right++];
}
}
return new int[]{maxIndex, betweenMax};
}
public static void main(String[] args) {
int result = new GreenBean().maxWater(new int[] {6,4,5});
System.out.println(result);
}
}
样例输入
height
[5,0,2,1,4,0,1,0,3]
[8,1,6,1,4,1,2,1]
[1]
[11, 2, 4, 7, 18, 3, 8, 5, 9, 11]
输出:
17
9
0
39
其他语言实现
Go版: code.juejin.cn/api/raw/718…
Python版:code.juejin.cn/api/raw/718…