当青训营遇上码上掘金之“寻友之旅”(Go/C++/Python)

109 阅读2分钟

当青训营遇上码上掘金

题目

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

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

思路

这题可以通过宽度优先搜索(BFS)来解决。

如果只考虑步行,因为N, K都不超过10510 ^ 5, 那么最坏的情况也不会超过10510^5

现在考虑公交,因为当N>KN > K时,只能通过步行的方式来到达K,那么显然,当 N>KN > K 时只需要继续搜索步行的情况即可。状态数不会超过10510^5

我们令f[i]f[i]表示从 N 到 i 的最少时间,初始化 f[i]=(iN),f[N]=0f[i] = \infty(i \ne N),f[N] = 0

空间复杂度与时间复杂度都是O(N)O(N)

代码

// 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语言码上掘金代码片段:当青训营遇上码上掘金之“寻友之旅”

如果你有什么不理解,或者文章出现了错误,欢迎在评论区交流。