bfs算法

167 阅读1分钟

广度优先搜索bfs又叫做层次遍历

转化为全零矩阵的最少反转次数

转化为全零矩阵的最少反转次数

算法:

将初始状态调用encode()加入并队列。在搜索过程中,依次取出队首状态,调用decode()得到二维矩阵,枚举二维矩阵中的每个位置进行反转,对于翻转后的状态,调用encode()函数,通过哈希集合判断该状态是否被搜索过。如果未被搜索,则将其加入队尾。当搜索到全零状态,即encode()的值也为0时,搜索结束。

本题思路关键:

  1. 将二维矩阵映射为int,方便存储
  2. 层次遍历时,每次通过计算队列的大小来了解当前所在层次
  3. 通过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;
    }
}