一、题目描述
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
+
.
.
.
+
2
n
−
1
=
2
n
−
1
S = 1+2+4+...+2^{n-1}=2^n-1
S=1+2+4+...+2n−1=2n−1 ,其中
n
n
n 为 A
的个数。而进行 R
操作时,车的速率直接变为1,且方向反转,在一个 R
操作之后,车可能会经历若干个 A
操作后再进行 R
操作,再经历若干个 A
操作 ……
这里我们可以发现最终的字符串应该是如下组成:AA...ARAA...ARAA...A
,即 一串 A
+ 一个 R
+ 一串 A
+ … 。令
T
T
T 表示最终位置,
S
n
S_n
Sn 表示某一串 A
所行进的长度,又因为 R
操作后速度反向,而初始速度方向是向前的,所以
T
=
S
1
−
S
2
+
S
3
−
S
4
+
.
.
.
T = S_1 - S_2 + S_3 - S_4 + ...
T=S1−S2+S3−S4+...
有了这个之后,我们将每个
S
i
S_i
Si 中 A
的个数记为
n
i
n_i
ni,则
S
i
=
2
n
i
−
1
S_i = 2^{n_i-1}
Si=2ni−1。当然这里 A
串的长度可能为0,则其对应的
S
i
=
2
0
−
1
=
0
S_i = 2^0-1 =0
Si=20−1=0 。
所以我们最终的结果(字符串长度)为
r
e
s
=
n
1
+
1
+
n
2
+
1
+
n
3
+
.
.
.
res = n_1 + 1 + n_2 + 1 + n_3 + ...
res=n1+1+n2+1+n3+...
这里的加数
1
1
1 表示一个 R
操作的出现。
那么就有对应关系: r e s = F ( T ) res = F(T) res=F(T) , F ( ) F() F() 为一个函数,可以看作具体实现时的代码的函数。接下来我们就能得到递推式,分三种情况讨论:
-
当 T < S 1 T < S_1 T<S1 时,由上式有 S 1 − T = S 2 − S 3 + S 4 − S 5 + . . . S_1 - T = S_2-S_3+S_4-S_5+ ... S1−T=S2−S3+S4−S5+... ,则等式右边是一个规模变小的 T ′ T' T′ ,且 F ( T ′ ) = n 2 + 1 + n 3 + 1 + n 4 + . . . F(T') = n_2+1+n_3+1+n_4+ ... F(T′)=n2+1+n3+1+n4+... ,故
F ( T ) = F ( T ′ ) + n 1 + 1 F(T) = F(T') + n_1 + 1 F(T)=F(T′)+n1+1 -
当 T > S 1 T > S_1 T>S1 时,由上式有 T − S 1 + S 2 = S 3 − S 4 + S 5 − S 6 + . . . 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 ′ ′ ) = n 3 + 1 + n 4 + 1 + n 5 + . . . F(T'')=n_3+1+n_4+1+n_5+... F(T′′)=n3+1+n4+1+n5+... ,故
F ( T ) = F ( T ′ ′ ) + n 1 + 1 + n 2 + 1 F(T) = F(T'') + n_1 + 1 + n_2 + 1 F(T)=F(T′′)+n1+1+n2+1 -
当 T = S 1 T = S_1 T=S1 时, F ( T ) = n 1 F(T) = n_1 F(T)=n1 。
剩下的就是选择 S 1 S_1 S1 的问题了。若 T = S 1 T = S_1 T=S1 ,则可直接得出。另外两种情况下,显然第一步应该走尽可能远,即选择一个离 T T T 最近的 S 1 S_1 S1 ,所以
- 当 T < S 1 T < S_1 T<S1 时, S 1 = 2 ⌊ l o g 2 T ⌋ + 1 S_1 = 2^{\lfloor log_2T \rfloor +1} S1=2⌊log2T⌋+1
- 当 T > S 1 T > S_1 T>S1 时, S 1 = 2 ⌊ l o g 2 T ⌋ S_1 = 2^{\lfloor log_2T \rfloor} S1=2⌊log2T⌋
而当 T > S 1 T > S_1 T>S1 时,我们还需要选择 S 2 S_2 S2 ,这里的 S 2 S_2 S2 为倒退的距离,不容易判断,所以我们令 n 2 = 0 , 1 , 2 , . . . , ⌊ l o g 2 T ⌋ − 1 n_2 = 0, 1, 2, ..., \lfloor log_2T \rfloor -1 n2=0,1,2,...,⌊log2T⌋−1 ,每一个 n 2 n_2 n2 都计算一遍 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];
}
};