1.题目
2.思路
一开始想着能不能先使用DFS,快速写出来,然后再使用BFS来写,因为一般DFS写代码的时间短一点,BFS 需要自己构建队列,时间会长一点。
然后DFS超时了,因为DFS侧重于遍历从起点到最深的节点,相当于这里会遍历无数个没用的节点。时间复杂度应该是O(10 ^ 4 * 10 ^ 4),所以只能用BFS来判断。
对于BFS来说,每一次遍历都是一层,相当于是走一步,这样总会有x层的时候,走到target,找到答案,或者结束。
这道题的两个要点:
- 如何求解一个字符串的下一个字符串?比如一开始为“0000”,下一个字符串有哪些?
- 注意边界条件剪枝,比如记录是否访问过vis, 是不是出现在死亡数组里面。
第一个问题求解一个字符串的下一个字符串?
首先就是有四个字符可以进行+ 1 和 -1 两个操作,所以相当于有8个候选字符串。每次从中选一个假如队列即可。中间会有一些已经访问过的,所以记得去重剪枝,不然会超时。
注意字符串数组char[]arr转化为String的话,不要用arr.toString(),因为这样得到的是字符串的地址。需要使用new String(arr)
可以使用一个函数来计算下一个字符串的集合。这样代码功能区分更明显。
第二个问题剪枝
- 一开始用一个map存一下死亡数组,这样可以O(1)时间判断是否出现在死亡数组中。
- 用一个visMap记录这个字符串是否已经访问过,剪枝
- 最开始判断target是否出现在死亡数组里面,如果出现,直接return -1
- 找到结果,return step
时间复杂度——O(10^4 * (8 + 8) + 4 * m)
首先,从“0000” -- “9999”总共有10 ^ 4个字符串(状态空间的上限)。然后计算每个字符串的下一个字符为O(8), 加入队列也有O(8),然后还有计算思死亡数组的O(4 * m),大概是这样。
空间复杂度——O(10^4 * 8 + m + 1)
首先死亡数组的哈希表空间O(m), 然后队列中存的元素最大个数为10^ 4 , 每个字符串长度为4,还有一个step 1, 为O(10 * 4 + 5),大概是这样。
class Solution {
int ans = 0;
Map<String, Integer>map = new HashMap();
Map<String, Integer>visMap = new HashMap();
public int openLock(String[] deadends, String target) {
for(String s : deadends){
map.put(s, 1);
}
if(map.containsKey(target))return -1;
Deque<String[]>d = new ArrayDeque<>();
d.addLast(new String[]{"0000", "0"});
while(!d.isEmpty()){
String[]cur = d.pollFirst();
String start = cur[0];
int step = Integer.parseInt(cur[1]);
if(map.containsKey(start))continue;
if(visMap.containsKey(start))continue; //已经访问过
if(start.equals(target)){ //找到答案
return step;
}
visMap.put(start, 1);
List<String>list = getNextString(start);
for(String s : list){
if(!map.containsKey(s) && !visMap.containsKey(s)){
d.addLast(new String[]{s, step + 1 +""});
}
}
}
return -1;
}
public List<String> getNextString(String s){
char[]arrays = s.toCharArray();
int[]dx = new int[]{1, -1};
List<String>list = new ArrayList<String>();
for(int i = 0 ; i < 4; i++){
for(int j = 0 ; j < 2; j++){
char tempCopy = arrays[i];
int temp = (int)(arrays[i] - '0') + dx[j];
if(temp == -1){
arrays[i] = '9';
}
else if(temp == 10){
arrays[i] = '0';
}
else{
arrays[i] = (char)(temp + '0');
}
list.add(new String(arrays));
// list.add(arrays.toString()); //不能这样将字符数组转化为字符串。这样输出的是字符串的地址。
arrays[i] = tempCopy;
}
}
return list;
}
}
3.结果
如果用Set存储,应该时间还会再少一些。