以下算法返回数组的上一个较大元素。它来自these笔记的第11页。
// Input: An array of numeric values a[1..n]
// Returns: An array p[1..n] where p[i] contains the index of the previous
// larger element to a[i], or 0 if no such element exists.
previousLarger(a[1..n])
for (i = 1 to n)
j = i-1;
while (j > 0 and a[j] <= a[i]) j--;
p[i] = j;
return p
我的作业问题是:鉴于输入序列{a1,...,an}
是集合{1,...,n}
的随机排列,预计运行时间是多少?
我认为这需要某种概率分析,但我需要一些提示,因为我过去只进行过最坏情况分析。我正在尝试找到给定i的j-loop
成本的公式(1 +我们操作的次数j--
),然后将该公式从1加到n。
“预期”是什么意思?我真的不知道如何解释这个。
答案 0 :(得分:1)
以@Heuster的答案为基础:
1)你知道答案是在O(n)和O(n ^ 2)之间。这只是为了检查最终结果。
2)元素i
的预期步数确实是:
sum_{k=1}^i 1 / (k+1)
= O(log i)
3)你必须将所有这些数字加在i上。这给你:
sum_{i=1}^n O(log i)
= O(n log n)
我所做的并不严谨,但你可以证明它是衍生出来的。 O(n log n)介于O(n)和O(n ^ 2)之间,因此它似乎是一个很好的候选者:)
答案 1 :(得分:0)
对于和任意索引i
,a[i-1] > a[i]
(换句话说,内部while循环将采取一步)的可能性是多少?这很容易:a
中的所有元素都不同,所以P(a[i-1] > a[i]) = P(a[i] > a[i-1]) = 1/2
。
现在,看一下内部while循环需要采取两个步骤的情况。也就是a[i-2] > a[i] > a[i-1]
。这正是3个元素的6个排列中的一个,因此机会为1 / 3! = 1 / 6
。
让我们概括一下,并假设内部while循环需要采取k
步。我们考虑子列表a[i-k], a[i-k+1], ..., a[i]
。我们知道a[i-k]
是此子列表的最大元素,a[i]
是第二大(否则,内循环会更快停止)。中间元素的顺序是无关紧要的。因此,我们采取k
步骤的可能性为1 / (k + 1) * 1 / k = 1 / (k * (k + 1))
。请注意,1/2
的{{1}}和k = 1
1/6
的确为k = 2
。
a[i]
之前没有任何元素增加的可能性只是1 / i
(a[i]
是该子列表中的最大元素)。在这种情况下,内循环需要i
步。
元素i
的预期步数是(概率乘以值的总和):
Sum[{k, 1, i} k * 1 / ((k * (k + 1))] + i / i
= Sum[{k, 1, i} 1 / (k + 1)] + 1
= H_{i+1}
其中H_{i}
是第i个谐波数,它是log i
的离散变量。也就是说,元素i
的步数为Θ(i)
。
现在剩下的是对所有i
求和以找到预期的运行时间。如果使用精确值(H_{i+1}
),则无法获得良好的表达式,请参阅Wolfram Alpha。
然而,标准的继续方法是继续使用近似的log i
。显然,log 0 + log 1 + ... + log n-1
小于n log n
。现在,考虑总和的后半部分:
log n/2 + log n/2+1 + ... + log n-1 > n/2 log n/2
= n/2 (log n - log 2)
= Ω(n log n)
因此,预计的运行时间为Θ(n log n)
。