【力扣】773. 滑动谜题

  •  问题描述

在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示.

一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换.

最终当板 board 的结果是 [[1,2,3],[4,5,0]] 谜板被解开。

给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。

  • 示例
输入:board = [[1,2,3],[4,0,5]]
输出:1
解释:交换 0 和 5 ,1 步完成

输入:board = [[1,2,3],[5,4,0]]
输出:-1
解释:没有办法完成谜板

输入:board = [[4,1,2],[5,0,3]]
输出:5
解释:
最少完成谜板的最少移动次数是 5 ,
一种移动路径:
尚未移动: [[4,1,2],[5,0,3]]
移动 1 次: [[4,1,2],[0,5,3]]
移动 2 次: [[0,1,2],[4,5,3]]
移动 3 次: [[1,0,2],[4,5,3]]
移动 4 次: [[1,2,0],[4,5,3]]
移动 5 次: [[1,2,3],[4,5,0]]
输入:board = [[3,2,4],[1,5,0]]
输出:14
  • 提示
  • board 是一个如上所述的 2 x 3 的数组.
  • board[i][j] 是一个 [0, 1, 2, 3, 4, 5] 的排列.
  • 解读 

1、广度优先搜索(bfs)。见 【模板】广度优先搜索(bfs)

  •  代码
	class Data {
		int[][] mat;
		int val;
		int len;

		public Data(int[][] mat, int len) {
			this.mat = mat;
			this.val = toHash(this.mat);
			this.len = len;
		}

	}

	Queue<Data> datas = new LinkedList<>();
	Set<Integer> sets = new HashSet<>();

	public int toHash(int[][] mat) {
		int m = mat.length;
		int n = mat[0].length;
		int sum = 0;
		int index = 1;
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				sum += mat[i][j] * index;
				index = index * 10;
			}
		}
		return sum;
	}

	public int[][] change(int[][] mat, int s, int t, int op) { // s, t 改变, op 0,上,1,下,2,左,3右
		int m = mat.length;
		int n = mat[0].length;

		int cs = s;
		int ct = t;

		if (op == 0) {
			cs--;
		} else if (op == 1) {
			cs++;
		} else if (op == 2) {
			ct--;
		} else {
			ct++;
		}
		if (cs < 0 || cs >= m || ct < 0 || ct >= n) {
			return null;
		}

		int[][] nm = new int[m][n];
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				nm[i][j] = mat[i][j];
			}
		}

		// s,t 与 cs, ct 交换

		int p = nm[s][t];
		nm[s][t] = nm[cs][ct];
		nm[cs][ct] = p;
		return nm;

	}

	public void addData(Data data) { // 产生下一个。

		int[][] mat = data.mat;
		int m = mat.length;
		int n = mat[0].length;

		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (mat[i][j] == 0) {
					for (int k = 0; k < 4; k++) {
						int[][] nm = change(mat, i, j, k);
						if (nm == null) {
							continue;
						}
						Data d = new Data(nm, data.len + 1);

						if (sets.contains(d.val)) {
							continue;
						}
						sets.add(d.val);
						datas.add(d);
					}
					return;
				}

			}
		}
	}

	public int slidingPuzzle(int[][] board) {

		Data data = new Data(board, 0);
		datas.offer(data);
		sets.add(data.val);
		while (!datas.isEmpty()) {
			data = datas.poll();
			if (data.val == 54321) {
				return data.len;
			}
			this.addData(data);

		}
		return -1;
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值