面试谜题:跳跃游戏

发布于 2024-12-29 13:46:15 字数 335 浏览 1 评论 0原文

跳跃游戏: 给定一个数组,从第一个元素开始,通过跳跃到达最后一个元素。跳转长度最多可以是数组中当前位置的值。最佳结果是当您以最少的跳跃次数达到目标时。

找到最佳结果的算法是什么?

示例:给定数组 A = {2,3,1,1,4} 到达末尾(索引列表)的可能方式为

  1. 0,2,3,4 > (跳转 2 到索引 2,然后跳转 1 到索引 3,然后跳转 1 到索引 4)
  2. 0,1,4 (跳转 1 到索引 1,然后跳转 3 到索引 4)

由于第二个解决方案有只有 2 次跳跃最佳结果。

Jump Game:
Given an array, start from the first element and reach the last by jumping. The jump length can be at most the value at the current position in the array. The optimum result is when you reach the goal in minimum number of jumps.

What is an algorithm for finding the optimum result?

An example: given array A = {2,3,1,1,4} the possible ways to reach the end (index list) are

  1. 0,2,3,4 (jump 2 to index 2, then jump 1 to index 3 then 1 to index 4)
  2. 0,1,4 (jump 1 to index 1, then jump 3 to index 4)

Since second solution has only 2 jumps it is the optimum result.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

放赐 2025-01-05 13:46:15

概述

给定数组 a 和当前位置 i 的索引,重复以下操作,直到到达最后一个元素。

考虑 a[i+1]a[a[i] + i] 中的所有候选“跳转元素”。对于索引 e 处的每个此类元素,计算 v = a[e] + e。如果其中一个元素是最后一个元素,则跳转到最后一个元素。否则,跳转到具有最大 v 的元素。

更简单地说,在触手可及的元素中,寻找能让您在下一次跳跃中走得最远的元素。我们知道这个选择 x 是正确的,因为与您可以跳转到的所有其他元素 y 相比,从 y 可到达的元素是从x可到达的元素的子集(向后跳转的元素除外,这显然是不好的选择)。

该算法的运行时间为 O(n),因为每个元素只需考虑一次(可以跳过第二次考虑的元素)。

示例

考虑值 a、索引、i 以及索引和值 v 之和的数组。

i ->  0   1   2   3   4   5   6   7   8   9  10  11  12
a -> [4, 11,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1]
v ->  4  12   3   4   5   6   7   8   9  10  11  12  13

从索引 0 开始并考虑接下来的 4 个元素。找到 v 最大的那个。该元素位于索引 1,因此跳转到 1。现在考虑接下来的 11 个元素。目标触手可及,所以向目标迈进吧。

演示

请参阅此处此处以及代码

Overview

Given your array a and the index of your current position i, repeat the following until you reach the last element.

Consider all candidate "jump-to elements" in a[i+1] to a[a[i] + i]. For each such element at index e, calculate v = a[e] + e. If one of the elements is the last element, jump to the last element. Otherwise, jump to the element with the maximal v.

More simply put, of the elements within reach, look for the one that will get you furthest on the next jump. We know this selection, x, is the right one because compared to every other element y you can jump to, the elements reachable from y are a subset of the elements reachable from x (except for elements from a backward jump, which are obviously bad choices).

This algorithm runs in O(n) because each element need be considered only once (elements that would be considered a second time can be skipped).

Example

Consider the array of values a, indicies, i, and sums of index and value v.

i ->  0   1   2   3   4   5   6   7   8   9  10  11  12
a -> [4, 11,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1]
v ->  4  12   3   4   5   6   7   8   9  10  11  12  13

Start at index 0 and consider the next 4 elements. Find the one with maximal v. That element is at index 1, so jump to 1. Now consider the next 11 elements. The goal is within reach, so jump to the goal.

Demo

See here or here with code.

浮生面具三千个 2025-01-05 13:46:15

动态规划。

假设您有一个数组 B,其中 B[i] 显示到达数组 A 中的索引 i 所需的最小步数。你的答案当然是在 B[n] 中,因为 An 个元素,并且索引从 1 开始。假设 C[i ]=j 表示从索引 j 跳转到索引 i(这是为了恢复后面所走的路径)

因此,算法如下:

set B[i] to infinity for all i
B[1] = 0;                    <-- zero steps to reach B[1]
for i = 1 to n-1             <-- Each step updates possible jumps from A[i]
    for j = 1 to A[i]        <-- Possible jump sizes are 1, 2, ..., A[i]
        if i+j > n           <-- Array boundary check
            break
        if B[i+j] > B[i]+1   <-- If this path to B[i+j] was shorter than previous
            B[i+j] = B[i]+1  <-- Keep the shortest path value
            C[i+j] = i       <-- Keep the path itself

需要跳转的次数为 B[n].需要采取的路径是:

1 -> C[1] -> C[C[1]] -> C[C[C[1]]] -> ... -> n

可以通过简单的循环来恢复。

该算法的时间复杂度为 O(min(k,n)*n) ,空间复杂度为 O(n)。 nA 中的元素数量,k 是数组内的最大值。

请注意,

我保留了这个答案,但奇琴的贪婪算法是正确的并且更有效。

Dynamic programming.

Imagine you have an array B where B[i] shows the minimum number of step needed to reach index i in your array A. Your answer of course is in B[n], given A has n elements and indices start from 1. Assume C[i]=j means the you jumped from index j to index i (this is to recover the path taken later)

So, the algorithm is the following:

set B[i] to infinity for all i
B[1] = 0;                    <-- zero steps to reach B[1]
for i = 1 to n-1             <-- Each step updates possible jumps from A[i]
    for j = 1 to A[i]        <-- Possible jump sizes are 1, 2, ..., A[i]
        if i+j > n           <-- Array boundary check
            break
        if B[i+j] > B[i]+1   <-- If this path to B[i+j] was shorter than previous
            B[i+j] = B[i]+1  <-- Keep the shortest path value
            C[i+j] = i       <-- Keep the path itself

The number of jumps needed is B[n]. The path that needs to be taken is:

1 -> C[1] -> C[C[1]] -> C[C[C[1]]] -> ... -> n

Which can be restored by a simple loop.

The algorithm is of O(min(k,n)*n) time complexity and O(n) space complexity. n is the number of elements in A and k is the maximum value inside the array.

Note

I am keeping this answer, but cheeken's greedy algorithm is correct and more efficient.

坏尐絯 2025-01-05 13:46:15

从数组构造一个有向图。例如: i->j if |ij|<=x[i] (基本上,如果您可以一跳从 i 移动到 j,则 i->j 作为图中的边)。现在,找到从第一个节点到最后一个节点的最短路径。

FWIW,您可以使用 Dijkstra 算法来找到最短路线。复杂度为 O( | E | + | V | log | V | )。自从 |电子| < n^2,这变成了 O(n^2)。

Construct a directed graph from the array. eg: i->j if |i-j|<=x[i] (Basically, if you can move from i to j in one hop have i->j as an edge in the graph). Now, find the shortest path from first node to last.

FWIW, you can use Dijkstra's algorithm so find shortest route. Complexity is O( | E | + | V | log | V | ). Since | E | < n^2, this becomes O(n^2).

自控 2025-01-05 13:46:15

我们可以计算远索引以跳跃最大值,并且在两者之间如果任何索引值大于远索引值,我们将更新远索引值。

简单的 O(n) 时间复杂度解决方案

public boolean canJump(int[] nums) {
    int far = 0;
    for(int i = 0; i<nums.length; i++){
        if(i <= far){
            far = Math.max(far, i+nums[i]);
        }
        else{
            return false;
        }
    }
    return true;
}

We can calculate far index to jump maximum and in between if the any index value is larger than the far, we will update the far index value.

Simple O(n) time complexity solution

public boolean canJump(int[] nums) {
    int far = 0;
    for(int i = 0; i<nums.length; i++){
        if(i <= far){
            far = Math.max(far, i+nums[i]);
        }
        else{
            return false;
        }
    }
    return true;
}
合约呢 2025-01-05 13:46:15

从左(结束)开始......遍历直到数字与索引相同,使用这些数字中的最大值。例如,如果列表是

   list:  2738|4|6927
   index: 0123|4|5678

一旦您从该数字开始重复上述步骤,直到您到达最右边。

273846927
000001234

如果您找不到与索引匹配的内容,请使用索引最远且值大于索引的数字。在本例中为 7。(因为索引很快就会大于数字,所以您可能只计算 9 个索引)

start from left(end)..and traverse till number is same as index, use the maximum of such numbers. example if list is

   list:  2738|4|6927
   index: 0123|4|5678

once youve got this repeat above step from this number till u reach extreme right.

273846927
000001234

in case you dont find nething matching the index, use the digit with the farthest index and value greater than index. in this case 7.( because pretty soon index will be greater than the number, you can probably just count for 9 indices)

情归归情 2025-01-05 13:46:15

基本思想:

通过查找所有可以最后跳转到目标元素的数组元素(所有 i 使得 A[i ] >= 目标 - i)。

将每个这样的 i 视为新目标并找到到达它的路径(递归地)。

选择找到的最小长度路径,附加目标,返回。

python 中的简单示例:

ls1 = [2,3,1,1,4]
ls2 = [4,11,1,1,1,1,1,1,1,1,1,1,1]

# finds the shortest path in ls to the target index tgti
def find_path(ls,tgti):

    # if the target is the first element in the array, return it's index.
    if tgti<= 0:
        return [0]

    # for each 0 <= i < tgti, if it it possible to reach
    # tgti from i (ls[i] <= >= tgti-i) then find the path to i

    sub_paths = [find_path(ls,i) for i in range(tgti-1,-1,-1) if ls[i] >= tgti-i]

    # find the minimum length path in sub_paths

    min_res = sub_paths[0]
    for p in sub_paths:
        if len(p) < len(min_res):
            min_res = p

    # add current target to the chosen path
    min_res.append(tgti)
    return min_res

print  find_path(ls1,len(ls1)-1)
print  find_path(ls2,len(ls2)-1)

>>>[0, 1, 4]
>>>[0, 1, 12]

basic idea:

start building the path from the end to the start by finding all array elements from which it is possible to make the last jump to the target element (all i such that A[i] >= target - i).

treat each such i as the new target and find a path to it (recursively).

choose the minimal length path found, append the target, return.

simple example in python:

ls1 = [2,3,1,1,4]
ls2 = [4,11,1,1,1,1,1,1,1,1,1,1,1]

# finds the shortest path in ls to the target index tgti
def find_path(ls,tgti):

    # if the target is the first element in the array, return it's index.
    if tgti<= 0:
        return [0]

    # for each 0 <= i < tgti, if it it possible to reach
    # tgti from i (ls[i] <= >= tgti-i) then find the path to i

    sub_paths = [find_path(ls,i) for i in range(tgti-1,-1,-1) if ls[i] >= tgti-i]

    # find the minimum length path in sub_paths

    min_res = sub_paths[0]
    for p in sub_paths:
        if len(p) < len(min_res):
            min_res = p

    # add current target to the chosen path
    min_res.append(tgti)
    return min_res

print  find_path(ls1,len(ls1)-1)
print  find_path(ls2,len(ls2)-1)

>>>[0, 1, 4]
>>>[0, 1, 12]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文