题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/open-the-lock
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。
解:
BFS(广度优先算法)一般解决办法:一般情况下,其邻居节点尚未被检验过的节点会被放置在一个被称为 open 的容器中(例如队列或是链表),而被检验过的节点则被放置在被称为 closed 的容器中;
本题思路:从根节点出发,寻找当前锁相邻的锁,然后将其添加到open集合中,然后每次将访问之后的锁添加到close集合中;
public static int openLock(String[] deadends,String target){
Set<String> dead = new HashSet<>(Arrays.asList(deadends));
Set<String> visited = new HashSet<>();
String init = "0000";
if (dead.contains(init) || dead.contains(target)) {
return -1;
}
if (target.equals(init)) {
return 0;
}
Set<String> set1 = new HashSet<>();
set1.add(init);
Set<String> set2 = new HashSet<>();
set2.add(target);
int count=0;
while (!set1.isEmpty() && !set2.isEmpty()) {
//将最小的集合遍历
if (set1.size() > set2.size()) {
Set<String> temp = set1;
set1 = set2;
set2 = temp;
}
Set<String> set3 = new HashSet<>();
for (String curLock : set1) {
List<String> neibors=findNeibors(curLock);
for (String nextLock : neibors) {
//如果set2中包含了这个Lock,则表示初试和目标在途中相遇到了
if(set2.contains(nextLock)) {
return count+1;
}
if (!dead.contains(nextLock) && !visited.contains(nextLock)) {
visited.add(nextLock);
set3.add(nextLock);
}
}
}
count++;
set1 = set3;
}
return -1;
}
/**
* 找当前锁相邻的锁
*/
public static List<String> findNeibors(String currLock){
int size = currLock.length();
List<String> result = new ArrayList<String>();
//对锁的4位数分别处理
for(int i=0;i<size;i++){
String temp = currLock;
char[] cs = temp.toCharArray();
if(cs[i]=='9'){
cs[i]= '0';
}else{
cs[i] = (char)(cs[i] +1);
}
temp = new String(cs);
result.add(temp);
//执行-1操作
temp = currLock;
cs = temp.toCharArray();
if(cs[i] =='0'){
cs[i] = '9';
}else{
cs[i]=(char)(cs[i]-1);
}
temp = new String(cs);
result.add(temp);
}
return result;
}
一步一个脚印,记录自己的成长