【问题标题】:Sample Online Data Algorithm Analysis [closed]在线数据算法分析示例
【发布时间】:2020-06-09 13:50:45
【问题描述】:

我正在阅读一本名为“编程面试要素”的书,但遇到了以下问题:

实现一个算法,该算法将一个不同的数组作为输入 元素和大小,并返回给定大小的子集 数组元素。所有子集的可能性应该相等。返回 结果是输入数组本身。

他们提供的解决方案如下:

import random
def random_sampling(k, A):
    for i in range(k):
        # Generate a random index in [i, len(A) - 1].
        r = random.randint(i, len(A) - 1)
        A[i], A[r] = A[r], A[i]


A = [3, 7, 5, 11]
k = 3

print(random_sampling(k, A))

我不明白作者试图直观地做什么。他们的解释如下

另一种方法是枚举所有大小为 k 的子集,然后选择 从这些中随机一个。由于有 (n 到 k) 个大小为 k 的子集, 时间和空间的复杂性是巨大的。高效的关键 构建一个大小正好为 k 的随机子集是首先构建一个 大小 k - 1 然后再添加一个元素,随机选择 其余的部分。当 k = 1 时,这个问题是微不足道的。我们调用 随机数生成器,取返回值 mod n(称为 r), 并将 A[0] 与 A[r] 交换。条目 A[0] 现在保存结果。

对于 k > 1,我们首先像上面一样随机选择一个元素,然后我们 现在对 n - 1 个元素的子数组 A[1, n -1] 重复相同的过程。 最终,随机子集占据槽 A[0, k - 1] 和 剩余元素在最后 n - k 个槽中。

直观地说,如果所有大小为 k 的子集都是等可能的,那么 构造过程确保大小为 k + 1 的子集也是 同样可能。对此的正式证明使用数学归纳法 - 归纳假设是每个大小 k 的每个排列 A 的子集同样可能在 A[0, k -1] 中。

作为一个具体的例子,让输入是 A = 和大小 是 3. 在第一次迭代中,我们使用随机数生成器 在区间 [0,3] 中选择一个随机整数。让返回的随机 数字是 2。我们用 A[2] 交换 A[0] - 现在数组是 。 现在我们在区间 [1, 3] 中选择一个随机整数。让返回的 随机数为 3。我们将 A[1] 与 A[3] 交换 - 现在是结果数组 是 。现在我们在区间 [2,3] 中选择一个随机整数。 令返回的随机数为 2。当我们将 A[2] 与自身交换时, 结果数组不变。随机子集首先由他组成 三个条目,即 {5, 11, 3}。

抱歉,文字太长了;我的问题是这样的

  1. 他们所指的效率的关键是什么?它没有在我的脑海中点击
  2. “最终,随机子集占据插槽 A[0, k-1] 而其余元素位于最后 n - k 个插槽中”是什么意思
  3. 是否有明确的理由说明“A 的每个大小 k 子集的每个排列都同样可能在 A[0, k - 1] 中”?
  4. 您能否更清楚地解释算法背后的理论?
  5. 算法的返回值应该是多少?

谢谢

【问题讨论】:

  • (这里的问题太多了...)你明白A[i], A[r] = A[r], A[i] 的那一行在做什么吗?对我来说,这个算法似乎很关键。
  • On 5:“return 语句返回一个函数的值。return 没有表达式参数返回 None从函数的末尾落下也返回 @ 987654327@。” (The Official Pyhton Tutorial)。所以这会返回并打印None(顺便说一句,如果你运行它,你也可以看到它)。

标签: python arrays algorithm random data-structures


【解决方案1】:
  1. 一个直观的解决方案可能是
def random_sampling(k, A):
    subset = []
    selected = set()
    for i in range(k):
        index = random.randint(0, len(A) - 1)
        while index in selected:
            index = random.randint(0, len(A) - 1)
        selected.add(index)
        subset.append([A[index]])
    return subset

但不清楚每个 k 子集具有相等的概率(因为对于相同的 k,您可能在不同范围内使用不同数量的随机数)

所以符合概率条件的解决方案将是

import itertools as it
def random_sampling(k, A):
    index_posibilities = [i for i in it.combinations(A,k)] #very expansive action
    index = random.randint(0, len(index_posibilities) - 1)
    selected = []
    for i in index:
        selected.append(A[i])
    return selected

所以他们给出的解决方案确保您对每组 k 个元素使用相同的随机程序,而没有上面的蛮力

  1. 现在列表的顺序是,前k个元素是我们选择的这些,列表的其余部分是剩下的项目

  2. 这是归纳假设,我假设长度为 k-1 的每个集合具有相同的概率,并为长度为 k 的集合证明它。

  3. 确保每个 k 大小子集的概率相同的有效方法是执行完全相同的步骤来生成它

  4. 没有返回值,因为函数中的列表被改变了,main中也改变了,子集是函数被调用后列表的前k个元素

【讨论】:

    猜你喜欢
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 2011-10-29
    • 1970-01-01
    相关资源
    最近更新 更多