*# 当青训营遇上码上掘金*
题目:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
思路:
动态规划问题
小青和小码在一条直线上,小青如果步行去小码家,那肯定时间非常长,题目问最快到达时间是多少,那么肯定要添加公交的方式,但是如何去判断在哪坐公交,那一段是步行呢,找到最优问题。
首先维护一个dis[1000000]数组,此为N到达每一个点的最短时间,(相当于一个动态规划数组)然后最初的位置dis[N]=0,其他的位置设置为∞。
找到动态规划的问题状态之间的关系,首先如果到达当前位置x的时间为dis[x],则分为三种情况,步行+1到达,步行-1到达和公交*2到达,则问题可以转化成关系式
如果当前位置x的时间比前一个位置x-1大的话则加1步,dis[x]=dis[x-1]+1,如果当前位置x比后一个位置x+1大的话则减一步,dis[x]=dis[x+1]+1,如果当前位置x*2比步行大的话,则dis[x*2]=dis[x]+1
如何记录当前小青走到什么位置了呢,需要进行什么操作呢,用到了队列queue,(相当于bfs广度优先遍历)使用队列开始从第一个位置N开始行走,当每次都记录三种状态的最短时间,记录每次走的一步的位置,到dis[k]为最小的时间位置。
代码实现:
public static int mintime(int N,int K) {
int INF = 100000000;//定义无穷大
int[] dis = new int[200000];//定义最小值数组
//初始化最小距离数组
for (int i = 0; i < dis.length; i++) {
dis[i] = INF;
}
dis[N] = 0;
//初始化队列
Queue<Integer> queue = new LinkedList<Integer>();
queue.add(N);
while (!queue.isEmpty()) {
int x = queue.poll();
if (x > K) {
if (dis[K] > dis[x] + x - K) {
dis[K] = dis[x] + x - K;
}
} else {
if (dis[x + 1] > dis[x] + 1) {
dis[x + 1] = dis[x] + 1;
queue.add(x + 1);
}
if (x > 0) {
if (dis[x - 1] > dis[x] + 1) {
dis[x - 1] = dis[x] + 1;
queue.add(x - 1);
}
if (x > 1 && dis[x * 2] > dis[x] + 1) {
dis[x * 2] = dis[x] + 1;
queue.add(x * 2);
}
}
}
}
retuen dis[K];
}
}
[具体的代码实现请看](java实现小青找小码 - 码上掘金 (juejin.cn))