广度优先搜索bfs又叫做层次遍历
转化为全零矩阵的最少反转次数
算法:
将初始状态调用encode()加入并队列。在搜索过程中,依次取出队首状态,调用decode()得到二维矩阵,枚举二维矩阵中的每个位置进行反转,对于翻转后的状态,调用encode()函数,通过哈希集合判断该状态是否被搜索过。如果未被搜索,则将其加入队尾。当搜索到全零状态,即encode()的值也为0时,搜索结束。
本题思路关键:
- 将二维矩阵映射为int,方便存储
- 层次遍历时,每次通过计算队列的大小来了解当前所在层次
- 通过HashSet来存储已经搜索过的状态,没有搜索过的状态才加入队列中
class Solution {
int r;
int c;
public int minFlips(int[][] mat) {
r=mat.length;
c=mat[0].length;
Set<Integer> s=new HashSet<> ();
Queue<Integer> q=new LinkedList<> ();
q.add(encode(mat));
s.add(encode(mat));
int step=0;
while (!q.isEmpty()) {
int len=q.size();
while (len>0) {
int curNum=q.poll();
if (curNum==0) {
return step;
}
int[][] cur=decode(curNum);
List<int[][]> children=flip(cur);
for (int[][] child:children) {
int code=encode(child);
if (s.add(code)) {//没搜索过这个节点,再加入队列
q.add(code);
}
}
len--;
}
step++;
}
return -1;
}
private List<int[][]> flip(int[][] mat){
List<int[][]> res=new ArrayList<> ();
int[][] dirs= {{1,0},{0,1},{-1,0},{0,-1}};
for (int i=0;i<mat.length;i++) {
for (int j=0;j<mat[0].length;j++) {
int[][] temp=cloneMat(mat);
temp[i][j]=temp[i][j]^1;
for (int[] dir:dirs) {
int newI=i+dir[0];
int newJ=j+dir[1];
if (inArea(newI, newJ)) {
temp[newI][newJ]=temp[newI][newJ]^1;
}
}
res.add(temp);
}
}
return res;
}
private boolean inArea(int x,int y) {
return x>=0 && x<r && y>=0 && y<c;
}
private int[][] cloneMat(int[][] mat){
int r=mat.length;
int c=mat[0].length;
int[][] res=new int[r][c];
for (int i=0;i<r;i++) {
for (int j=0;j<c;j++) {
res[i][j]=mat[i][j];
}
}
return res;
}
private int encode(int[][] mat) {
int n=0;
for (int i=0;i<r;i++) {
for (int j=0;j<c;j++) {
n=n*2+mat[i][j];
}
}
return n;
}
private int[][] decode(int n){
int shang=n;
int yu=0;
int[][] res=new int[r][c];
for (int i=r-1;i>=0;i--) {
for (int j=c-1;j>=0;j--) {
yu=shang%2;
shang/=2;
res[i][j]=yu;
}
}
return res;
}
}
滑动谜题
class Solution {
public int slidingPuzzle(int[][] board) {
Queue<Integer> q=new LinkedList<> ();
Set<Integer> s=new HashSet<> ();
int step=0;
q.add(encode(board));
s.add(encode(board));
while (!q.isEmpty()) {
int len=q.size();
while (len>0) {
int curNum=q.poll();
if (curNum==123450)
return step;
int[][] curMat=decode(curNum);
List<int[][]> ls=slide(curMat);
for (int[][] mat:ls) {
int code=encode(mat);
if (s.add(code)) {
q.add(code);
}
}
len--;
}
step++;
}
return -1;
}
private List<int[][]> slide(int[][] board){
List<int[][]> res=new ArrayList<> ();
int[][] dirs= {{1,0},{0,1},{-1,0},{0,-1}};
int[] pos=new int[2];//0的坐标
boolean flag=false;
for (int i=0;i<2;i++) {
for (int j=0;j<3;j++) {
if (board[i][j]==0) {
flag=true;
pos[0]=i;
pos[1]=j;
break;
}
}
if (flag)
break;
}
for (int[] dir:dirs) {
int[][] copy=clone(board);
int newX=pos[0]+dir[0];
int newY=pos[1]+dir[1];
if (inArea(newX, newY)) {
copy[pos[0]][pos[1]]=copy[newX][newY];
copy[newX][newY]=0;
}
res.add(copy);
}
return res;
}
private boolean inArea(int x,int y) {
return x>=0 && x<2 && y>=0 && y<3;
}
private int[][] clone(int[][] board){
int[][] copy=new int[2][3];
for (int i=0;i<2;i++) {
for (int j=0;j<3;j++) {
copy[i][j]=board[i][j];
}
}
return copy;
}
private int encode(int[][] board) {
int n=0;
for (int i=0;i<2;i++) {
for (int j=0;j<3;j++) {
n=n*10+board[i][j];
}
}
return n;
}
private int[][] decode(int n){
int[][] board=new int[2][3];
for (int i=1;i>=0;i--) {
for (int j=2;j>=0;j--) {
board[i][j]=n%10;
n/=10;
}
}
return board;
}
}