字节青训营代码笔记

85 阅读1分钟

当青训营遇上码上掘金

主题 3:寻友之旅

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

思路:
这道题第一眼看上去是动态规划,实际上是BFS的变体。
递推公式如下:

IMG_0108.jpg 然而我们发现这个递推公式的代码很难实现,因为当前节点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);