在下面的示例中,我试图返回“a”所属的最小2个元素(最近邻居)。
“a”中最小的两个元素基于:
List((("a","b"),1.0) , (("a","c"),4.0) , (("a","c"),3.0) , (("b","c"),2.0) )
是
List((("a","b"),1.0) , (("a","c"),3.0))
这是我的解决方案:
val l = List((("a","b"),1.0) , (("a","c"),4.0) , (("a","c"),3.0) , (("b","c"),2.0) )
//> l : List[((String, String), Double)] = List(((a,b),1.0), ((a,c),4.0), ((a,c
//| ),3.0), ((b,c),2.0))
val justA = l.filter(v => v._1._1.equals("a") || v._1._2.equals("a")).sortBy(_._2).take(2)
//> justA : List[((String, String), Double)] = List(((a,b),1.0), ((a,c),3.0))
这个计算有更有效的解决方案吗?
答案 0 :(得分:1)
在过滤步骤之后,您可以应用找到k个最小剩余元素的算法。这类似于这个问题:Algorithm to find k smallest numbers in array of n items
并概括一下我刚刚发布到那个问题的答案(因为在查找算法时我忘记了谁曾问过哪个问题):
有可能在O(n)时间内找到k个最小的n个元素(我的意思是真正的O(n)时间,而不是O(n + k的某个函数))。请参阅此处 - http://en.wikipedia.org/wiki/Selection_algorithm - 特别是关于“无序部分排序”和“中间选择作为枢轴策略”的小节,以及此处 - http://en.wikipedia.org/wiki/Median_of_medians - 用于制作此O的基本部分( n)中。
附录:如果你真的只需要找到两个最小的元素,那么,不是这个答案前面部分所描述的k元素,有两个很多可以在过滤步骤之后应用的更简单的O(n)算法。
算法1。在对剩余数据的一次传递中,找到最小的元素。将其取下并放在一边。然后找到剩下的最小元素。你现在有两个最小的元素;找到第一个的时间是O(n),找到第二个的时间是O(n),并且这一起仍然是O(n)。
算法2. 使用单淘汰锦标赛,找到剩余的最小元素。这需要n-1次比较。第二个最小的元素将是与最小元素进行比较的大约lg(n)元素之一(使用基数为2的对数),因此接下来在O(log n)时间内找到这些元素中最小的元素。所以这也是O(n),但比算法1的比较少。但是,在你的情况下,比较非常快,所以我可能只使用算法1.