Leetcode.752 打开转盘锁
1. 思路
我们可以使用广度优先搜索,找出从初始数字 0000到解锁数字 target 的最小旋转次数。
具体地,我们在一开始将 (0000,0) 加入队列,并使用该队列进行广度优先搜索。在搜索的过程中,设当前搜索到的数字为 status,旋转的次数为 step,我们可以枚举 status 通过一次旋转得到的数字。设其中的某个数字为 next_status,如果其没有被搜索过,我们将(next_status,step+1) 加入队列。如果搜索到了 target,我们就返回其对应的旋转次数。
为了避免搜索到死亡数字,我们可以使用哈希表存储 deadends 中的所有元素,这样在搜索的过程中,我们可以均摊 O(1) 地判断一个数字是否为死亡数字。同时,我们还需要一个哈希表存储所有搜索到的状态,避免重复搜索。
2. 代码
class Solution {public int openLock(String[] deadends, String target) {if (target.equals("0000")) {return 0;}Set<String> dead = new HashSet<String>();for (String deaded : deadends) {dead.add(deaded);}if(dead.contains("0000")){return -1;}int step =0;Queue<String> queue = new LinkedList<String>();queue.add("0000");Set<String> seen = new HashSet<String>();seen.add("0000");while (!queue.isEmpty()){step++;int size = queue.size();for(int i=0;i<size;i++){String cur = queue.poll();for(String nextString:get(cur)){if(!seen.contains(nextString)&&!dead.contains(nextString)){if(nextString.equals(target)){return step;}queue.add(nextString);seen.add(nextString);}}}}return -1;}public char numPrev(char x) {return x == '0' ? '9' : (char) (x - 1);}public char numSucc(char x) {return x == '9' ? '0' : (char) (x + 1);}public List<String> get(String status) {List<String> ret = new ArrayList<String>();char[] array = status.toCharArray();for (int i = 0; i < 4; ++i) {char num = array[i];array[i] = numPrev(num);ret.add(new String(array));array[i] = numSucc(num);ret.add(new String(array));array[i] = num;}return ret;}}
Leetcode.773 滑动谜题
1. 思路
我们可以使用广度优先搜索,找出从初始状态 board 到目标状态 的最小交换次数。
具体地,我们在一开始将 加入队列,并使用该队列进行广度优先搜索。在搜索的过程中,设当前搜索到的状态为
,操作的次数为
,我们可以枚举 status 通过一次操作得到的状态。设其中的某个状态为 next_status,如果其没有被搜索过,我们就将
加入队列。如果搜索到了
,我们就返回其对应的操作次数。
在搜索的过程中,我们需要一个哈希表存储所有搜索到的状态,避免重复搜索。
如果搜索完成后,我们仍没有搜索到 ,说明我们无法解开谜板,返回 -1。
2.代码
class Solution {int[][] neighbors = {{1, 3}, {0, 2, 4}, {1, 5}, {0, 4}, {1, 3, 5}, {2, 4}};public int slidingPuzzle(int[][] board) {StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {stringBuffer.append(board[i][j]);}}String initial = stringBuffer.toString();if (initial.equals("123450")) {return 0;}int step = 0;Queue<String> queue = new LinkedList<String>();queue.offer(initial);Set<String> seen = new HashSet<String>();seen.add(initial);while (!queue.isEmpty()) {step++;int size = queue.size();for (int i = 0; i < size; i++) {String cur = queue.poll();for (String nextStatus : get(cur)) {if (!seen.contains(nextStatus)) {if (nextStatus.equals("123450")) {return step;}queue.offer(nextStatus);seen.add(nextStatus);}}}}return -1;}private List<String> get(String cur) {List<String> stringList = new ArrayList<String>();char[] chars = cur.toCharArray();int index = cur.indexOf('0');for (int y : neighbors[index]) {swap(chars, index, y);stringList.add(String.valueOf(chars));swap(chars, index, y);}return stringList;}public void swap(char[] array, int x, int y) {char temp = array[x];array[x] = array[y];array[y] = temp;}}
Leetcode. 909 蛇题棋
1. 思路
对于该问题,我们可以使用广度优先搜索。将节点编号和到达该节点的移动次数作为搜索状态,顺着该节点的出边扩展新状态,直至到达终点 ,返回此时的移动次数。若无法到达终点则返回 -1
2. 代码
class Solution {public int snakesAndLadders(int[][] board) {int n = board.length;boolean[] vis = new boolean[n * n + 1];Queue<int[]> queue = new LinkedList<int[]>();queue.offer(new int[]{1, 0});while (!queue.isEmpty()) {int[] p = queue.poll();for (int i = 1; i <= 6; ++i) {int nxt = p[0] + i;if (nxt > n * n) { // 超出边界break;}int[] rc = id2rc(nxt, n); // 得到下一步的行列if (board[rc[0]][rc[1]] > 0) { // 存在蛇或梯子nxt = board[rc[0]][rc[1]];}if (nxt == n * n) { // 到达终点return p[1] + 1;}if (!vis[nxt]) {vis[nxt] = true;queue.offer(new int[]{nxt, p[1] + 1}); // 扩展新状态}}}return -1;}public int[] id2rc(int id, int n) {int r = (id - 1) / n, c = (id - 1) % n;if (r % 2 == 1) {c = n - 1 - c;}return new int[]{n - 1 - r, c};}}
