LeetCode 818. Race Car

一、题目描述

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.

 


 

二、题目分析

  根据题意,有一辆车,其根据一个由 AR 组成的字符串来加速、前进和倒退。我们要考虑这样一个字符串,其最终使车来到题目所给的 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+...+2n1=2n1 ,其中 n n nA 的个数。而进行 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=S1S2+S3S4+...
  有了这个之后,我们将每个 S i S_i SiA 的个数记为 n i n_i ni,则 S i = 2 n i − 1 S_i = 2^{n_i-1} Si=2ni1。当然这里 A 串的长度可能为0,则其对应的 S i = 2 0 − 1 = 0 S_i = 2^0-1 =0 Si=201=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() 为一个函数,可以看作具体实现时的代码的函数。接下来我们就能得到递推式,分三种情况讨论:

  1. T &lt; S 1 T &lt; 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+ ... S1T=S2S3+S4S5+... ,则等式右边是一个规模变小的 T ′ T&#x27; T ,且 F ( T ′ ) = n 2 + 1 + n 3 + 1 + n 4 + . . . F(T&#x27;) = 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&#x27;) + n_1 + 1 F(T)=F(T)+n1+1

  2. T &gt; S 1 T &gt; 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+ ... TS1+S2=S3S4+S5S6+... ,则等式右边是一个规模变小的 T ′ ′ T&#x27;&#x27; T ,且 F ( T ′ ′ ) = n 3 + 1 + n 4 + 1 + n 5 + . . . F(T&#x27;&#x27;)=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&#x27;&#x27;) + n_1 + 1 + n_2 + 1 F(T)=F(T)+n1+1+n2+1

  3. 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 ,所以

  1. T &lt; S 1 T &lt; S_1 T<S1 时, S 1 = 2 ⌊ l o g 2 T ⌋ + 1 S_1 = 2^{\lfloor log_2T \rfloor +1} S1=2log2T+1
  2. T &gt; S 1 T &gt; S_1 T>S1 时, S 1 = 2 ⌊ l o g 2 T ⌋ S_1 = 2^{\lfloor log_2T \rfloor} S1=2log2T

  而当 T &gt; S 1 T &gt; 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,...,log2T1 ,每一个 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];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值