O(1) 空间中的计数排序

问题描述

我有以下计数排序,但空间复杂度对我来说太高了,我正在寻找一种方法来在 O(1) 的空间复杂度中做到这一点

df[
  df[,"Category.1"] == df[,"Category.2"] | 
  sapply(1:nrow(df),function(x) {
  df[x,"Value.1"] %in% List[[df[x,"Category.1"]]] &
    df[x,"Value.2"] %in% List[[df[x,"Category.1"]]]
  }),]

#   Category.1 Value.1 Category.2 Value.2
# 1          A     0.2          A     0.0
# 2          A     0.2          B     0.3
# 4          B     0.2          B     0.2

目前,该算法正在分配 O(k) 空间。 假设 MyCountingSort(A,B,k) for i = 0 to k do G[i] = 0 for j = 0 to length[A] do G[A[j]] = G[A[j]] + 1 for i = 1 to k do G[i] = G[i] + G[i-1] for j = length(A) to 1 do B[G[A[j]]] = A[j] G[A[j]] = G[A[j]] - 1 ,如何将算法空间复杂度提高到 O(1)?

解决方法

我在这里假设 A 是您的输入数组,B 是您的输出数组。因此,|A| = |B|。我进一步假设 k 是我们可能遇到的最大数量的值(例如,如果 A 只包含从 1k 或从 0 到 k-1)。如果您在提问时指定此类详细信息会对我们有所帮助,但我猜这或多或少是您要问的。 :)

由于我们有非常方便的附加约束 k <= |A|,我们可以使用给定的数组 AB 作为索引数组的中间存储。本质上,在您的代码中将 B 作为您的 G 并对其执行 1st2nd 循环。然后我们进行累积加法(第三次循环)。

完成此操作后,我们可以将 B 复制回 A。最后,我们用最终的排序数组覆盖 B(代码中的第 4 个循环)。

这样,除了已经给出的输入参数之外,不会分配任何内存。通常,算法的空间复杂度被定义为与算法的输入无关。由于我们只是回收输入数组而不是自己分配任何东西,因此该算法确实具有 O(1) 空间复杂度。

请注意,在一般情况下(其中 k 不一定是 <= |A|),不会这么容易。另外,只是因为输出数组B已经作为输入提供给我们,我们可以利用这个“技巧”将它用于我们内部使用,因此不必分配任何新的内存.