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

76 阅读2分钟

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

1. 题目大意

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

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

2. 解题思路

思路 1(最直观的贪心): 拿到题的第一思路就是贪心求解,(1)在反向移动(n>k)的情况下,只能选择步行,每次挪动一单位,耗时一分钟,最快到达时间即二者距离;(2)正向移动时,由于公交车是最快移动方式,因此每一步优先选择能否坐公交前进 (2*n < k),直到不能乘坐公交时选择步行走完剩下的路程,但是由于可以步行回退,这里需要比较是多乘一次车更近还是不乘更近。另外,根据题目意思,在 N = 0 的情况下,第一步只能选择步行向前,需要做一个特判。

时间复杂度:O(logn)O( logn )

空间复杂度:O(1)O (1)

思路 2(广度优先搜索)

从小青的位置出发,每次最多可达三个节点(N+1,N-1,2*N),因此可以采用广度优先搜索查找小码所在的节点,需要存储到达每个节点的时间,当到达小码的节点则直接返回其对应的时间,否则将当前节点的左右节点,以及公交节点2 * N入队(入队节点必须在0-100000之间)。若队列为空,则做错误处理,返回-1.

时间复杂度:O(n)O(n)

空间复杂度:O(n)O(n)

Go语言实现(贪心):

package main

import (
	"fmt"
	"math"
)

//青训营寻友之旅
func main() {
	var n int
	var k int
	var t int
	fmt.Scanf("%d %d", &n, &k)
	if n == 0 {
		t++
		n++
	}
	dis := k - n
	if dis <= 0 {
		t = int(math.Abs(float64(dis)))
	} else {
		for n*2 < k {
			t++
			n *= 2
		}
		t = int(math.Min(float64(t+1+(2*n-k)), float64(t+(k-n))))
	}
	fmt.Printf("%d", int(t))
}