贪吃蛇
难度:
标签:
题目描述
代码结果
运行时间: 164 ms, 内存: 18.7 MB
/*
* Problem: LeetCode 353 - Design Snake Game
*
* The implementation using Java Streams focuses more on functional-style operations.
* We use streams where possible, although this problem is inherently stateful and stream usage is limited.
*/
import java.util.*;
import java.util.stream.Collectors;
public class SnakeGameStream {
private int width, height, score;
private Deque<int[]> snake;
private Set<String> snakeSet;
private List<int[]> food;
private int foodIndex;
public SnakeGameStream(int width, int height, int[][] food) {
this.width = width;
this.height = height;
this.food = Arrays.stream(food).collect(Collectors.toList());
this.score = 0;
this.foodIndex = 0;
this.snake = new LinkedList<>();
this.snakeSet = new HashSet<>();
this.snake.add(new int[]{0, 0});
this.snakeSet.add("0_0");
}
public int move(String direction) {
int[] head = snake.peekFirst();
int x = head[0], y = head[1];
switch (direction) {
case "U": x--; break;
case "L": y--; break;
case "R": y++; break;
case "D": x++; break;
}
String newHeadPos = x + "_" + y;
if (x < 0 || x >= height || y < 0 || y >= width || (snakeSet.contains(newHeadPos) && !newHeadPos.equals(snake.peekLast()[0] + "_" + snake.peekLast()[1]))) {
return -1;
}
snake.addFirst(new int[]{x, y});
snakeSet.add(newHeadPos);
if (foodIndex < food.size() && Arrays.equals(food.get(foodIndex), new int[]{x, y})) {
score++;
foodIndex++;
} else {
int[] tail = snake.removeLast();
snakeSet.remove(tail[0] + "_" + tail[1]);
}
return score;
}
}
解释
方法:
该题解使用双端队列 deque 和字典来模拟贪吃蛇游戏。字典 snake_dict 存储蛇身体每一节的位置,双端队列 snake 存储蛇身体的位置。move 方法根据给定的方向移动蛇头,同时判断是否出界、是否吃到自己以及是否吃到食物。如果吃到食物,则分数加 1,食物索引加 1;否则,将蛇尾从双端队列和字典中删除。最后,将新的蛇头位置加入双端队列和字典中。
时间复杂度:
O(1)
空间复杂度:
O(width * height)
代码细节讲解
🦆
在贪吃蛇游戏中,当蛇头移动到一个新的位置后,为什么需要检查这个新位置是否已经在蛇身字典中,这里的逻辑是如何确保不会错误地判断蛇吃到自己?
▷🦆
为什么在蛇吃到食物后不需要从字典中删除蛇尾的记录,而在没有吃到食物时需要这样做?
▷🦆
在实现中使用了双端队列和字典来存储蛇的每一节,这样的数据结构选择有什么特别的优势?
▷🦆
当蛇头向某个方向移动时,如何计算新的蛇头位置,并确保这个位置的计算是正确的?
▷