Существует много ресурсов о том, как удалить дубликаты и подобные проблемы, но я не могу найти ни одного по удалению уникальных элементов. Я использую SWI-Prolog, но не хочу использовать встроенные модули для достижения этой цели.
То есть вызов remove_unique([1, 2, 2, 3, 4, 5, 7, 6, 7], X).
должен с успехом привести к X = [2, 2, 7, 7]
.
Очевидным решением является что-то вроде
count(_, [], 0) :- !.
count(E, [E | Es], A) :-
S is A + 1,
count(E, Es, S).
count(E, [_ | Es], A) :-
count(E, Es, A).
is_unique(E, Xs) :-
count(E, Xs, 1).
remove_unique(L, R) :- remove_unique(L, L, R).
remove_unique([], _, []) :- !.
remove_unique([X | Xs], O, R) :-
is_unique(X, O), !,
remove_unique(Xs, O, R).
remove_unique([X | Xs], O, [X | R]) :-
remove_unique(Xs, O, R).
Должно сразу стать понятно, почему это не идеальное решение: count
— это O(n)
, как и is_unique
, так как он просто использует count
. Я мог бы улучшить это с помощью fail
ing, когда мы находим более одного элемента, но в худшем случае все еще O(n)
.
Итак, мы подошли к remove_unique
. Для каждого элемента мы проверяем, является ли текущий элемент is_unique
в O
. Если тест не пройден, элемент добавляется в результирующий список в следующей ветке. Работая в O(n²)
, мы получаем много выводов. Хотя я не думаю, что мы сможем ускорить его в худшем случае, можем ли мы добиться большего, чем это наивное решение? Единственное улучшение, которое я ясно вижу, - это изменить count
на что-то, что дает сбой, как только идентифицируется >1 элемент.