在最近的一次考试中,我们获得了一个函数,用于计算未排序的ArrayList中出现的双精度数(不是原始double
,但项目出现两次的次数)。
我正确地确定Big O复杂度为O(N ^ 2),但只是部分信用,因为我错误地确定了完整的复杂性。功能如下:
public static <T> int countDoubles(ArrayList<T> list, int index, Comparator<? super T> cmp) {
if (index >= list.size())
return 0;
int count = 0;
for (int i = index + 1; i < list.size(); i++) {
if (cmp.compare(list.get(index), list.get(i)) == 0)
count++;
}
return count + countDoubles(list, index + 1, cmp);
}
在他刚刚发布的考试解决方案中,他给出了这样的解释:
输入集合中有N个项目,该方法会自行调用 一遍又一遍地使用减少步骤,产生新的索引N次 直到它到达基本情况(收集的结尾)。对于每一个 递归框架有一个for循环,可以在一个较少的元素上工作 每一帧中的集合反复出现,直到它结束 集合。所以有N个递归调用和N -1步骤 第一次打电话,N-2为第二次,N-3为第三次,依此类推 到达数组的末尾。这种行为有二次增长 上限复杂度的术语,因为它将呈现以下内容 表达式:
T(N)=(N-1)+(N-2)+(N-3)+ ... + 1 = N(N-1)/ 2 =((N ^ 2)/ 2) - (N / 2) = O(N ^ 2)
为了正确理解这一点,我尝试绘制一个大小为10的简单数组,每次将其检查的大小减少一个。
[] [] [] [] [] [] [] [] [] []
[] [] [] [] [] [] [] [] []
[] [] [] [] [] [] [] []
[] [] [] [] [] [] []
[] [] [] [] [] []
[] [] [] [] []
[] [] [] []
[] [] []
[] []
[]
计算递归级别有意义N
。计算每个元素得出9 + 8 ... = 45考虑到100(N级递归* N个元素)是100,我不明白N/2
来自哪里,更不用说((N^2)/2) - (N/2)
了。
任何解释都非常感谢,因为我一直在寻找过去的一个月,似乎无法完全掌握我所缺少的东西。谢谢。
答案 0 :(得分:2)
1
到M
的整数之和为((M+1) * M) / 2
。这只是一个数学事实(通常通过归纳证明)。如果你不相信,试试一些例子。
算法的第一次传递执行N-1
compare
s,每个递归级别少一compare
,直到最后一级递归为1 compare
。因此,比较的总数(对于所有递归级别)是从1
到N-1
的整数之和。在公式中用N-1
代替M
会将比较的总数作为(N * (N-1)) / 2
。
从那里,它只是代数
(N * (N-1)) / 2 = (N * N - N) / 2 = ((N^2) / 2) - (N / 2)
将其分解的原因是因为big-O只关心具有最大指数的N
。当然,big-O也不关心常量。所以你扔掉了(N / 2)
并忽略了/ 2
,答案是O( N ^ 2 ),这是最大的一个......'
好吧,别担心我对此事的看法,就是这样。