Google面试题 | 贪吃蛇

1,614 阅读3分钟

专栏 | 九章算法
网址 | www.jiuzhang.com


题目描述

实现一个贪吃蛇游戏,贪吃蛇一开始在[0,0]位置且长度为1。每当贪吃蛇吃到食物,长度和获得的分数都增加一。对于每次move输出move之后的分数。如果贪吃蛇走出边界或和自己的身体相撞则游戏结束,输出-1。下面地图中 S是Snake, F是food

给出一个地图长为3,宽为2,food的位置是[1,2],[0,1]

一开始snake出现在[0,0],food出现在[1,2]

以下用S表示snake,用F表示food

|S| | |
| | |F|

snake.move("R"); -> Returns 0

| |S| |
| | |F|

snake.move("D"); -> Returns 0

| | | |
| |S|F|

snake.move("R"); -> Returns 1 (Snake eats the first food and right after that, the second food appears at (0,1) )

| |F| |
| |S|S|

snake.move("U"); -> Returns 1

| |F|S|
| | |S|

snake.move("L"); -> Returns 2 (Snake eats the second food)

| |S|S|
| | |S|

snake.move("U"); -> Returns -1 (Game over because snake collides with border)


算法分析

本题是个看似复杂的模拟题,需要我们实现两个函数:一是贪吃蛇游戏的构造函数,二是每一次的move并返回当前分数。

对于模拟题而言,一般有以下两个特点:

  1. 算法简单,只需模拟给定的操作。比如本题中就是模拟贪吃蛇的移动,纪录移动后贪吃蛇的身体的位置。

  2. 代码量大(相对),细节较多。

以本题为例,讲讲模拟题的思路。

1.读题,跟着样例梳理整个操作。本题中,我们首先按照输入的指定方向移动一下贪吃蛇(同时判断贪吃蛇有没有出界或者撞到自己),然后我们看看有没有吃到食物:对于吃到和不吃到两种情况调整贪吃蛇的长度。

2.选取合适的数据结构保存数据。本题中我们需要保存贪吃蛇的身体位置,同时贪吃蛇的头和尾巴的位置都有可能发生变化,因此我们需要用一个两端都能操作的队列(Deque)来保存贪吃蛇。另外,为了O(1)判断贪吃蛇是否撞到自己,我们用一个HashSet纪录贪吃蛇的身体。

3.细节与边界情况处理。本题中,有一种情况是贪吃蛇下一次move恰好移动到了尾巴位置,此时我们不应该认为贪吃蛇发生了相撞,因为头和尾巴是一起移动的(前提是它没吃到东西)。

最后我们来分析一下时空复杂度,Deque操作O(1),判断游戏结束也是O(1),总的move时间复杂度O(1)。空间复杂度,Deque大小为move的次数(用循环队列可以优化到widthheight),HashSet最大为widthheight。


参考程序

Design Snake Game 参考程序

面试官角度分析

本题属于中等难度以上的题目,算法方面没有特别的考量,主要考察面试者的代码能力和对队列这种数据结构的掌握程度。


推荐阅读



欢迎关注我的微信公众号:九章算法(ninechapter)。
精英程序员交流社区,定期发布面试题、面试技巧、求职信息等

九章算法,IT教育领域的深耕者
九章算法,IT教育领域的深耕者