你的赛车起始停留在位置 0,速度为 +1,正行驶在一个无限长的数轴上。(车也可以向负数方向行驶。)
你的车会根据一系列由 A(加速)和 R(倒车)组成的指令进行自动驾驶 。
当车得到指令 "A" 时, 将会做出以下操作: position += speed, speed *= 2。
当车得到指令 "R" 时, 将会做出以下操作:如果当前速度是正数,则将车速调整为 speed = -1 ;否则将车速调整为 speed = 1。 (当前所处位置不变。)
例如,当得到一系列指令 "AAR" 后, 你的车将会走过位置 0->1->3->3,并且速度变化为 1->2->4->-1。
现在给定一个目标位置,请给出能够到达目标位置的最短指令列表的长度。
示例 1:
输入:
target = 3
输出: 2
解释:
最短指令列表为 "AA"
位置变化为 0->1->3
示例 2:
输入:
target = 6
输出: 5
解释:
最短指令列表为 "AAARA"
位置变化为 0->1->3->7->7->6
说明:
1 <= target(目标位置) <= 10000。
官方题解中的方法二和我的方法类似,这里放出另一种方法(最短路)的代码。
class Solution {
class node{
int step,target;
public node(int step,int target) {
this.step=step;
this.target=target;
}
}
public int racecar(int target) {
int K=33-Integer.numberOfLeadingZeros(target-1);
int barrier=1<<K;
int[] dis=new int[2*barrier+1];
Arrays.fill(dis, Integer.MAX_VALUE);
dis[target]=0;
PriorityQueue<node> q=new PriorityQueue<node>((a,b)->a.step-b.step);
q.add(new node(0,target));
while(!q.isEmpty()) {
node now=q.poll();
int steps=now.step;
int tar1=now.target;
if(dis[Math.floorMod(tar1, dis.length)]>steps)
continue;
for(int k=0;k<=K;k++) {
int walk=(1<<k)-1;
int tar2=walk-tar1;
int steps2=steps+k+(tar2!=0?1:0);
if(Math.abs(tar2)<=barrier && steps2<dis[Math.floorMod(tar2, dis.length)]) {
q.add(new node(steps2,tar2));
dis[Math.floorMod(tar2, dis.length)]=steps2;
}
}
}
return dis[0];
}
}
方法二:动态规划
class Solution {
public int racecar(int target) {
int[] dp=new int[target+3];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0]=0; dp[1]=1; dp[2]=4;
for(int t=3;t<=target;t++) {
//从最高位不为0的位算起,二进制表示的位数
int k=32-Integer.numberOfLeadingZeros(t);
if(t==(1<<k)-1) {
dp[t]=k;
continue;
}
for(int j=0;j<k-1;j++)
dp[t]=Math.min(dp[t], dp[t-(1<<(k-1))+(1<<j)]+k-1+j+2);
if((1<<k)-1-t<t)
dp[t]=Math.min(dp[t], dp[(1<<k)-1-t]+k+1);
}
return dp[target];
}
}