当青训营遇上码上掘金 主题 3:寻友之旅

35 阅读3分钟

当青训营遇上码上掘金 主题 3:寻友之旅

我选择的主题描述如下:

主题 3:寻友之旅

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

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

解题思路

求最快到达时间,由于小青每次移动的时间是固定的,因此最快到达的时间就相当于求解最少移动的次数。将坐标上所有整数视为节点,节点与节点之间如果可以通过步行或公交的方式直接到达,那么可以将这两个节点视为通过一条有向边直接相连。

如此一来,可以构造一个有向图,其中每个节点都对应一个非负整数。考虑到 0≤N , K≤100 000,因此节点的数量也是100 000。所有相邻的整数之间都有有向边相连,例如:1→2,2→3,3→2,2→1,以此类推。除此以外,每个整数还存在指向其2倍的整数节点的有向边,例如:2→4,4→8,3→6,以此类推。

如此建模之后,原题就转化成了在这个有向图上从地点N这个节点出发,最少经过几条有向边,才能到达地点K对应的节点。可以使用广度优先搜索算法(BFS)进行求解。

BFS算法

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

其算法过程如下:

  1. 访问顶点vi ;
  2. 访问vi 的所有未被访问的邻接点w1 ,w2 , …wk ;
  3. 依次从这些邻接点(在步骤②中访问的顶点)出发,访问它们的所有未被访问的邻接点; 依此类推,直到图中所有访问过的顶点的邻接点都被访问;

算法实现

通常可以使用一个先进先出(FIFO)的队列数据结构,来实现BFS算法。对于这一题,本文给出python代码实现的BFS代码,供读者参考,也可通过“码上掘金”平台查看:code.juejin.cn/api/raw/719…

# 广度优先搜索BFS即可,用队列实现
from queue import Queue

def main(N: int, K: int) -> int:
    q = Queue()
    q.put((N, 0))
    while not q.empty():
        cur = q.get()
        if cur[0] == K:
            return cur[1]
        elif cur[0] < K:
            if cur[0] <= 100000:
                q.put((cur[0] + 1, cur[1] + 1))     # 往前走
                q.put((cur[0] * 2, cur[1] + 1))     # 公交车
            if cur[0] > 0:
                q.put((cur[0] - 1, cur[1] + 1))     # 往回走
        else:   # cur[0] > K
            q.put((cur[0] - 1, cur[1] + 1))     # 往回走
    return 0    


if __name__ == '__main__':
    # n = int(input("请输入N:"))
    # k = int(input("请输入K:"))
    n = 1
    k = 1023
    res = main(n, k)
    print('最短时间:', res)