寻友之旅|最短路径问题

82 阅读2分钟

当青训营遇上码上掘金

题目

寻友之旅

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

解答

这是一个求最短路径问题,可以使用广搜(BFS)解决。首先将小码的家作为终点,小青的家作为起点,然后开始搜索。在每一层遍历中,每一个点都可以通过步行或公交到达下一层的点。每次移动的时间都是1分钟,直到找到小码的家。最后输出到达小码的家所需的最短时间。

package main

import "fmt"

const MAX = 100001

func main() {
    n, k := 0, 0
    fmt.Scan(&n, &k)

    // 用队列存储已经遍历过的点,用visted数组记录每个点是否已经遍历过
    queue := make([]int, 0, MAX)
    visted := make([]bool, MAX)

    // 用distination数组记录每个点到起点的距离
    distination := make([]int, MAX)
    distination[n] = 0

    // 初始化起点
    visted[n] = true
    queue = append(queue, n)

    walk, bus, cur := 0, 0, 0
    for len(queue) > 0 {
        // 取出队头元素
        cur = queue[0]
        queue = queue[1:]

        // 分别计算步行和公交到达的点
        walk = cur - 1
        bus = cur * 2

        // 步行到达的点
        if walk >= 0 && !visted[walk] {
            visted[walk] = true
            distination[walk] = distination[cur] + 1
            queue = append(queue, walk)
        }

        // 公交到达的点
        if bus < MAX && !visted[bus] {
            visted[bus] = true
            distination[bus] = distination[cur] + 1
            queue = append(queue, bus)
        }
    }

    fmt.Println(distination[k])
}

分析

上面的算法是一种使用广搜(BFS)求最短路径的方法,主要流程如下:

  • 将小青的家作为起点,将小码的家作为终点。
  • 使用队列存储已经遍历过的点,用 visited 数组记录每个点是否已经遍历过。
  • distination 数组记录每个点到起点的距离。
  • 从起点开始遍历,每次从队列中取出一个点,分别计算步行和公交到达的点。
  • 更新到达的点的距离,并将其加入队列中。
  • 重复上述步骤直到找到终点。
  • 输出终点到起点的距离。

这个算法的时间复杂度为 O(n),空间复杂度为 O(n)。

EXTRA

对于 最短路径算法 问题还有一个更加通用的算法 Dijkstra 算法

Dijkstra算法的一般解题过程如下:

  1. 初始化: 将起点的距离设置为0,其余点的距离设置为无穷大,用一个vis数组记录每个点是否已经遍历过。
  2. 将起点加入队列,并将其设为已遍历。
  3. 取出队列中距离最小的点,记为当前点。
  4. 更新当前点的相邻点的距离,如果可以通过当前点到达相邻点,并且这条路径更短,则更新相邻点的距离。
  5. 将所有未遍历过的相邻点加入队列,并将它们标记为已遍历。
  6. 如果当前点是终点,则结束遍历。
  7. 如果队列不为空,则回到步骤3。
  8. 输出终点的距离。

Dijkstra算法是一种贪心算法,它每次选择距离最小的点进行扩展,保证每次选择的路径都是最短的,因此算法的时间复杂度为O(n^2)。

在实际应用中Dijkstra算法可以使用堆优化来优化时间复杂度,这样算法的时间复杂度就能降为O(nlogn)。

详细 Dijkstra 算法