当青训营遇上码上掘金
题目
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
思路
这题可以通过宽度优先搜索(BFS)来解决。
如果只考虑步行,因为N, K都不超过, 那么最坏的情况也不会超过。
现在考虑公交,因为当时,只能通过步行的方式来到达K,那么显然,当 时只需要继续搜索步行的情况即可。状态数不会超过。
我们令表示从 N 到 i 的最少时间,初始化
空间复杂度与时间复杂度都是
代码
// go codes
func minTime(N, K int) int {
const INF int = 1e9
dis := make([]int, 200005)
for i := range dis {
dis[i] = INF
}
dis[N] = 0
q := []int{N}
for len(q) > 0 {
x := q[0]
q = q[1:]
if x > K {
// 当 x > K 时只能-1操作,可以直接剪枝
if dis[K] > dis[x] + x - K {
dis[K] = dis[x] + x - K
}
} else {
// 分别搜索-1, +1, *2, 操作
if x > 0 {
if dis[x - 1] > dis[x] + 1 {
dis[x - 1] = dis[x] + 1
q = append(q, x - 1)
}
}
if dis[x + 1] > dis[x] + 1 {
dis[x + 1] = dis[x] + 1
q = append(q, x + 1)
}
if x > 1 && dis[x * 2] > dis[x] + 1 {
dis[x * 2] = dis[x] + 1
q = append(q, x * 2)
}
}
}
return dis[K]
}
// cpp code
int minTime(int N, int K) {
std::vector<int> dis(200005, 1e9);
dis[N] = 0;
std::queue<int>q;
q.push(N);
while(!q.empty()) {
int x = q.front();
q.pop();
if(x > K) dis[K] = std::min(dis[K], dis[x] + x - K);
else {
if(x > 0) {
if(dis[x - 1] > dis[x] + 1) {
dis[x - 1] = dis[x] + 1;
q.push(x - 1);
}
}
if(dis[x + 1] > dis[x] + 1) {
dis[x + 1] = dis[x] + 1;
q.push(x + 1);
}
if(x > 1 && dis[x * 2] > dis[x] + 1) {
dis[x * 2] = dis[x] + 1;
q.push(x * 2);
}
}
}
return dis[K];
}
# python codes
def minTime(N, K) -> int :
dis = [int(1e9)] * 200005
dis[N] = 0
q = [N]
while(q):
tmp = q
q = []
for x in tmp:
if x > K :
if dis[K] > dis[x] + x - K :
dis[K] = dis[x] + x - K
else :
if x > 0 :
if dis[x - 1] > dis[x] + 1 :
dis[x - 1] = dis[x] + 1
q.append(x - 1)
if dis[x + 1] > dis[x] + 1 :
dis[x + 1] = dis[x] + 1
q.append(x + 1)
if x > 1 and dis[x * 2] > dis[x] + 1 :
dis[x * 2] = dis[x] + 1
q.append(x * 2)
return dis[K]
结尾
这里放出Go语言码上掘金代码片段:当青训营遇上码上掘金之“寻友之旅”
如果你有什么不理解,或者文章出现了错误,欢迎在评论区交流。