BFS
模板
// 计算从起点start到终点target 的最近距离
public int bfs(Node start,Node target){
Queue<Node> q ;// 核心数据结构
Set<Node> visited; // 避免走回头路
q.offer(start) ; //将起点加入队列
visited.add(start) ;
int step = 0 ;
while(!q.isEmpty()) {
int sz = q.size();
// 将当前队列中的所有节点向四周扩散
for(int i=0;i<sz;i++) {
Node cur = q.poll();
//划重点:这里判断是否到达终点
if( cur == target) return step ;
// 将cur的相邻节点加入队列
for(Node x : cur.adj()) {
if(x not in visited) {
q.offer(x);
visited.add(x);
}
}
}
// 划重点:更新步数在这里
step++;
}
}
397 整数替换
public int integerReplacement(int n) {
if(n==1) return 0;
Map<Long,Integer> map = new HashMap<>();
Deque<Long> d = new ArrayDeque<>() ;
d.addLast(n*1L);
map.put(n*1L,0);
while(!d.isEmpty()) {
long t = d.pollFirst();
int step = map.get(t);
long[] ns = t%2 == 0? new long[]{t/2} : new long[] {t+1,t-1} ; //每个节点可能的情况,都要加入队列
for(long x : ns ){
if(x==1) return step +1; // 达到终点
if(!map.containsKey(x)) { // 用map记录次数 如果已经有记录 就不用继续了。
map.put(x,step+1);
d.addLast(x);
}
}
}
return -1;
}
838 推多米诺
注意的是:需要有一个时间的判定。在相同的时间受到两个方向的力才保持不变。而time就是起时间记录的作用,比如在本位置,的下一步是向右倒下,那么对应的时间是time+1,只有当右边过来的向左倒下的时间也是time+1的时候,才保持中立。
public String pushDominoes(String dominoes) {
char[] cs = dominoes.toCharArray();
int n = cs.length ;
int[] g= new int[n] ;
Deque<int[]> d = new ArrayDeque<>();
for(int i=0;i<n;i++) {
if(cs[i]=='.') continue ;
int dire = cs[i] == 'L' ? -1 : 1;
d.add(new int[]{i,1,dire});
g[i] = 1;
}
while(!d.isEmpty()) {
int[] info = d.pollFirst() ;
int loc = info[0],time = info[1],dire = info[2];
int ne = loc + dire; //下一个位置
if(ne<0||ne>=n) continue ; // 越界
if(g[ne]==0){ // 首次受力
d.addLast(new int[]{ne,time+1,dire});
g[ne] = time +1 ;
cs[ne] = dire==-1?'L':'R';
}else if(g[ne]==time+1) { // 多次受力
cs[ne] = '.';
}
return String.valueOf(cs);
}
}
752 打开转盘锁
public static int openLock(String[] deadends, String target) {
HashSet<String> set = new HashSet<>();
for(String str : deadends) set.add(str); //将死锁的情况记录下来
Deque<String> deque = new ArrayDeque<>();
HashSet<String> set2 = new HashSet<>(); //用来记录已经遍历过的情况
deque.addLast("0000");
set2.add("0000");
int step = 0;
while(!deque.isEmpty()) {
int sz = deque.size();
for(int n=0;n<sz;n++) { //不能少了双遍历的这一步
String poll = deque.poll(); //poll 或者是pollFirst 对应下面是 addLast
if(poll.equals(target)) return step;
if(set.contains(poll)) continue ; //不能在这里直接判定是否已经遍历过,因为前面先将“0000”加入了set2,此时如果直接判断就会跳出循环。
char[] cs1 = poll.toCharArray();
for(int i=0;i<4;i++) {
char[] cs2 = cs1.clone();
if(cs1[i]=='9') cs2[i] = '0';
else cs2[i] = (char) (cs1[i]+1);
String str = new String(cs2); //不能直接sc2.toString() 这样输出的是地址
if(!set2.contains(str)) {
deque.offer(str);
set2.add(str);
}
if(cs1[i]=='0') cs2[i] = '9';
else cs2[i] = (char) (cs1[i]-1);
String str2 = new String(cs2);
if(!set2.contains(str2)) {
deque.offer(str2);
set2.add(str2);
}
}
}
step ++ ;
}
return -1;
}
}