当青训营遇上码上掘金
主题 3:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
思路:
这道题第一眼看上去是动态规划,实际上是BFS的变体。
递推公式如下:
然而我们发现这个递推公式的代码很难实现,因为当前节点dp[i]的结果可能来自于dp[i + 1],而dp[i + 1]是否已是最优解是未知的,因此很难实现递推公式的更新。
但是我们仔细观察可以发现,X-1、X+1和2*X可以看作是BFS的三个方向,而BFS又十分适合解最短路径,所以此题用BFS是一个很好的选择。
// 宽搜队列的节点定义
class Node {
int pos; // 当前位置
int count; // 已走步数
Node(int pos, int count) {
this.pos = pos;
this.count = count;
}
}
q.offer(new Node(N, 0));
while (!q.isEmpty()) {
Node cur = q.poll();
if (cur.pos == K) {
System.out.println(cur.count);
return;
}
if (cur.pos + 1 <= 100000 && !visited[cur.pos + 1]) {
q.offer(new Node(cur.pos + 1, cur.count + 1));
visited[cur.pos + 1] = true;
}
if (cur.pos - 1 >= 0 && !visited[cur.pos - 1]) {
q.offer(new Node(cur.pos - 1, cur.count + 1));
visited[cur.pos - 1] = true;
}
if (cur.pos * 2 <= 100000 && !visited[cur.pos * 2]) {
q.offer(new Node(cur.pos * 2, cur.count + 1));
visited[cur.pos * 2] = true;
}
}
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
思路:
经典接雨水,单调栈。分别从两端开始搜索单调递减栈,然后计算体积即可。
这里有个注意点是使用双端队列代替Java中的Stack,因为Stack继承自Vector,由synchronized关键词修饰效率很低,其次也继承了许多不属于Stack的操作。
List<Integer> a = new ArrayList<>();
int res = 0;
String line = "5,0,2,1,5,0,1,0,3";
String[] strs = line.split(",");
int amax = -1;
for (int i = 0; i < strs.length; i++) {
int t = Integer.parseInt(strs[i]);
a.add(t);
if (t > amax) {
amax = t;
}
res -= t;
}
res += amax;
Deque<Integer> dq = new LinkedList<>();
for (int i = 0; i < a.size(); i++) {
if (!dq.isEmpty()) {
while (!dq.isEmpty() && a.get(dq.peekLast()) < a.get(i)) {
dq.pollLast();
}
dq.offerLast(i);
} else {
dq.offerLast(i);
}
}
int r = dq.pollLast();
while (!dq.isEmpty()) {
int l = dq.pollLast();
res += (r - l) * a.get(r);
r = l;
}
dq.clear();
for (int i = a.size() - 1; i >= 0; i--) {
if (!dq.isEmpty()) {
while (!dq.isEmpty() && a.get(dq.peekLast()) <= a.get(i)) {
dq.pollLast();
}
dq.offerLast(i);
} else {
dq.offerLast(i);
}
}
r = dq.pollLast();
while (!dq.isEmpty()) {
int l = dq.pollLast();
res += (r - l) * a.get(r);
r = l;
}
System.out.println(res);