当青训营遇上码上掘金 | 寻友之旅

169 阅读3分钟

当青训营遇上码上掘金

这次我选择的是 主题三:寻友之旅

题目

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。

  • 步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
  • 公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)

请帮助小青通知小码,小青最快到达时间是多久?

输入: 两个整数 N 和 K 输出: 小青到小码家所需的最短时间 (单位: 分)

解题思路

思考

有两种情况,第一种即 N > K 时 这种情况下由于公交车只能向前走, 所以肯定只能步行,一次走一格。 所以需要考虑 N < K的情况。

可能遇到的情况:

  • 公交直达 N = 10, K = 20 则此时 10 -> 公交 10*2 -> 20
  • 步行 -> 公交 N=6, k = 20 则此时 6 -> 步行 5 -> 公交 10 -> 公交 20
  • 公交 -> 步行 -> 公交 N = 6, K = 26 则此时 6 -> 公交 12 -> 步行 13 -> 公交 26
  • ...

由于N,K 可能出现的情况很多, 考虑问题时 很容易忽略其他解而得到错误的答案,我们可能考虑使用广度优先算法1, 来解决这类问题.

求解

可以使用广度优先搜索(BFS)来解决这个问题。将小青的当前位置作为起点,小码的位置作为终点,然后从起点开始搜索。

具体实现可以使用一个队列来存储当前所有可以到达的位置,每次从队列中取出第一个位置,然后把它能到达的位置加入队列。如这里我使用一个dist数组来记录每个节点到达起始节点n的距离。使用一个visited数组来记录每个节点是否被遍历过。

每次从队列中取出第一个节点,将其周围未被遍历过的节点加入队列并将其标记为已遍历。如果当前节点是K则代表遍历结束,输出此时的 dist['cur'] 即所需结果。

代码

package main

import "fmt"  

const (
    max = 100005
)
var (
    n, k int
    dist [max]int
    visited [max]bool
)

func main() {
    fmt.Println("input n, k:")
    fmt.Scan(&n, &k)
    
    // fittler
    if n < 0 || k > 100000 {
        fmt.Println("invalid input")
        return
    }
    
    queue := []int{n}
    dist[n] = 0
    visited[n] = true
    
    for len(queue) > 0 {
        
        // 将起始点压入队列
        cur := queue[0]
        queue = queue[1:]
        if cur == k {
            fmt.Println(dist[cur])
            return
        }
        // 步行向后
        if cur-1 >= 0 && !visited[cur-1] {
            visited[cur-1] = true
            dist[cur-1] = dist[cur] + 1
            queue = append(queue, cur-1)
        }
        
        // 步行向前
        if cur+1 < max && !visited[cur+1] {
            visited[cur+1] = true
            dist[cur+1] = dist[cur] + 1
            queue = append(queue, cur+1)
        }
        
        // bus
        if cur*2 < max && !visited[cur*2] {
            visited[cur*2] = true
            dist[cur*2] = dist[cur] + 1
            queue = append(queue, cur*2)
        }
    }
}

Footnotes

  1. 广度优先算法(BFS) 是一种图论算法,它是从起点开始,沿着宽度优先遍历图中的所有节点。它使用一个队列来存储待遍历的节点,每次取出队列中的第一个节点并将其相邻节点加入队列。广搜算法可用于求最短路径、最小生成树、拓扑排序等问题。