algorithm - 如何改进这个列表算法?

标签 algorithm functional-programming scheme racket

给出一个数字列表(字符或任何其他)和另一个随机数(字符或与列表同类),如果列表中有两个相邻值与最后一个相同(三个值相同),则将它们淘汰,然后递归进行。
例如
(1 5 3 3 2 2 4 3) + 2 => (1 5 3 3 2 2 4 3 2) => ( 1 5 3 3 4 3) => (1 5 4)

(1 3 3 2) + 2 => (1 3 3 2 2)

我的解决方案是这样的:

一个。扫描列表并获取与列表最后一个相同的两个相同值第一次出现的位置,如果未找到则为#f。

删除那三个值

递归调用一个

(define scan ;; list->list (get the position)
  (lambda (lst)
    (let scan-loop ((lst lst) (n 0))
      (cond
       [(<= (length  lst) 2) #f]
       [(and (equal? (car lst) (cadr lst))
     (equal? (car lst) (last lst))) n]
       [else
     (scan-loop (cdr lst) (+ n 1))]))))

(define (Arrange lst k) ; list,k -> list (remove the value) 
   (remove-k (remove-k (remove-k lst k) k) (- (length lst) 3)))

(define (remove-k lst k)
 (let remove-loop ((init lst) (n k) (new '()))
  (cond
   [(null? init) (error "K is too big for list")]
   [(= n 0) (append new (cdr init))]
   [else
    (remove-loop (cdr init) (- n 1) (append new (list (car init)) ))])))

(define (eliminate lst) ; list ,num -> lst (the main function)
  (let ([flag (scan lst)])
     (if flag
         (eliminate (Arrange lst flag))
         lst)))

这可行。但是当列表很长时它会变得非常慢。
我有一个测试:

(define lst (build-list 10000 (lambda (x) (random 10))))
(eliminate lst)

在Drracket(6GB内存,2.3G hz cpu *4)中,根据性能分析,主要耗费的时间有这些:
调用 remove-loop11517101 次,花费 49283 毫秒
调用 scan-loop2450002 次,花费 121294 毫秒
调用 Arrange747 次,花费 713182 毫秒
调用 eliminate748 次,花费 130611 毫秒

而且在运行过程中,我发现只有一个cpu几乎被100%使用(轮流)。
这个可以多线程运行吗?

而且我认为主要问题是我使用的算法效率低下。我认为它可以真正优化。可能使用动态算法,用一个表来存储每次发生和更新。
如何做到这一点?

非常感谢。

最佳答案

不要在 Dr Racket 中测量结果,因为 IDE 的开销非常高。始终从 shell 执行耗时的计算。

这是我的算法,对于包含 10,000 个元素的列表,该算法的执行时间不到半秒(而您的算法为 9.5 分钟):

(define (remn lst)
  (if (null? lst)
      lst
      (let* ((rlst (reverse lst)) (last (car rlst)))
        (let loop ((left null) (curn 0) (rght (reverse (cdr rlst))))
          (if (null? rght)
              (append (reverse left) (list last))
              (let ((e (car rght)))
                (if (equal? e last)
                    (if (= curn 1)
                        (remn (append (reverse (cdr left)) (cdr rght)))
                        (loop (cons e left) (add1 curn) (cdr rght)))
                    (loop (cons e left) 0 (cdr rght)))))))))

例子:

> (remn '(1 5 3 3 2 2 4 3 2))
'(1 5 4)
> (remn '(1 3 3 2 2))
'(1 3 3 2 2)
> (remn '(1 1 3 3 3 3 3 1))
'(3 3)

关于algorithm - 如何改进这个列表算法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23676690/

相关文章:

ios - 如何从字典 [Objective-C] 中的其他键中删除对象?

python - 评估列表 : AvgP@K and R@K are they same?

function - Scala 中的 "lifting"是什么?

javascript - 寻找一个 FP 算法来从点分隔的字符串中组成对象

list - 在 Racket 中,列表相对于向量的优势是什么?

scheme - Typed Racket 中的绘图功能

python - SICP 练习 3.20 - 理解环境图(我的图中缺少绑定(bind))

javascript - 根据内容长度设置显式模式宽度

c++ - 给定的 float 位于哪个段?

scala - 为什么 Scala 类型推断在这里失败