【Leetcode】818. Race Car

题目地址:

https://leetcode.com/problems/race-car/

有一辆车处在位置 0 0 0,初始速度为 1 1 1,有一个目标位置 t t t。如果其当前速度为 v v v,位置为 x x x,每一步其可以采取如下操作:
1、其可以走到 x + v x+v x+v的位置,并且 v v v变为 2 v 2v 2v
2、其可以将 v v v变为 − v ∣ v ∣ -\frac{v}{|v|} vv(速度变为负数的意思是方向反向)。
问其至少多少步能到达 t t t,其中 t ≥ 1 t\ge 1 t1

由于速度一定是 2 2 2的幂次,我们可以将 ( x , k , d ) (x,k,d) (x,k,d)做成一个状态, x x x是位置, k k k是速度的 2 2 2的指数, d d d是方向,正向为 1 1 1负向为 0 0 0。这样初始状态就是 ( 0 , 0 , 1 ) (0,0,1) (0,0,1)。那么问题就转为从 ( 0 , 0 , 1 ) (0,0,1) (0,0,1)走到 ( t , . , . ) (t,.,.) (t,.,.)至少要多少步,每一步可以走到 ( x + 2 k , k + 1 , d ) (x+2^k, k+1, d) (x+2k,k+1,d)或者 ( x , 0 , d ∧ 1 ) (x, 0, d\wedge 1) (x,0,d1),可以用BFS来解决。我们可以将连续的同方向的加速分隔出来,那么每次走的距离是 1 + 2 1 + . . . + 2 c − 1 = 2 c − 1 1+2^1+...+2^{c-1}=2^c-1 1+21+...+2c1=2c1,而这样的数的二进制表示即为连续的若干个 1 1 1。问题即是要用若干个形如那样的整数的加减凑出 t t t。如果走到 > 2 t >2t >2t的位置是不划算的,同样如果走到 < 0 <0 <0的位置也不划算。代码如下:

class Solution {
 public:
  struct Node {
    int x, k, d;
    bool operator==(const Node& n) const {
      return x == n.x && k == n.k && d == n.d;
    }
  };

  int racecar(int target) {
    queue<Node> q;
    auto nhash = [](const Node& n) {
      auto h = hash<int>();
      return h(n.x) ^ h(n.k) ^ h(n.d);
    };
    unordered_set<Node, decltype(nhash)> vis(0, nhash);
    q.push({0, 0, 1});
    vis.insert({0, 0, 1});
    int res = 0;
    while (q.size()) {
      res++;
      for (int i = q.size(); i; i--) {
        auto t = q.front(); q.pop();
        int x = t.x + (1 << t.k) * (t.d * 2 - 1);
        if (0 <= x && x <= target * 2) {
          if (x == target) return res;
          if (!vis.count({x, t.k + 1, t.d})) {
            q.push({x, t.k + 1, t.d});
            vis.insert({x, t.k + 1, t.d});
          }
        }

        x = t.x;
        int d = t.d ^ 1;
        if (!vis.count({x, 0, d})) {
          q.push({x, 0, d});
          vis.insert({x, 0, d});
        }
      }
    }
    return -1;
  }
};

时空复杂度 O ( t log ⁡ t ) O(t\log t) O(tlogt)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值