小知识,大挑战!本文正在参与「程序员必备小知识」创作活动
最短寻路算法是电梯算法的一种,其主要的思想是,当每次一次要运动时,选取离当前位置最近的位置移动。也就是每次只走最短的一步。 假设题目是这样的,有20个数,分布在 0到200,我们所处的位置为100。求以每次最短寻路情况下的路径。
我们可以认为这是一个搜索问题,类似深度优先搜索,每次搜索离我们最近的点移动。但是有一个问题就是,这样做的话,每当我们走一步,点离我们的距离是会动态变化的。麻烦的是每次我们都要重新最小的值决定移动方式。
这个思路并不是一个好的思路。我们得换一个想法来实现。
如果我们每次都知道左右两边离当前位置最近的点的位置,我们是不是就可以在常数的事件内决定当前的步数。
如果我们的数组是有序的,那么当前位置的两边,一定会有一个值离他最近,然后这个值的方向的下一个值会是下一次要比较的值。
这样的话,会类似于归并排序的merge操作,每次在两个数组中二选一,同样的这里的两个数组也应该是有序的。不同的地方在于,这里的类merge操作,它有个数组是倒着被选择的(因为靠进当前位置的方向距离才短)。
假设arr是已经排序过的数,序列划分成两节可以通过二分搜索来实现,代码实现如下:
pivot = bisect_right(arr, cur)
l, r = pivot - 1, pivot
positions = []
while l >= 0 or r < len(arr):
if r >= len(arr) or (l >= 0 and abs(arr[l] - cur) <= abs(arr[r] - cur)):
step += abs(arr[l] - cur)
cur = arr[l]
positions.append(arr[l])
l -= 1
else:
step += abs(arr[r] - cur)
cur = arr[r]
positions.append(arr[r])
r += 1
同样的也参考了归并排序merge中的哨兵的思想,当一边的数组已经耗尽之后,我们把它当作当作是无穷大,也就是离当前位置无穷远,可以直接考虑另一边。这样可以在一个循环里完成所有的合并操作。
当类比到了merge时,代码还是比较容易写的,当然这个方式也能看作是搜索算法,只是要从搜索的思路跳到这种实现,可能并不是那么容易。