通过最大跳跃长度数组的最短路径

时间:2015-10-20 03:40:13

标签: c++ algorithm

我正在调试以下问题并发布代码。想知道代码是否正确。我目前的疑问是,i是否应该总是增加(在这一行 - for (;i <= end; i++))?

  • 给定一个非负整数数组,您最初位于数组的第一个索引处。

  • 数组中的每个元素代表该位置的最大跳跃长度。

  • 您的目标是以最小跳数达到最后一个索引。

  • 例如: 给定数组A = [2,3,1,1,4], 到达最后一个索引的最小跳转次数是2。 (从索引0到1跳1步,然后从最后一个索引跳3步。)

class Solution {
public:
    int jump(vector<int>& nums) {
        int i = 0, n = nums.size(), step = 0, end = 0, maxend = 0;
        while (end < n - 1) {
            step++;
            for (;i <= end; i++) {
                maxend = max(maxend, i + nums[i]);
                if (maxend >= n - 1) return step;
            }
            if(end == maxend) break;
            end = maxend;
        }
        return n == 1 ? 0 : -1;
    }
};

3 个答案:

答案 0 :(得分:3)

动态编程解决方案想法:O(n ^ 2)

假设给定的数组是<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> 。从第i个位置开始,你可以跳A[1..n]。您已经计算了所有j&gt; = i&amp;&amp;的结果J&LT; = N。所以现在

1 or 2 or 3...A[i]

通过这种方式,您可以计算所有内容。

O(n ^ 2)时间复杂度。

修改:O(n)

您也可以在ans[i]=min(ans[i+j],ans[i]) where i+j<=n && j=1,2,...A[i] 中进行计算。从一个位置开始,您将始终移动到具有最高O(n)值的位置。 我的意思是假设你处于i+A[i]位置。接下来,您将移至j位置,以使j最大。 如果其中一个元素是最后一个元素,则跳转到最后一个元素。否则,跳转到具有最大j+A[j]的元素。

O(n)解决方案......

j+A[j]
Jump     2 3 1 1 4
position 1 2 3 4 5
j+A[j]   3 5 4 5 9
         ^ . . . .
         . ^ . . .    
         . . . . ^  ---> so 2 jumps.. :)

答案 1 :(得分:2)

我在这里看到两种解决方法。

递归。

简单但效率低下

您只需要从索引0开始,并且对于每个索引i尝试提前跳转到1到a[i]索引,同时保持最后一个索引的最佳结果。它具有很高的算法复杂度,因此只有在效率真的无关紧要或n非常小时才应该选择。

算法将如下所示:

int best = 2147483647;
vector<int> A;

void Jump(int index, int step)
{
    if (step > best)
    {
        // for positive values, if step > best we won't improve our result
        // avoid worthless calculations
        return; 
    }
    if (index == A.size() - 1)
    {
        if (step < best) best = step;
        return;
    }

    int maxJumps = A[index];
    for (int i = index; i <= min(index + maxJumps, A.size() - 1); i++) 
    {
        Jump(i, step + 1);
    }
}

int main()
{
    // read input
    Jump(0, 0);
}

对于您的情况,递归将采用这种方式:

Start from A[0] (equal to 2)                             step = 0
> A[0+1] with step+1 (equal to 3)                        step = 1
>> A[1+1] with step+1 (equal to 1)                       step = 2
>>> A[2+1] with step+1 (equal to 1)                      step = 3
>>>> A[3+1] with step+1 (equal to 4)                     step = 4
>>>>> End of array. Compare step(4), best (MAXINT)         best = 4
>> A[1+2] with step+1 (equal to 1)                       step = 2
>>>> A[3+1] with step+1 (equal to 4)                      step = 3
>>>>> End of array. Compare step (3), best (4)             best = 3
>> A[1+3] with step+1 (equal to 4)                       step = 2
>>>>> End of array. Compare step(2), best (3)              best = 2
> A[0+2] with step+1 (equal to 1)                        step = 2
>>> A[2+1] with step+1 (equal to 1)                       step = 3
>>>> A[3+1] with step+1 (equal to 4)                      step = 4
>>>>> End of array. Compare step(4), best(2)               best = 2

<强>动态。智能和高效

此方法使用Dynamic programming。让我们得到一个与数组A长度相同的数组B。让B[i]表示&#34; 最小需要多少步才能跳转到A [i ]&#34 ;.如果我们知道B[i],那么我们可以说我们可以跳转到i + 1的所有可能索引(从i + A[i]B[i] + 1)。因此,您只需要从0到N-1遍历数组并向前看,改进每个ii + a[i]的结果。

这样的事情:

vector<int> A, B;
int n;

int main() 
{
    // read n; read A of size n
    B.reserve(n); // B should be the same size and initialized with zeroes (by default)

    B[0] = 0; // not obligatory, 0 by default, just for clearness
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = i + 1; j <= min(i + A[i], n - 1); j++)
        {
            // improve result if we weren't there yet or if we can come to A[j]
            // faster if we go from A[i]
            if (B[j] == 0 || B[i] + 1 < B[j]) 
                B[j] = B[i] + 1;
        }
    }
}

算法将以这种方式工作:

A = 2 3 1 1 4
B = 0 0 0 0 0

i = 0, improve 0+1, 0+2
B = 0 1 1 0 0

i = 1, improve 1+1, 1+2, 1+3
B = 0 1 2 2 2

i = 2, no improvements 
i = 3, no improvements

答案存储在B[n - 1] 我已经实施了working IDEOne demo

答案 2 :(得分:1)

我正在分享算法。现在, BFS 描述如下:

int A[N];         // It contains the initial values
int result[N];    // Initialise all with positive infinty or INT_MAX in C
bool visited[N];  // Initially, all initialise with '0' means none of the index is visited
queue Q;          // create a queue 

index = 1
cost = 0
push index in rear of Q.
result[index] = cost
visited[index] = true

while(Q is not empty) {
    index = pop the value from the front of the Q.
    cost = cost + 1

    for(i in 1 to A[index]) {
        temp_index = index + i;
        if(temp_index <= N   AND  visited[temp_index] == false) {
            push temp_index in rear of Q.
            result[temp_index] = cost
            visited[temp_index] = true
        }
    }
}

// Finally print the value of result[N]
print result[N]

注意:还存在 DP 方法,其时间复杂度 O(n 2