当青训营遇上码上掘金
题目简介
Details
两个点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:小青到小码家所需的最短时间(以分钟为单位)
题解
初步认知
一眼动态规划
动态规划的入门就是斐波那契数列的代码实现。后续围绕动态规划又诞生了一批算法题,解法主要围绕循环和递归两种控制流进行展开,这道题主要通过循环的控制流来实现。
动态规划-入门级问题的核心在于递推公式,有了递推公式一切都好说。
我们来看从N到K的走法解析。
前置:在这里仅讨论正常情况,也就是N小于K的情况。
当N=K时,直接return 0,
当N>K时,只能步行回去。
递推公式及解析
来看这样一种简单的情况。
本题递推公式的基本逻辑:比较步行/坐车的耗时情况
从走出第一步开始
对于在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
点,如下图所示:
所以有:
if (i >= K){
auto beyond = dp[i] - (K - i);
result = result < beyond ? result : beyond;
}
代码地址
完整代码以及地址:戳我