题目来源:力扣(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 dead = new HashSet<>(Arrays.asList(deadends));
Set visited = new HashSet<>();
String init = "0000";
if (dead.contains(init) || dead.contains(target)) {
return -1;
}
if (target.equals(init)) {
return 0;
}
Set set1 = new HashSet<>();
set1.add(init);
Set set2 = new HashSet<>();
set2.add(target);
int count=0;
while (!set1.isEmpty() && !set2.isEmpty()) {
//将最小的集合遍历
if (set1.size() > set2.size()) {
Set temp = set1;
set1 = set2;
set2 = temp;
}
Set set3 = new HashSet<>();
for (String curLock : set1) {
List 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 findNeibors(String currLock){
int size = currLock.length();
List result = new ArrayList();
//对锁的4位数分别处理
for(int i=0;i