864. Shortest Path to Get All Keys
864. Shortest Path to Get All Keys
题目: https://leetcode.com/problems/shortest-path-to-get-all-keys/
难度: Hard
题意:
- 给一个最大30*30的地图
- 其中有6个钥匙6个锁,锁要拿到相应的钥匙才能开
- 上下左右四个方向走,问最少要走多少步,才能拿到所有的钥匙
思路:
- 这个题比较暴力,就是广度优先搜索
- 注意搜索空间,总共最多才6个钥匙6个锁,定义状态为:去过的钥匙集合(二进制压缩),去过的锁集合(二进制压缩),当前位置。我们需要从这个状态转移到另一个状态,从这个状态开始广度优先搜索。转移到另一个状态,合并下一轮的搜索空间
- 复杂度是o(k * 2 ^ 6 * 2 ^ 6 *30 * 30),k是搜索空间所用数据结构的复杂度
- 这个题我写的比较差,主要是用了哈希表来保存搜索空间,引入了不必要的复杂度,超时了。大家写的时候直接用数组来保存搜索空间即可
- 这道题优化空间很大,可以剪枝,大家可以当做练习
代码:
class Solution {
private int[] dx = new int[]{1, -1, 0, 0};
private int[] dy = new int[]{0, 0, 1, -1};
private class State {
int setKey;
int setLock;
int posX;
int posY;
public State() {
}
public State(int setKey, int setLock, int posX, int posY) {
this.setKey = setKey;
this.setLock = setLock;
this.posX = posX;
this.posY = posY;
}
@Override
public int hashCode() {
int hashCode = 0;
hashCode = hashCode * 31 + Integer.hashCode(setKey);
hashCode = hashCode * 31 + Integer.hashCode(setLock);
hashCode = hashCode * 31 + Integer.hashCode(posX);
hashCode = hashCode * 31 + Integer.hashCode(posY);
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof State)) {
return false;
}
State state = (State) obj;
return setKey == state.setKey && setLock == state.setLock &&
posX == state.posX && posY == state.posY;
}
}
private class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public int shortestPathAllKeys(String[] grid) {
Map<State, Integer> currentMap = new HashMap<State, Integer>();
State start = new State();
int numKey = 0;
for (int i = 0;i < grid.length;i++) {
for (int j = 0;j < grid[i].length();j++) {
if (grid[i].charAt(j) == '@') {
start.posX = i;
start.posY = j;
}
if (grid[i].charAt(j) <= 'f' && grid[i].charAt(j) >= 'a') {
numKey ++;
}
}
}
start.setKey = start.setLock = ((1 << numKey) - 1);
currentMap.put(start, 0);
if (numKey == 0) {
return 0;
}
int ret = 0x3fffffff;
while (!currentMap.isEmpty()) {
Map<State, Integer> nextMap = new HashMap<State, Integer>();
for (State state: currentMap.keySet()) {
int curValue = currentMap.get(state);
if (state.setKey == 0) {
ret = ret < curValue ? ret : curValue;
continue;
}
int[][] dis = new int[grid.length][grid[0].length()];
for (int i = 0;i < grid.length;i++) {
for (int j = 0;j < grid[0].length();j++) {
dis[i][j] = 0x3fffffff;
}
}
dis[state.posX][state.posY] = 0;
LinkedList<Point> queue = new LinkedList<Point>();
queue.addLast(new Point(state.posX, state.posY));
while (!queue.isEmpty()) {
Point point = queue.pollFirst();
for (int i = 0;i < 4;i++) {
Point next = new Point(point.x + dx[i], point.y + dy[i]);
if (next.x < 0 || next.y < 0 || next.x >= grid.length || next.y >= grid[0].length()) {
continue;
}
char c = grid[next.x].charAt(next.y);
if (c == '#') {
continue;
}
if (c <= 'F' && c >= 'A' && (state.setKey & (1 << (c - 'A'))) != 0) {
continue;
}
if (dis[next.x][next.y] == 0x3fffffff) {
dis[next.x][next.y] = dis[point.x][point.y] + 1;
queue.addLast(next);
if (c <= 'f' && c >= 'a' && (state.setKey & (1 << (c - 'a'))) != 0) {
State nextState = new State(
state.setKey - (1 << (c - 'a')),
state.setLock,
next.x,
next.y
);
int value = currentMap.get(state) + dis[next.x][next.y];
if (!nextMap.containsKey(nextState) || value < nextMap.get(nextState)) {
nextMap.put(nextState, value);
}
}
if (c <= 'F' && c >= 'A' && (state.setLock & (1 << (c - 'A'))) != 0) {
State nextState = new State(
state.setKey,
state.setLock - (1 << (c - 'A')),
next.x,
next.y
);
int value = curValue + dis[next.x][next.y];
if (!nextMap.containsKey(nextState) || value < nextMap.get(nextState)) {
nextMap.put(nextState, value);
}
}
}
}
}
}
currentMap = nextMap;
}
if (ret == 0x3fffffff) {
return -1;
} else {
return ret;
}
}
}