Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 在clojure[script]中,如何返回两个排序向量之间最近的元素_Algorithm_Clojure_Clojurescript - Fatal编程技术网

Algorithm 在clojure[script]中,如何返回两个排序向量之间最近的元素

Algorithm 在clojure[script]中,如何返回两个排序向量之间最近的元素,algorithm,clojure,clojurescript,Algorithm,Clojure,Clojurescript,在clojure[script]中,如何编写一个函数最近的,该函数接收两个排序向量a,b,并为a的每个元素返回b的最近元素 例如, (nearest [1 2 3 101 102 103] [0 100 1000]); [0 0 0 100 100 100] 我希望解决方案既地道又有良好的性能:O(n^2)是不可接受的 受@amalloy的启发,我发现了这个问题,并编写了这个解决方案: (defn abs[x] (max x (- x)))

clojure[script]
中,如何编写一个函数
最近的
,该函数接收两个排序向量
a
b
,并为
a的每个元素返回
b
的最近元素

例如,

(nearest [1 2 3 101 102 103] [0 100 1000]); [0 0 0 100 100 100]

我希望解决方案既地道又有良好的性能:
O(n^2)
是不可接受的

受@amalloy的启发,我发现了这个问题,并编写了这个解决方案:

(defn abs[x]                         
  (max x (- x)))                     

(defn nearest-of-ss [ss x]           
  (let [greater (first (subseq ss >= x))
        smaller (first (rsubseq ss <= x))]
    (apply min-key #(abs (- % x)) (remove nil? [greater smaller]))))

(defn nearest[a b]
  (map (partial nearest-of-ss (apply sorted-set a)) b))
(定义abs[x]
(最大x(-x)))
(与ss[ss x]最接近的定义)
(让[更大(第一个(子节ss>=x))

较小的(首先(rsubseq ss让
n
be
(count a)
m
be
(count b)
。然后,如果
a
b
都是有序的,那么这可以在我认为应该是
O(n log(log m))
的时间内完成,换句话说,非常接近
n
的线性

首先,让我们重新实现
abs
和一个独立于主机的二进制搜索(改进)(利用本机,例如Java的版本应该会快得多)

如果对
b
进行排序,则
b
中的二进制搜索需要
logm
步骤。因此,将此映射到
a
是一个
O(nlogm)
解决方案,对于实用主义者来说,这可能已经足够好了

(defn nearest* [a b]
  (map #(b (binary-search-nearest-index b %)) a))
然而,我们也可以使用这样一个事实,即
a
被排序为划分和征服
a

(defn nearest [a b]
  (if (< (count a) 3)
    (nearest* a b)
    (let [m (quot (count a) 2)
          i (binary-search-nearest-index b (a m))] 
      (lazy-cat
        (nearest (subvec a 0 m) (subvec b 0 (inc i))) 
        [(b i)]
        (nearest (subvec a (inc m)) (subvec b i))))))
(定义最近[a b]
(如果(<(计数a)3)
(最近的*a b)
(让[m(quot(计数a)2)
i(二元搜索最近索引b(am))]
(懒猫
(最近的(subvec a 0 m)(subvec b 0(inc i)))
[(b i)]
(最近的(subvec a(inc m))(subvec b i‘‘‘‘‘‘‘‘)

我认为这应该是
O(n log(log m))
。我们从
a
的中位数开始,在
log m
时间中找到最接近的
b
。然后我们在
a
的每一半上递归
b
的分割部分。如果a
m
-b的比例因子每次被分割,你就有O(n log m)。如果仅分割出一个常量部分,则处理该部分的
a
的一半是线性时间。如果这种情况持续下去(对
b
的常量大小部分的迭代一半),则使用二进制搜索或排序集得到
O(n)
的时间复杂度为O(n*log m),其中n为
(计数a)
和m
(计数b)

然而,利用a和b被排序的事实,时间复杂度可以是O(max(n,m))

(定义最近[a b]
(如果让[more-b(下一个b)]
(让[x y]b
米(/(+xy)2)
[m] (以#分割)(最接近[123101102103501601][010010000])
(0 0 0 100 100 100 100 1000)

b
m
元素中对
a
n
元素进行二进制搜索:
n lg m
。如果不能保证,请先排序
b
(m log m)。您自己还没有尝试解决这个问题;而且,对于这个问题来说,排序向量是一个非常糟糕的数据结构。例如,将事物放入排序集中,然后问题的“二进制搜索”部分就免费了。@amalloy“免费”是什么意思?在必要功能已经存在的意义上是免费的?二进制搜索树中的搜索与随机访问数组中的二进制搜索具有相同的对数复杂度特征。如果您要求对排序集上的耳机和尾套进行比较,这是工作的两倍。或者,我是天真的吗?@a.Webb,请参阅下面我的答案:排序集h作为两个方便的函数:
subseq
rsubseq
@viebel是的,我刚刚进入了Java。它们本质上是一样的。每个函数都需要对数时间才能在支持排序集的二元搜索树中找到合适的起始位置。因为你要做两次,这可能是做二元搜索的两倍在数组上。我喜欢它,但是如果
m>>n
那么
n log m
max(n,m)好
。考虑到你关于两种排序方式的观点,我怀疑在这种情况下可能会更好。@A.Webb是正确的,但构建排序集是
m log m
,因此只有二进制搜索方式在
m>>n
时更好。你是对的,b被排序并作为向量将允许指数跳过b(感谢编辑,顺便说一句,我从我的回复历史中粘贴了错误的代码片段).@A.Webb我认为
O(n log(m/n))
是你可以通过
m>>n
得到的。它简化为
O(n log m)
O(n)
否则。我想
O(n log m)
,但还没有把笔写在纸上。从
a
的中位数开始,在
log m
时间中找到最近的
b
。在
a
的每一半上递归
b
的拆分部分。如果每次拆分
b
的m尺寸因子,则为
O(n log m)
。如果只分离出一个恒定部分,那么在该部分工作的
a
的一半是线性时间。如果这种情况持续下去(在
b
的恒定大小部分工作的
a
的迭代一半),则您有
O(n)
否则
O(log log log m)
最终。上述想法现在已在中实现。我既没有进行过调优、测试,也没有进行过详细分析。注意:如果进行调优,您希望
a
上有一个更高的计数阈值,以便在递归中回退到
最近的*
,回退到
O(max(n,m))
由@cgrand在递归中当
m是一个很好的解决方案。像我一样,你隐式地假设b严格递增。@cgrand受你的启发。递增,是的。严格地说是吗?我没有考虑重复,因为我把
b
看作是相邻的区间,但我认为我们的解决方案
(defn nearest [a b]
  (if (< (count a) 3)
    (nearest* a b)
    (let [m (quot (count a) 2)
          i (binary-search-nearest-index b (a m))] 
      (lazy-cat
        (nearest (subvec a 0 m) (subvec b 0 (inc i))) 
        [(b i)]
        (nearest (subvec a (inc m)) (subvec b i))))))
(defn nearest [a b]
  (if-let [more-b (next b)]
    (let [[x y] b
          m (/ (+ x y) 2)
          [<=m >m] (split-with #(<= % m) a)]
      (lazy-cat (repeat (count <=m) x)
        (nearest >m more-b)))
    (repeat (count a) (first b))))


=> (nearest [1 2 3 101 102 103 501 601] [0 100 1000])
(0 0 0 100 100 100 100 1000)