如何删除列表的副本? (运行时间为O(n log n)) 例如:'(4 6 1 1 2 3 3 5 6)=> '(4 6 1 2 3 5)
(define (re-dup lst)
(cond
((empty? lst) empty)
(else
(define el (first lst))
(define el-free-lst (filter (lambda (x) (not (= el x))) (rest lst)))
(cons el (re-dup el-free-lst)))))
这是对的吗?
答案 0 :(得分:2)
您当前的解决方案是O(n^2)
,因为filter
遍历列表一次为原始列表中的每个元素。可以使用具有常量时间插入和成员资格操作的辅助数据结构编写O(n)
解决方案,以跟踪已经找到的元素。
在Racket中,我们有一个开箱即用的set
数据结构,对于常量时间操作,“实际上需要一组O(log N)时间大小N“(请参阅documentation),因此set-member?
和set-add
程序将为O(log n)
。因此,使用Racket的set
进行此实现并非最佳,但我们实现了O(n log n)
目标:
(define (re-dup lst)
(let loop ((seen (set))
(lst lst)
(acc '()))
(cond ((null? lst)
(reverse acc))
((set-member? seen (car lst))
(loop seen (cdr lst) acc))
(else
(loop (set-add seen (car lst))
(cdr lst)
(cons (car lst) acc))))))
按预期工作,保留列表中的原始顺序(这是此问题的约束,如评论中所述),但需要额外执行O(n)
reverse
次操作:
(re-dup '(4 6 1 1 2 3 3 5 6))
=> '(4 6 1 2 3 5)
答案 1 :(得分:0)
您可以通过以下方式获得O(n log n)
行为:
O(n log n)
)O(n)
因此整体O(n log n)
。
(define (re-dup lst)
(if (null? lst)
lst
(let ((lst (list-sort < lst)))
(let thinning ((skip (car lst)) (rest (cdr lst)))
(cond ((null? rest) (list skip))
((equal? skip (car rest)) (thinning skip (cdr rest)))
(else (cons skip (thinning (car rest) (cdr rest)))))))))