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

180 阅读2分钟

当青训营遇上码上掘金

题目如下

主题 3:寻友之旅

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

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

看到这道题目第一反应就感觉和图的找最短路径题目很类似,而且比最短路径更简单一些,这道题目是一维的,不用像最短路径那样子要考虑四个方向,只需要考虑左右两个方向即可。
即每次向左走一步或者向右走一步或者向右移动到当前位置的两倍的点,一直这样子直到到地点K。求最短路径的常见做法就是广度优先搜索,因此这道题也使用同样的解法。当然,也可以使用深度优先搜索,但需要把每次深度优先搜索的结果进行比较,然后取一个最小值,最小值即为答案。由于广度优先搜索个人感觉会比较好理解,所以这里采用广度优先搜索的方法进行解题
用一个队列保存每次走到的点,下次从队列中依次取出这些点,对这些点做对应的操作,然后把操作后的结果放进队列,如此循环直到刚好走到点K或者队列为空。为了防止走到重复的点导致死循环,使用哈希表来记录加入过队列的点(即走过的点),在每个点加入队列前都判断该点是否在哈希表中,不在才加入队列中。并且一进入队列就标记为已访问
最终代码如下:

package main

import "fmt"

//定义数组表示每次移动的步数,2表示乘2
var pathX = []int{-1, 1, 2}

func FindFriend(N int, K int) int {
	used := make(map[int]bool) //标记走过的点
	ans := 0
	que := make([]int, 0)
	que = append(que, N)
	used[N] = true
	for len(que) > 0 {
		length := len(que)
		for i := 0; i < length; i++ {
			dx := que[0]
			if dx == K {
				return ans
			}
			que = que[1:]
			for j := 0; j < 3; j++ {
				px := 0
				if j == 2 {
					px = dx * 2
				} else {
					px = dx + pathX[j]
				}
				if px < 0 || px >= 2*K {
					continue
				}
				if !used[px] { //下一步要到达的点没有走过
					que = append(que, px)
					used[px] = true
				}
			}
		}
		ans++
	}
	return -1 //表示无法到达
}

func main() {
	var N int
	var K int
	fmt.Scanln(&N)
	fmt.Scanln(&K)
	ans := FindFriend(N, K)
	if ans == -1 {
		fmt.Println("小青无法到达小码家")
	} else {
		fmt.Println("小青到小码家时间为:", ans)
	}
}

菜鸟一个,如果有错希望大佬们指正~~~