【问题标题】:How to improve this list algorithm?如何改进这个列表算法?
【发布时间】:2014-07-03 19:25:27
【问题描述】:

如果列表中有两个与最后一个相同的相邻值(三个值是一样的),那么它们就会被淘汰,然后递归进行。
例如
(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。

b.删除这三个值

c。递归调用一个

(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(6 GB内存,2.3G hz cpu *4)中,根据性能分析,主要的时间成本是:
调用remove-loop11517101times,花费49283毫秒
调用scan-loop2450002times,花费121294毫秒
调用Arrange747times,花费713182毫秒
调用eliminate748 次,花费130611 毫秒

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

我认为主要问题是我使用的算法效率低下。我认为它可以真正优化。也许使用动态算法,使用一个表来存储发生和每次更新。
该怎么做?

非常感谢。

【问题讨论】:

  • 您是否尝试存储(对于每个值?)相邻出现的位置?只能一步一步改变。
  • 你能更好地解释你的例子吗(一步一步)?我设法根据数据提出了一些规则,但这似乎与您对消除什么的解释不相符。而且最后3个没有相邻的3个,那为什么要去掉呢?
  • 我的错。例子应该是这样的:(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)

标签: algorithm functional-programming scheme racket


【解决方案1】:

不要在 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)

【讨论】:

  • 第二个例子错了,应该是(1 3 3 2) + 2 => (1 3 3 2 2)。但第一个是对的。(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)。首先消除2,然后消除3。是我解释错了还是有什么让你困惑的地方?
  • 是的,你的错误例子让我很困惑。我修改了我的代码,现在应该是正确的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-07
  • 1970-01-01
  • 2019-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多