如何避免访问二维数组中的无效位置?(骑士巡游问题场景)
骑士巡游边界校验优化方案
方案1:预定义偏移量统一校验
骑士的8种移动偏移是固定值,我们可以先把所有偏移量存为常量数组,遍历所有偏移后统一做边界校验,无需编写多组独立的if判断,代码更简洁易维护:
// 预定义骑士8种移动的行、列偏移量 int[][] knightOffsets = {{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}, {2, -1}, {2, 1}}; ArrayList<int[]> validMoves = new ArrayList<>(); int boardSize = 8; for (int[] offset : knightOffsets) { int newRow = currentRow + offset[0]; int newCol = currentColumn + offset[1]; // 同时校验边界+是否未访问 if (newRow >= 0 && newRow < boardSize && newCol >= 0 && newCol < boardSize && table[newRow][newCol] == 0) { validMoves.add(new int[]{newRow, newCol}); } } // 后续直接遍历validMoves做递归即可
注意:你原有代码中反复复用同一个arr数组对象,ArrayList存储的是对象引用,会导致所有添加的元素都和最后一次赋值的arr值一致,上述方案中每次添加都创建新数组解决了这个bug。
方案2:扩展棋盘边缘,完全省略边界判断
如果想要你理想中无需判断边界、直接访问的效果,可以把棋盘数组向外扩展骑士最大移动步长(2格)的宽度,边缘区域预先标记为不可用(非0值),访问越界位置时实际访问的是边缘的不可用区域,不会触发数组越界,自动被过滤:
// 初始化12x12的扩展棋盘,边缘2层赋值为-1(不可用),中间8x8为实际棋盘,初始值0 int[][] table = new int[12][12]; for (int i = 0; i < 12; i++) { for (int j = 0; j < 12; j++) { table[i][j] = (i < 2 || i >= 10 || j < 2 || j >= 10) ? -1 : 0; } } // 后续获取合法移动时无需判断边界 int[][] knightOffsets = {{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}, {2, -1}, {2, 1}}; ArrayList<int[]> validMoves = new ArrayList<>(); // 注意:实际使用的棋盘坐标要统一加2,比如初始位置(0,0)对应扩展棋盘的(2,2) for (int[] offset : knightOffsets) { int newRow = currentRow + offset[0]; int newCol = currentColumn + offset[1]; if (table[newRow][newCol] == 0) { validMoves.add(new int[]{newRow, newCol}); } }
内容的提问来源于stack exchange,提问作者Waifu_Forever
相关产品推荐
相关产品推荐

