修剪和搜索 |复杂性分析概述
“修剪”这个词的意思是通过去除不必要的东西来减少一些东西。因此, Prune-and-Search是解决各种优化问题的优秀算法范式。这种方法首先由Nimrod Megiddo于1983 年提出。这种方法总是由多次迭代组成。在每次迭代中,它丢弃一部分输入数据,例如 f,然后对剩余数据递归调用相同的算法来解决问题。
这种方法的主要思想是通过修剪一部分输入元素并递归剩余的有效输入元素来减少搜索空间。经过一些迭代后,输入数据的大小会变得非常小,以至于可以在常数时间 c' 内通过蛮力方法求解。
此类算法的时间复杂度分析:
让每次迭代所需的时间为O(n^k) 其中-
n = size of input data
k is some constant.
让f = 在每次迭代中删除的数据的分数。递归地,上述方法可以写成——
T(n) = T((1-f)n) + O(n^k)
We have,
T(n) <= T((1-f)n) + c*n^k for very large value of n.
<= T((1-f)^2 * n) + c*n^k +c*((1-f)^k)*n^k
.
.
<= c’ + c*n^k + c*((1-f)^k)n^k + c*((1-f)^2k)n^k + ….. + c*((1-f)^pk)n^k
= c’ + c*n^k(1 + (1-f)^k + (1-f)^2k + ….. + (1-f)^pk).
Since (1-f) < 1, as n tends to very large number
Therefore, T(n) = O(n^k).
表明整个过程的时间复杂度与每次迭代中剪枝搜索的时间复杂度在同一数量级。这种方法可用于分析许多已知问题的算法,如二分搜索、从未排序的数组中找到第 K 个最大/最小元素(选择问题)、1 中心问题(最小封闭圆)、求解两个变量的线性规划、等等。
例子:
1.二分查找:
正如我们所知,这种技术适用于排序的数据列表,用于在给定列表中搜索特定值(比如' val ')的索引。为此,我们转到中间元素并将其与val进行比较。如果中间元素等于val ,那么我们返回这个中间元素。否则,我们会修剪一半的数据,其余元素使用相同的技术。详细实现见this。
时间复杂度分析:
在每一步中,由于它仅将val与中间元素进行比较,因此这一步的复杂度将是O(1) ,假设它是c (任何常数)。并且列表的一半被删除,因此T(n) = T(n/2) + O(1) if n>=2否则T(n) = O(1) = c 。
In simple terms,
T(n) = T(n/2) + c
= T(n/4) + c + c
= T(n/8) + c + c + c
…..
= T(1) + c + … + c + c
= k times c where k will be a constant.
Since half of input is discarded in each iteration, so the value of k will be at most log(n) in worst cases. Therefore, worst case complexity of Binary Search will be
T(n) = O(log(n)).
2.选择问题:
给定一个包含n 个元素的无序列表,任务是从列表中找到第 K 个最小的元素。第一种非常基本的方法是按升序对给定列表进行排序,并直接选择第 K 个索引处的值。因此,排序通常需要O(n*log(n))时间,并且O(1)用于检索第 K 个索引值。因此,这种方法的总体T(n) = O(n*log(n)) 。
第二种方法是使用 QuickSelect 方法,即 Prune-and-Search 技术。这种修剪和搜索选择算法的基本思想是确定一个不包含第 K 个元素的部分,并从下一次迭代中丢弃该部分元素。我们知道,为了拥有一个O(n)算法,我们必须有一种方法能够在每次迭代中在O(n)时间内修剪掉一小部分元素。假设P是列表的一个元素,它可以将给定列表分成两部分,比如S1和S2 ,这样S1包含小于或等于P的所有元素,而S2包含大于P的所有元素。现在我们可以这么说
- 如果|S1| == K ,那么S1[k]将是第 K 个最小的元素。
- 如果|S1| > K ,则第 K 个元素必须存在于S1中。所以丢弃第二部分S2并使用相同的算法在S1上递归。
- 否则,第 K 个元素必须在S2中。因此,丢弃S1并在S2上递归S2中的第 (K-|S1|) 个元素。
这里的关键是如何选择P以便我们总是可以丢弃 S 的一部分,无论我们是修剪S1还是S2 。答案是P应该是列表S的中位数。同样,找到中位数是这个问题的特例,其中K=n/2 。
但是可以使用以下算法通过其他方式更有效地计算中位数:
- 将列表划分为n/5个子列表,每个子列表最多包含 5 个元素。
- 现在我们可以对每个子列表进行排序并在恒定时间内找到它们的中位数。
- 再次递归地找到所有中位数的中位数,直到大小最多变为 5。获得的中位数将是快速选择算法中使用的完美枢轴。[请注意,插入排序将是对大小为 5 的较小子列表进行排序的更好选择.]
为什么只有5个?
将列表拆分为 5 的大小假设最坏情况拆分为 70-30。至少一半的中位数大于中位数的中位数,因此 n/5 块中的一半至少有 3 个元素,这给出了 3n/10 的分割,这意味着在最坏的情况下另一个分区是 7n/10,即 T(n ) = T(n/5) + T(7n/10) + O(n)。因为 (n/5 + 7n/10) < 1,所以在最坏的情况下 T(n) = O(n)。设 P 是中位数的中位数,可以表示为-
|1''1''1''1''1| 1 1 1 1
|2 2 2 2 2| 2 2 2 2
|3__3__3__3_|P|'3''3''3''3|
4 4 4 4 |4 4 4 4 4|
5 5 5 5 |5__5__5__5__5|
如此处所示, S中至少四分之一的元素小于或等于P ,并且S中至少四分之一的元素大于或等于P。因此,如果我们以这种方式选择 P,我们总是可以在每次迭代期间剪掉至少四分之一的元素。因此,将 S 拆分为大小为 5 的子列表将是找到中位数的有效方法。现在我们可以将算法声明为-
Prune-and-Search Algorithm to find Kth smallest element
Input: A set S of n elements and K.
Output: The Kth smallest element in S.
Approach:
Step-1: If |S| <= 5, apply any Brute Force method.
Step-2: Divide S into n/5 sublists each containing at most 5 elements.
Step-3: Sort each sublists(Insertion sort will be better one to apply).
Step-4: Recursively find P as median of medians of each sublists.
Step-5: Partition S into S1 and S2 such that S1 contains all elements less than or equal to P and S2 contains all elements greater than P.
Step-6: Now there can be three cases as
a) if |S1| == K, then S1[k] will be the Kth smallest element.
b) if |S1| > K, then Kth element must be present in S1. So discard the second part s2 and recurse on s1 with same algorithm.
c) Otherwise Kth element must be in S2. So discard S1 and recurse on S2 for (K-|S1|)th element in S2.
有关详细代码和实现,请访问未排序数组中的第 K 个最小/最大元素 |第 3 组(最坏情况线性时间)
复杂性分析:由于每个子列表包含 5 个元素,因此对它们进行排序将花费恒定的时间。因此,步骤 2、3 和 5 可以在 O(n) 时间内完成,而步骤 4 需要 T(n/5) 时间,因为我们使用相同的算法递归地找到 n/5 个中位数的中位数。由于我们在每次迭代中至少修剪 n/4 个元素,因此在最坏的情况下,每次迭代后都会保留 3n/4 个元素。因此,T(n) = T(3n/4) + T(n/5) + O(n)。
Let T(n) = a0 + a1*n + a2*(n^2) + …. where a1 != 0.
we have
T(3n/4) = a0 + (3/4)a1*n + (9/16)a2*(n^2) + ….
T(n/5) = a0 + (1/5)a1*n + (1/25)a2*(n^2) + ….
T((3n/4) + (n/5)) = T(19n/20) = a0 + (19/20)a1*n + (361/400)a2*(n^2) + ….
Thus, T(3n/4) + T(n/5) <= a0 + T(19n/20).
Therefore,
T(n) = T(3n/4) + T(n/5) + O(n)
<= T(19n/20) + cn.
Applying the initially obtained formula for general case to this inequality,
we will get T(n) = O(n).
因此,我们有一个最坏情况的线性时间算法来解决基于修剪和搜索技术的选择问题。同样,我们可以应用这些类型的策略来解决具有两个变量的线性规划和最小封闭圆问题。