Java 实现最优路径查找算法(伪Leetcode路径查找算法)
今天忙里偷闲写了下关于Leetcode里面的路径查找相关算法,题目在下面的链接,这个题目和它前面的62题是连在一起的,但是这个题目有一个规定是,只能向右和向下查找,这里就有很大的可操作性了,本文是基于四个方向都可以移动来实现的,并且没有规定死开始位置和目标位置。
这里说明一下,这个算法的主要采用的是递归的实现,但是放到Leetcode里面时间复杂度是过不了的,如果有更好的实现思路请私信或者留言给我,算法中有可以改进的地方,也请留言告知,谢谢!
这里发一下题目的链接:
https://leetcode.com/problems/unique-paths-ii/
PS:这个算法不是完全按照leetcode里面的题目,Leetcode里面是规定是只能向右和向下,本文算法实现是没有做规定的.
实现方法:
动态规划算法
实现说明:
动态规划算法实现 两个条件:1、递归方案,2、边界条件
递归方案:位置点的遍历;
边界条件:最终目的点和当前遍历的路径深度是否大于查找到的路径的深度;下一个位置点是否是障碍物点或者是否已经同遍历层级遍历过。该算法是找出所有的路径,在这些路径中可以找到最优解,并且最优解有可能不止一个。
- 在有第一条路径的时候,获取路径的长度。 然后在递归是可以判断当前路径的长度,如果已经大于已经有结果的最小路径,则直接回退即可,不需要遍历。
实现代码
代码里面是有相应的注释,就不过多解释了
public class Solution {
// 结果容器
private ArrayList<ArrayList<Point>> resultList = new ArrayList<ArrayList<Point>>();
// 已经有路径的步数大小,如果大于这个步数就不用在递归了,肯定不是最优解
private int alreadyPath = -1;
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
return uniquePathsWithObstacles(obstacleGrid, 0, 0,
obstacleGrid.length - 1, obstacleGrid[0].length - 1);
}
private int uniquePathsWithObstacles(int[][] obstacleGrid, int startX,
int startY, int endX, int endY) {
Point[] pointArray = constructPointArray(obstacleGrid);
if (pointArray != null && pointArray.length == 1
&& pointArray[0].value == 0) {
return 1;
}
if (pointArray[startY + startX * obstacleGrid[0].length].value == 1
|| pointArray[endY + endX * obstacleGrid[0].length].value == 1) {
return 0;
}
ArrayList<Point> list = new ArrayList<Point>();
list.add(pointArray[startY + startX * obstacleGrid[0].length]);
pointArray[startY + startX * obstacleGrid[0].length].IsCheck = true;
caclPath(pointArray, pointArray[startY + startX
* obstacleGrid[0].length], pointArray[endY + endX
* obstacleGrid[0].length], list, obstacleGrid);
return resultList.size();
}
private void caclPath(Point[] pointArray, Point currentPoint,
Point targetPoint, ArrayList<Point> pointList, int[][] obstacleGrid) {
if (alreadyPath != -1 && alreadyPath < pointList.size()) {
return;
}
if (currentPoint == targetPoint) {
ArrayList<Point> tempList = (ArrayList<Point>) pointList.clone();
if (tempList.size() < alreadyPath) {
resultList = new ArrayList<ArrayList<Point>>();
}
alreadyPath = tempList.size();
resultList.add(tempList);
currentPoint.IsCheck = false;
return;
} else {
ArrayList<Point> pointArrayTemp = currentPoint.getAroundPoint(
pointArray, obstacleGrid, targetPoint);
for (int i = 0; i < pointArrayTemp.size(); ++i) {
pointList.add(pointArrayTemp.get(i));
pointArrayTemp.get(i).IsCheck = true;
caclPath(pointArray, pointArrayTemp.get(i), targetPoint,
pointList, obstacleGrid);
pointArrayTemp.get(i).IsCheck = false;
pointList.remove(pointArrayTemp.get(i));
}
}
}
/**
* 组成点对象
*
* @param obstacleGrid
* @return
*/
private Point[] constructPointArray(int[][] obstacleGrid) {
Point[] arrayPoint = new Point[obstacleGrid.length
* obstacleGrid[0].length];
Point point = null;
for (int i = 0; i < obstacleGrid.length; ++i) {
for (int k = 0; k < obstacleGrid[0].length; ++k) {
point = new Point();
point.X = i;
point.Y = k;
point.IsCheck = false;
point.value = obstacleGrid[i][k];
arrayPoint[k + i * obstacleGrid[0].length] = point;
}
}
return arrayPoint;
}
private class Point {
public int X;
public int Y;
public boolean IsCheck;
public int value;
/**
* 获取某个点接下来可走的位置
*
* @param pointArray
* @param obstacleGrid
* @param targetPoint
* @return
*/
private ArrayList<Point> getAroundPoint(Point[] pointArray,
int[][] obstacleGrid, final Point targetPoint) {
Point original = this;
ArrayList<Point> arraylist = new ArrayList<Point>();
Point point = null;
// 上
if (original.X - 1 >= 0
&& pointArray[(original.X - 1) * obstacleGrid[0].length
+ original.Y].value != 1
&& !pointArray[(original.X - 1) * obstacleGrid[0].length
+ original.Y].IsCheck) {
// 说明点可以走
point = pointArray[(original.X - 1) * obstacleGrid[0].length
+ original.Y];
arraylist.add(point);
}
// 下
if (original.X + 1 < obstacleGrid.length
&& pointArray[(original.X + 1) * obstacleGrid[0].length
+ original.Y].value != 1
&& !pointArray[(original.X + 1) * obstacleGrid[0].length
+ original.Y].IsCheck) {
// 说明点可以走
point = pointArray[(original.X + 1) * obstacleGrid[0].length
+ original.Y];
arraylist.add(point);
}
// 左
if (original.Y - 1 >= 0
&& pointArray[(original.X) * obstacleGrid[0].length
+ original.Y - 1].value != 1
&& !pointArray[(original.X) * obstacleGrid[0].length
+ original.Y - 1].IsCheck) {
// 说明点可以走
point = pointArray[(original.X) * obstacleGrid[0].length
+ original.Y - 1];
arraylist.add(point);
}
// 右
if (original.Y + 1 < obstacleGrid[0].length
&& pointArray[(original.X) * obstacleGrid[0].length
+ original.Y + 1].value != 1
&& !pointArray[(original.X) * obstacleGrid[0].length
+ original.Y + 1].IsCheck) {
// 说明点可以走
point = pointArray[(original.X) * obstacleGrid[0].length
+ original.Y + 1];
arraylist.add(point);
}
return arraylist;
}
}
}
总结
这个算法是我认为最有意思的一个算法,它可以做路径查找的小游戏,在对战类的游戏中有很大的帮助,本文的缺陷是,递归方案使得时间耗时严重,后续会继续对其进行优化,有好的思路请留言告知。