一、题目描述
Your car starts at position 0 and speed +1 on an infinite number line. (Your car can go into negative positions.)
Your car drives automatically according to a sequence of instructions A (accelerate) and R (reverse).
When you get an instruction “A”, your car does the following: position += speed, speed *= 2.
When you get an instruction “R”, your car does the following: if your speed is positive then speed = -1
, otherwise speed = 1
. (Your position stays the same.)
For example, after commands “AAR”, your car goes to positions 0->1->3->3, and your speed goes to 1->2->4->-1.
Now for some target position, say the length of the shortest sequence of instructions to get there.
Example 1:
Input:
target = 3
Output: 2
Explanation:
The shortest instruction sequence is “AA”.
Your position goes from 0->1->3.
Example 2:
Input:
target = 6
Output: 5
Explanation:
The shortest instruction sequence is “AAARA”.
Your position goes from 0->1->3->7->7->6.
Note:
1 <= target <= 10000
.
二、题目分析
根据题意,有一辆车,其根据一个由 A
和 R
组成的字符串来加速、前进和倒退。我们要考虑这样一个字符串,其最终使车来到题目所给的 target
,即车的位置最终为 target
,最终返回该字符串的长度。
首先能够看到,当车的速度为1,并不断地进行 A
操作时,它的最终位置应为 S=1+2+4+...+2n−1=2n−1S = 1+2+4+...+2^{n-1}=2^n-1S=1+2+4+...+2n−1=2n−1 ,其中 nnn 为 A
的个数。而进行 R
操作时,车的速率直接变为1,且方向反转,在一个 R
操作之后,车可能会经历若干个 A
操作后再进行 R
操作,再经历若干个 A
操作 ……
这里我们可以发现最终的字符串应该是如下组成:AA...ARAA...ARAA...A
,即 一串 A
+ 一个 R
+ 一串 A
+ … 。令 TTT 表示最终位置,SnS_nSn 表示某一串 A
所行进的长度,又因为 R
操作后速度反向,而初始速度方向是向前的,所以
T=S1−S2+S3−S4+...
T = S_1 - S_2 + S_3 - S_4 + ...
T=S1−S2+S3−S4+...
有了这个之后,我们将每个 SiS_iSi 中 A
的个数记为 nin_ini,则 Si=2ni−1S_i = 2^{n_i-1}Si=2ni−1。当然这里 A
串的长度可能为0,则其对应的 Si=20−1=0S_i = 2^0-1 =0Si=20−1=0 。
所以我们最终的结果(字符串长度)为
res=n1+1+n2+1+n3+...
res = n_1 + 1 + n_2 + 1 + n_3 + ...
res=n1+1+n2+1+n3+...
这里的加数 111 表示一个 R
操作的出现。
那么就有对应关系:res=F(T)res = F(T)res=F(T) ,F()F()F() 为一个函数,可以看作具体实现时的代码的函数。接下来我们就能得到递推式,分三种情况讨论:
-
当 T<S1T < S_1T<S1 时,由上式有 S1−T=S2−S3+S4−S5+...S_1 - T = S_2-S_3+S_4-S_5+ ...S1−T=S2−S3+S4−S5+... ,则等式右边是一个规模变小的 T′T'T′ ,且 F(T′)=n2+1+n3+1+n4+...F(T') = n_2+1+n_3+1+n_4+ ...F(T′)=n2+1+n3+1+n4+... ,故
F(T)=F(T′)+n1+1 F(T) = F(T') + n_1 + 1 F(T)=F(T′)+n1+1 -
当 T>S1T > S_1T>S1 时,由上式有 T−S1+S2=S3−S4+S5−S6+...T-S_1+S_2 =S_3-S_4+S_5-S_6+ ...T−S1+S2=S3−S4+S5−S6+... ,则等式右边是一个规模变小的 T′′T''T′′ ,且 F(T′′)=n3+1+n4+1+n5+...F(T'')=n_3+1+n_4+1+n_5+...F(T′′)=n3+1+n4+1+n5+... ,故
F(T)=F(T′′)+n1+1+n2+1 F(T) = F(T'') + n_1 + 1 + n_2 + 1 F(T)=F(T′′)+n1+1+n2+1 -
当 T=S1T = S_1T=S1 时,F(T)=n1F(T) = n_1F(T)=n1 。
剩下的就是选择 S1S_1S1 的问题了。若 T=S1T = S_1T=S1 ,则可直接得出。另外两种情况下,显然第一步应该走尽可能远,即选择一个离 TTT 最近的 S1S_1S1 ,所以
- 当 T<S1T < S_1T<S1 时,S1=2⌊log2T⌋+1S_1 = 2^{\lfloor log_2T \rfloor +1}S1=2⌊log2T⌋+1
- 当 T>S1T > S_1T>S1 时,S1=2⌊log2T⌋S_1 = 2^{\lfloor log_2T \rfloor}S1=2⌊log2T⌋
而当 T>S1T > S_1T>S1 时,我们还需要选择 S2S_2S2 ,这里的 S2S_2S2 为倒退的距离,不容易判断,所以我们令 n2=0,1,2,...,⌊log2T⌋−1n_2 = 0, 1, 2, ..., \lfloor log_2T \rfloor -1n2=0,1,2,...,⌊log2T⌋−1 ,每一个 n2n_2n2 都计算一遍 F(T)F(T)F(T) ,取最小值。最后再取这两种情况的最小值。
三、具体实现
根据上面讨论,由递归方式实现。
class Solution
{
public:
int res[100001];
int racecar( int target )
{
if ( res[target] != 0 )
return res[target];
int n = log2( target + 1 );
if ( pow( 2, n ) - 1 == target ) {
res[target] = n;
return res[target];
}
int s1 = pow( 2, n + 1 ) - 1,
s2 = pow( 2, n ) - 1;
res[target] = racecar( s1 - target ) + ( n + 1 ) + 1;
for ( int i = 0; i < n; ++i ) {
int s3 = pow( 2, i ) - 1;
res[target] = min( res[target], racecar( target - s2 + s3 ) + n + i + 2 );
}
return res[target];
}
};