青训营 X 码上掘金-寻友之旅

48 阅读2分钟

当青训营遇上码上掘金

题目简介

Details

image.png

两个点AB在一条直线的不同地点,点A的坐标记为N,点B的坐标记为K。

现在A开始去寻找B,可以单步移动或者倍增移动

  • 单步移动:从x位置移动到x+1或者x-1位置
  • 倍增移动:从x位置移动到2x位置

注意“倍增移动”的方式不可以向后走。

Regulation

0≤N, K≤100000, N、K都为整数。

Input & Output

  • Input:N 、K
  • Output:小青到小码家所需的最短时间(以分钟为单位)

题解

初步认知

一眼动态规划

动态规划的入门就是斐波那契数列的代码实现。后续围绕动态规划又诞生了一批算法题,解法主要围绕循环和递归两种控制流进行展开,这道题主要通过循环的控制流来实现。

动态规划-入门级问题的核心在于递推公式,有了递推公式一切都好说。

我们来看从NK的走法解析。

前置:在这里仅讨论正常情况,也就是N小于K的情况。

当N=K时,直接return 0,

当N>K时,只能步行回去。

递推公式及解析

image.png

来看这样一种简单的情况。

本题递推公式的基本逻辑:比较步行/坐车的耗时情况

从走出第一步开始

image.png

对于在A左边的点位,A只能选择步行前往。

对于在A右边的点位,A可以进行步行乘车两种方式的比较。此处拿77点位举例。

  • 步行:1
  • 乘车:此处是在模拟递推过程,现在假设并没有掌握 x>77的点位信息情况,也就是说,不能考虑坐车到更远点位然后再步行回来的情况。只能先步行到77/2的位置,然后再向前步行。于是有:先步行到77/2=38(模拟计算机整型除法)点位,再花1分钟坐车,再走1分钟的距离,到达x=77的位置。

因此,我们有了基本的递推情况:

递推公式初步

比较走路/坐车的耗时情况。在这里我们通过一个dp数组来表示距离。

dp[i]  //用来表示从坐标x=N到x=i的距离

当在正常情况下k>n时:

auto a = dp[i-1] + 1;    //步行
auto b = dp[i/2] + 1;    //坐车

dp[i/2]的意思就是步行回到x=i/2的站点,这个位置存放的数据本身就已经代表了步行耗时,+1是坐车耗时

然后进行比较

auto result = a < b? a : b;

递推公式进阶

当然要考虑i为奇数的情况。还是拿刚才的x=77举例。不管怎么坐车到达77,都要要么向前走一步,要么向后走一步,因为坐车的结果是2*x,永远是偶数。

所以有

if (i % 2 != 0){
    auto tmp1 = dp[(i + 1) / 2] + 2;
    auto tmp2 = dp[(i - 1) / 2] + 2;
    auto b = tmp1 < tmp2 ? tmp1 : tmp2;
}

超限情况

当遍历到节点i=k, 我们应该停止遍历吗?

NO,仍然要继续进行向后计算,因为可能有:到达后面的节点再往回走的情况。

比如,起始节点为n,此时i已经遍历到k点了,继续向后遍历计算,然后发现其实可以直接坐车到t点(t > k),然后从t点再步行回k点,如下图所示:

image.png

所以有:

if (i >= K){
        auto beyond = dp[i] - (K - i);
        result = result < beyond ? result : beyond;
}

代码地址

完整代码以及地址:戳我