算法题之迷宫中任意位置走任意长度的所有路径查询【原创题,非官方题目】

迷宫大家都知道是可以用通过dfs(深度优先算法)进行解决,现在问题如下:小明参加了一个迷宫游戏,这个游戏有这样一个规则:小明只能向上下左右方向任意走n步(可以走回头路),现在需要知道这任意的n步所能覆盖的点的范围和这n步所有的路径

基本原理

经过推理,任意走n步(可以走回头路)有一个规律,那就是所有点构成的图形是一个旋转45度的正方形,如下图所示
在这里插入图片描述
并且从图上可以发现一个规律就是不管从哪个点走,走n步后走到的点的个数为(n+1)^2, 经过测试这个规律是正确的。
那么现在问题又来了,如何去获取这些点的坐标和所有到达的路径呢?

获取点的坐标【难度:简单】

思路如下:

  1. 输入坐标(x,y)和要走的步数
  2. 利用递归实现上下左右四个方向随意走动的功能,每走一步步数减一
  3. 当步数为0时输出当前的点的坐标

代码如下:

/**
	 * 深度遍历某一个位置走nbStep后的点坐标
	 * @param x  初始时的横坐标,注意这里为二维数组的第二维度
	 * @param y  初始时的纵坐标,注意这里为二维数组的第一维度
	 * @param nbStep 第几步
	 * direction 方向 ( 规定 1- 向右,2-向下, 3-向左,4-向上)
	 * @return 所到达的点坐标集合
	 */
	public static List<String> DFSResult(
			int x, int y, int nbStep
	) {
		List<String> result = DFSResult(
				x, y, nbStep, new ArrayList<String>()
		);
		return result;
	}
	private static List<String> DFSResult(
			int x, int y, int nbStep, List<String> result
	) {
		if (nbStep == 0) {
			String res = "(" + x + "," + y + ")";
			if (!result.contains(res)) {
				result.add(res);
			}
			return result;
		}
		int nextX = 0, nextY = 0;
		for (int direction = 1; direction < 5; direction++) {
			switch(direction) {
			case 1: nextX = x + 1; nextY = y; break;
			case 2: nextX = x; nextY = y + 1; break;
			case 3: nextX = x - 1; nextY = y; break;
			case 4: nextX = x; nextY = y - 1; break;
			}
			DFSResult(nextX,nextY, nbStep - 1, result);
		}
		return result;
	}

输入:
原点坐标(4,4)
要走的步数 2

输出:

(6,4)
(5,5)
(4,4)
(5,3)
(4,6)
(3,5)
(2,4)
(3,3)
(4,2)

获取所有到达的路径【难度:困难】

思路:

  1. 利用stack(栈)的先进后出原理存储每个路径上的点
  2. 每次走一步前将要到达的点存入stack中
  3. 当前节点上下左右都递归完毕后就返回前一节点继续后续的递归,这里要pop一下

代码如下:

/**
	 * 深度遍历某一个位置走nbStep后的路径
	 * @param x  初始时的横坐标,注意这里为二维数组的第二维度
	 * @param y  初始时的纵坐标,注意这里为二维数组的第一维度
	 * @param nbStep 第几步
	 * direction 方向 ( 规定 1- 向右,2-向下, 3-向左,4-向上)
	 */
	//node 为路径上的节点
	private class Node{
		int x;
		int y;
		public int getX() {
			return x;
		}
		public void setX(int x) {
			this.x = x;
		}
		public int getY() {
			return y;
		}
		public void setY(int y) {
			this.y = y;
		}
		public Node(int x, int y) {
			super();
			this.x = x;
			this.y = y;
		}
		@Override
		public String toString() {
			return "Node [x=" + x + ", y=" + y + "]";
		}
		
	}
	//用栈存放路径的节点
	private static Stack<Node> stackNode = new Stack<>();
	private static List<String> DFSRoute(
			int x, int y, int nbStep
	) {
		List<String> res = new ArrayList<>(); // 返回结果
		// 如果是最后一个位置就返回路径
		if (nbStep == 0) {
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < stackNode.size(); i++) {
				Node node = stackNode.get(i);
				if (i == stackNode.size() - 1) {
					sb.append("(" + node.getX() + "," + node.getY() + ")");
				} else {
					sb.append("(" + node.getX() + "," + node.getY() + ") => ");
				}
			}
			res.add(sb.toString());		
			stackNode.pop(); //弹出最后一个元素
			return res;
		}
		Node node = new Path().new Node(x, y);
		if (stackNode.size() == 0) {
			stackNode.push(node);
		}
		int nextX = 0, nextY = 0;
		// 前后左右走一遍
		for (int direction = 1; direction < 5; direction++) {
			switch(direction) {
			case 1: nextX = x + 1; nextY = y; break;
			case 2: nextX = x; nextY = y + 1; break;
			case 3: nextX = x - 1; nextY = y; break;
			case 4: nextX = x; nextY = y - 1; break;
			}
			// 将将要走上的点存入stack中
			Node node1 = new Path().new Node(nextX, nextY);
			stackNode.push(node1);
			//开启下一个递归,将结果保存在res中
			res.addAll(DFSRoute(nextX,nextY, nbStep - 1));
		}
		// 关键点:每次前后左右都走了一遍后就返回前一节点
		stackNode.pop();
		return res;
	}

输入:
原点坐标(4,4)
要走的步数 2

输出:

(4,4) => (5,4) => (6,4)
(4,4) => (5,4) => (5,5)
(4,4) => (5,4) => (4,4)
(4,4) => (5,4) => (5,3)
(4,4) => (4,5) => (5,5)
(4,4) => (4,5) => (4,6)
(4,4) => (4,5) => (3,5)
(4,4) => (4,5) => (4,4)
(4,4) => (3,4) => (4,4)
(4,4) => (3,4) => (3,5)
(4,4) => (3,4) => (2,4)
(4,4) => (3,4) => (3,3)
(4,4) => (4,3) => (5,3)
(4,4) => (4,3) => (4,4)
(4,4) => (4,3) => (3,3)
(4,4) => (4,3) => (4,2)

写的不足之处欢迎指出,也欢迎联系我qq:271527068

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zygswo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值