【问题标题】:Reaching the end of an array with a sequence of odd/even jumps通过一系列奇数/偶数跳转到达数组的末尾
【发布时间】:2020-07-29 05:58:20
【问题描述】:

我试图理解一个似乎使用动态编程的编程难题的 Python 解决方案。我能够遵循大多数解决方案,但我正在努力真正正式化解决方案。

问题表述如下:

给你一个整数数组A。从一些起始索引,您可以 进行一系列跳跃。 (1st, 3rd, 5th, ...) 系列中的跳跃 被称为“奇数”编号的跳跃,并且 (2nd, 4th, 6th, ...) 跳跃 该系列被称为偶数跳跃。

您可以通过以下方式从索引i向前跳转到索引j(使用i < j):

  • 奇数 编号的跳转(即跳转 1、3、5,...)期间,您跳转到索引 j 这样 A[i] <= A[j]A[j] 是可能的最小值。如果有 是多个这样的索引j,你只能跳转到最小的这样 索引 j。

  • 偶数 编号的跳跃(即,跳跃 2、4、6,...)期间,您会跳跃 到索引j 这样A[i] >= A[j]A[j] 是可能的最大 价值。如果有多个这样的索引j,只能跳转到 最小这样的索引j

  • 对于某些索引i 可能是不合法跳转。

一个起始索引是好的,如果从该索引开始,您可以通过跳跃若干次(可能是 0 次或多次)到达数组的末尾。

我们要求您返回良好起始指数的数量。

下面我展示了一些作者发表的解决这个问题的 Python 解决方案。我了解它是如何构建oddnextevennext 以及这些数组在技术上持有什么(从该索引以奇数或偶数跳转的索引位置)。我不明白的是最后一个循环是如何工作的,以及它背后的精确动态规划公式是什么。

def odd_even_jumps(self, A):
    N = len(A)

    def make(B):
        ans = [None] * N
        stack = []  # invariant: stack is decreasing
        for i in B:
            while stack and i > stack[-1]:
                ans[stack.pop()] = i
            stack.append(i)
        return ans

    B = sorted(range(N), key = lambda i: A[i])
    oddnext = make(B)
    B.sort(key = lambda i: -A[i])
    evennext = make(B)

    odd = [False] * N
    even = [False] * N
    odd[N-1] = even[N-1] = True

    # Why does this loop start from the end? 

    for i in range(N-2, -1, -1):
        if oddnext[i] is not None:
            odd[i] = even[oddnext[i]]
        if evennext[i] is not None:
            even[i] = odd[evennext[i]]

    return sum(odd)

【问题讨论】:

  • 你在跟踪程序时学到了什么?当您使用各种测试阵列打印 oddeven 时,您得到了什么?我没有在这个问题中看到这些努力。
  • 谢谢@Prune 我刚刚更新了 OP 以澄清这一点,并发布了我自己对这个问题的回答。我试图让它对其他可能想了解这个问题如何接受动态编程解决方案以及如何形式化它的人尽可能有用。

标签: python arrays algorithm dynamic-programming


【解决方案1】:

算法的第一部分identifies 用于输入数组的任何给定索引,奇数(oddNext)或偶数(evenNext)跳转到哪里。某些索引填充有None,因为您不能从它们进行任何合法(偶数或奇数)跳转。

获得此信息后,若要回答您的问题,请注意以下事项:

  • 任何可以合法跳转到好的索引的索引必须是好的索引(您可以“重复使用”解决方案以使该好的索引到达末尾)
  • 输入数组的最后一个索引始终是“好索引”(即您已经到了末尾)

因此,您可以从数组的末尾向后继续,通过检查它们是否会跳转到向前来识别好的索引您已经确定为好(或不好)索引的索引。

请注意,这是一个动态规划计算,因为您正在建立良好索引之间的循环关系并在数组中倒退时利用它(即您正在解决动态规划子问题根据它们的依赖结构,称为“自下而上”的方式)。

需要注意的一点是,该算法会针对每个位置和每个可能的跳转类型计算索引是否良好(即我们完全填充@987654325 @ 和 even 数组)。这是因为,当您在动态规划计算中进行迭代时,数组的不同起点可能需要从该索引进行奇数或偶数跳跃,即使,当 从任何特定索引开始,您只能根据问题陈述通过 odd 跳转来执行此操作。

没关系。在动态编程中,即使原始问题的解决方案并不依赖于所有子问题,也经常解决所有子问题。请注意,这也是为什么最终您只关心odd 数组中的哪些索引是好的索引。 even 数组只是填充odd 数组的动态编程脚手架的一部分。

【讨论】:

    【解决方案2】:

    您检查此索引是否有奇数跳转的每次迭代 如果确实如此 它检查跳转目的地 如果你在目的地的哪里并且有一个均匀的跳跃 你能走到尽头吗 如果是这样的话 这个奇数的索引值应该是真的

    然后你检查相同的偶数 (我有偶数跳跃吗?它的目标是奇数为真的索引?,将偶数值设置为真)

    然后您返回奇数真实值的数量,因为您的第一次跳转是奇数

    【讨论】:

    • 感谢@trigonom - 我对这个问题提供了我自己的答案,希望具有教育意义。
    猜你喜欢
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 2015-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    相关资源
    最近更新 更多