【Leetcode】353. Design Snake Game

题目地址:

https://leetcode.com/problems/design-snake-game/

设计二维矩阵内的贪吃蛇游戏。题目保证蛇在吃了一个食物后,下一个食物不会处于蛇的身体上。要动态返回游戏的得分,每当蛇吃了一个食物后,身体会变长,并且得分会加 1 1 1;如果蛇走到了边界之外,或者走到了自己身上,得分返回 − 1 -1 1

思路是用双端队列,队头表示蛇头,队尾表示蛇尾,这样每走一步的时候,就可以将新走到的那个格子入队,并且队头出队。之所以要用双端队列,是因为需要用front()方法看一下蛇头在什么位置,才能接着走下一步。同时为了节省空间和查询迅速(这里查询迅速主要是为了查一下是否蛇头走到了自身),可以用一个哈希表记录蛇的身体的各个点的坐标。代码如下:

class SnakeGame {
#define x first
#define y second
  using PII = pair<int, int>;

 private:
  int m, n;
  int score, food_idx;
  vector<vector<int>> food;
  deque<PII> dq;
  struct phash {
    int operator()(const PII &p) const {
      return hash<int>()(p.x) ^ hash<int>()(p.y);
    }
  };
  unordered_set<PII, phash> st;

 public:
  SnakeGame(int width, int height, vector<vector<int>> &food)
      : n(width), m(height), score(0), food_idx(0), food(std::move(food)) {
    dq.emplace_back(0, 0);
    st.insert({0, 0});
  }

  int move(string dir) {
    char d = dir[0];
    int x = dq.front().x, y = dq.front().y;
    x += d == 'D' ? 1 : 0;
    x += d == 'U' ? -1 : 0;
    y += d == 'L' ? -1 : 0;
    y += d == 'R' ? 1 : 0;

    if (x < 0 || x >= m || y < 0 || y >= n) return -1;
    pair cur{x, y};
    if (food_idx < food.size())
      if (x == food[food_idx][0] && y == food[food_idx][1]) {
        score++;
        dq.emplace_front(x, y);
        st.insert({x, y});
        food_idx++;
        return score;
      }

    auto tail = dq.back();
    dq.pop_back();
    st.erase(tail);
    // 撞到自己了
    if (st.count(cur)) return -1;
    dq.emplace_front(x, y);
    st.insert({x, y});
    return score;
  }
};

时空复杂度 O ( d ) O(d) O(d) d d d指direction。

注解:
1、move()方法的最后,如果没走到食物,一定要先将蛇尾出队,再判断是否蛇头咬到自己,否则会出错。因为当蛇走了一步的时候,蛇尾会跟着一起走,即使蛇头下一步会走到蛇尾原先的地方,但由于蛇尾已经走掉了,此时并不会咬到自己。

2、本题使用双端队列是不得已而为之,如果不把整条蛇的格点全记录下来的话,即使知道蛇头会走到哪里,也很难判断蛇尾跟到了哪里,最困难的地方在于不知道蛇尾的下一步的方向。用双端队列就很好解决了这个问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值