Algorithm 对和算法-二进制搜索的性能
我正在用Scala实现一个算法,用于从单独的数组l1和l2中查找值x1和x2,这样x1+x2=t,其中t是一些目标值 算法1逐个迭代l1和l2,并检查x1+x2=t。在O(n^2)中运行。 算法2对l2进行排序,然后对l1中的每个项目执行二进制搜索。假定在O(nlogn)中运行,但不运行。为什么它比算法1运行得慢 请注意,这是一个课程作业,我只是在寻找线索 算法1:Algorithm 对和算法-二进制搜索的性能,algorithm,scala,performance,sum,Algorithm,Scala,Performance,Sum,我正在用Scala实现一个算法,用于从单独的数组l1和l2中查找值x1和x2,这样x1+x2=t,其中t是一些目标值 算法1逐个迭代l1和l2,并检查x1+x2=t。在O(n^2)中运行。 算法2对l2进行排序,然后对l1中的每个项目执行二进制搜索。假定在O(nlogn)中运行,但不运行。为什么它比算法1运行得慢 请注意,这是一个课程作业,我只是在寻找线索 算法1: def hasPairSlow(l1: List[Int], l2: List[Int], target: Int): Optio
def hasPairSlow(l1: List[Int], l2: List[Int], target: Int): Option[Pair[Int, Int]] = {
l1 foreach { i =>
l2 foreach { j => if (i+j == target) return Some(i -> j) }
}
None
}
算法2:
def hasPair(l1: List[Int], l2: List[Int], target: Int): Option[Pair[Int, Int]] = {
val s2 = l2.sorted
l1 foreach { i =>
val p = checkPair(i, s2, target)
if (p.isDefined) return Some(i, p.get)
}
None
}
private def checkPair(x: Int, l: List[Int], target: Int): Option[Int] = {
val mid = l.length / 2
if (mid == 0) { // Length == 1
if (l.head + x == target) Some(l.head) else None
} else {
val candinate = l(mid)
if (candinate + x == target) Some(candinate)
else {
val s = l.splitAt(mid)
if (candinate + x > target) {
checkPair(x, s._1, target)
}
else /* candinate + x < target */ {
checkPair(x, s._2, target)
}
}
}
def hasPair(l1:List[Int],l2:List[Int],target:Int):选项[Pair[Int,Int]={
val s2=l2.0
l1 foreach{i=>
val p=检查对(i、s2、目标)
如果(p.isDefined)返回一些(i,p.get)
}
没有一个
}
专用def检查对(x:Int,l:List[Int],target:Int):选项[Int]={
val mid=l.长度/2
如果(mid==0){//Length==1
如果(l.head+x==目标)有一些(l.head)其他无
}否则{
val candinate=l(中间)
如果(candinate+x==目标)某些(candinate)
否则{
val s=l.splitAt(中间)
如果(candinate+x>目标){
支票对(x,s.\U 1,目标)
}
else/*candinate+x
很抱歉,由于声誉不高,我无法发表评论,但我很好奇您所说的“运行较慢”是什么意思?这两种算法的复杂性都是在最坏的情况下给出的。即使有非常大的n,Alg1在时间上也完全有可能超过Alg2(例如在第一次迭代中找到答案)
splitAt
函数遍历整个列表(与列表中的随机访问一样),所以您的第二个算法没有更好。它更糟糕,因为元素访问和列表拆分涉及的开销。好吧……首先,list
在scala中是一个LinkedList
。这意味着在列表中查找mth
元素需要O(m)
time。这意味着像val candinate=l(mid)
这样的东西实际上是O(mid)
而不是C
。这一事实是算法中最明显的问题之一。从L1和L2的末尾开始,并遵循类似的方法,当您只需要使用单个数组求和时,您可以选择向量
或范围
,而不是列表,因为它们具有随机ac分别在渐近常数
和常数
时间中访问时间复杂度。使用范围
尝试此操作,它提供常数
时间随机访问,然后我们可以讨论其他问题。@Sarvesh Kumar Singh,谢谢你的提示。我将尝试这两种方法,看看它如何影响性能。任务完成了使用一个文件,该文件只需运行n>10000的两种算法并打印时间。你是对的,我本可以更清楚地了解这一点。谢谢,在执行二进制搜索之前将列表转换为向量就成功了。
val s = l.splitAt(mid)