理论
概念
启发式搜索(Heuristically Search)又称为有信息搜索(Informed Search),它是利用问题拥有的启发信息来引导搜索,达到减少搜索范围、降低问题复杂度的目的,这种利用启发信息的搜索过程称为启发式搜索。
估价函数
启发式函数: h(n),它用来评价哪些结点最有希望的是一个我们要找的结点,h(n) 会返回一个非负实数,也可以认为是从结点n的目标结点路径的估计成本。
注意:估价函数的选取十分重要,会直接影响到算法的效率。
代码模板
有点类似于bfs,但这里使用的是优先队列,估价函数即优先级。
def AstarSearch(graph, start, end):
pq = collections.priority_queue() # 优先级 —> 估价函数
pq.append([start])
visited.add(start)
while pq:
node = pq.pop() # can we add more intelligence here ?
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
unvisited = [node for node in nodes if node not in visited]
pq.push(unvisited)
算法实践
问题描述
给你一个 n x n
的二进制矩阵 grid
中,返回矩阵中最短 畅通路径
的长度。如果不存在这样的路径,返回 -1
。
二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0
, 0
))到 右下角 单元格(即,(n - 1
, n - 1
))的路径,该路径同时满足下述要求:
- 路径途经的所有单元格的值都是
0
。 - 路径中所有相邻的单元格应当在
8
个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。
畅通路径的长度
是该路径途经的单元格总数。
示例
解题思路
先准备好8个方向的变化变量,然后从(0,0)
开始进行类bfs搜索,使用优先队列,估价函数为:到当前位置花费的成本 + x/y
坐标和上一个位置差的绝对值的最大值。
代码示例
class Solution {
int len = 0;
int[][] directions = new int[][]{{-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}};
public int shortestPathBinaryMatrix(int[][] grid) {
len = grid.length;
if (grid[0][0] == 1 || grid[len - 1][len - 1] == 1) {
return -1;
}
if (len == 1) {
return 1;
}
Queue<Node> queue = new PriorityQueue<>(10, Comparator.comparingInt(Node::cost));
queue.offer(new Node(0, 0, 1));
grid[0][0] = 1;
while (!queue.isEmpty()) {
Node current = queue.poll();
for (int i = 0; i < directions.length; i++) {
int x = current.x + directions[i][0];
int y = current.y + directions[i][1];
if (x == len - 1 && y == len - 1) {
return current.step + 1;
}
if (x < 0 || x >= len || y < 0 || y >= len) {
continue;
}
if (grid[x][y] == 0 || grid[x][y] > grid[current.x][current.y] + 1) {
grid[x][y] = current.step + 1;
Node newNode = new Node(x, y, grid[x][y]);
queue.add(newNode);
}
}
}
return -1;
}
class Node {
public int x;
public int y;
public int step;
public Node() {
}
public Node(int x, int y, int step) {
this.x = x;
this.y = y;
this.step = step;
}
public int cost() {
return step + Math.max(Math.abs(len - x - 1), Math.abs(len - y - 1));
}
}
}