773. 滑动谜题(BFS)

向右看齐 2023-10-05 19:52 95阅读 0赞

773. 滑动谜题

  • 题目
  • 解题思路
  • 代码

题目

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

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

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

给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。
在这里插入图片描述
提示:

  • board 是一个如上所述的 2 x 3 的数组.
  • board[i][j] 是一个 [0, 1, 2, 3, 4, 5] 的排列.

解题思路

对于这种计算最小步数的问题,我们就要敏感地想到 BFS 算法。

每次先找到数字 0,然后和周围的数字进行交换,形成新的局面加入队列…… 当第一次到达 target 时,就得到了赢得游戏的最少步数。

这里的 board 仅仅是 2x3 的二维数组,所以可以压缩成一个一维字符串。其中比较有技巧性的点在于,二维数组有「上下左右」的概念,压缩成一维后,如何得到某一个索引上下左右的索引?

很简单,我们只要手动写出来这个映射就行了:

  1. int[][] neighbor = new int[][]{
  2. {
  3. 1, 3},
  4. {
  5. 0, 4, 2},
  6. {
  7. 1, 5},
  8. {
  9. 0, 4},
  10. {
  11. 3, 1, 5},
  12. {
  13. 4, 2}
  14. };

在这里插入图片描述

在一维字符串中0的下标为4,那么0在原来二维数组的相邻元素是4、5、3它们对应的索引是:1、3、5。也就是neighbor[4]

至此,我们就把这个问题完全转化成标准的 BFS 问题了。接下来就只要套模板了。

代码

  1. class Solution {
  2. public int slidingPuzzle(int[][] board) {
  3. int m = 2;
  4. int n = 3;
  5. String start = "";
  6. StringBuffer sb = new StringBuffer();
  7. String target = "123450";
  8. //将2*3的数组转化成一个字符串
  9. for (int i = 0; i < m; i++) {
  10. for (int j = 0; j < n; j++) {
  11. sb.append(board[i][j]);
  12. start = sb.toString();
  13. }
  14. }
  15. //记录在一维字符串中 某个元素在 原来二维数组 中的 相邻元素 的索引。
  16. int[][] neighbor = new int[][]{
  17. {
  18. 1, 3},
  19. {
  20. 0, 4, 2},
  21. {
  22. 1, 5},
  23. {
  24. 0, 4},
  25. {
  26. 3, 1, 5},
  27. {
  28. 4, 2}
  29. };
  30. /*开始BFS*/
  31. Queue<String> q = new LinkedList<>();
  32. Set<String> visited = new HashSet<>();
  33. q.offer(start);
  34. visited.add(start);
  35. int step = 0;//因为start就是初始值,没有动过,所以步数不需要从1开始
  36. while (!q.isEmpty()) {
  37. int size = q.size();
  38. for (int i = 0; i < size; i++) {
  39. String cur = q.poll();
  40. if (cur.equals(target)) {
  41. return step;
  42. }
  43. //idx用来保存‘0’的索引。因为我们只可以移动‘0’
  44. int idx = 0;
  45. //这个循环就是从字符串中找到‘0’的索引
  46. for (; cur.charAt(idx) != '0'; idx++) {
  47. }
  48. //交换0和相邻元素的位置
  49. // neighbor[idx]:和0在二维数组中相邻元素的索引
  50. for (int adj : neighbor[idx]) {
  51. String new_board = cur;
  52. new_board = exchangeString(new_board, idx, adj);
  53. if (!visited.contains(new_board)) {
  54. q.offer(new_board);
  55. visited.add(new_board);
  56. }
  57. }
  58. }
  59. step++;
  60. }
  61. return -1;
  62. }
  63. /**
  64. * 交换字符
  65. *
  66. * @param string
  67. * @param src
  68. * @param dis
  69. * @return
  70. */
  71. public String exchangeString(String string, int src, int dis) {
  72. char[] chars = string.toCharArray();
  73. char temp = chars[dis];
  74. chars[dis] = chars[src];
  75. chars[src] = temp;
  76. return new String(chars);
  77. }
  78. }

发表评论

表情:
评论列表 (有 0 条评论,95人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Jetbrains第三组解答

    好了,最后来介绍一下Jetbrains第三组谜题的解决办法吧。 线索一:推特代码 先看看这次的推特代码,和前两组不太一样,这次是真的无意义随机字符串了。不过之前一段时间

    相关 Jetbrains第二组解答

    今年是Jetbrains公司创立20周年,怪不得Jetbrains会推出福利活动,顺带还有第二个解谜活动。当然我消息知道的晚了, 估计活动已经结束了,但是这个解谜活动还是挺有趣

    相关 (Puzzle)

    有一个5×5的网格,其中恰好有一个格子是空的,其他格子各有一个字母,一共有四种指令:A,B,L,R,分别表示把空格上、下、左、右的相邻字母移到空格中。输入初始网格和指令序列(分

    相关 C语言

    C语言的一些Tricky,分享一蛤,看看对理解C语言很有帮助。 [http://coolshell.cn/articles/945.html][http_coolshell