You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Turbo Prolog开发需求:移除列表中所有回文(含交叉回文)

Turbo Prolog:移除列表中所有回文元素(含交叉回文)

需求

编写Turbo Prolog程序,移除列表中所有属于长度大于1的回文子列表的元素,包括交叉回文(如1 2 1 3 1中的[1,2,1]和[1,3,1])。

现有实现问题

当前算法逻辑:

  1. 生成原列表的所有前缀子列表
  2. 筛选出长度>1的回文子列表
  3. 删除原列表中属于这些回文子列表的元素

针对示例列表[1,2,1,3,1,4,5,1],当前代码输出[4,5],但预期应为[4,5,1]。问题出在:直接根据元素值判断是否删除,导致最后一个1因为在其他回文子列表中出现过(如第一个1)被误删,而实际上它不属于任何回文子列表。

教授给出的解决思路:为原列表元素添加唯一索引,通过索引追踪回文子列表的位置,去重后删除对应索引的元素,避免值重复导致的误删。

当前代码

domains
int = integer
intl = int*
intll = intl*

predicates
read_list(intl)
reverse(intl, intl)
append(intll, intll, intll)
app(intl, intl, intl)
length(intl, int)
cut(intl, int, intl)
subseq(intl, int, int, intl)
prefixes(intl, int, intll)
all_sublists(intl, intll)
is_pal(intl)
all_pals(intll, intll)
all_palindroms(intl, intll)
belongs_to_sublist(int, intll)
filter_elements(intll, intl, intl)
member(int, intl)

clauses
read_list([Head|Tail]) :- 
    readint(Head), !,
    read_list(Tail).
read_list([]).

reverse([], []).
reverse([H|T], X) :- reverse(T, Rt), app(Rt, [H], X).

append([], X, X).
append([H|T], X, [H|R]) :- append(T, X, R).

app([], X, X).
app([H|T], X, [H|R]) :- app(T, X, R).

length([], 0).
length([_|T], N) :- length(T, N1), N = N1 + 1.

cut(_, 0, []) :- !.
cut([H|T], L, [H|R]) :- L1 = L - 1, cut(T, L1, R).

subseq(X, 0, L, R) :- cut(X, L, R), !.
subseq([_|X], P, L, R) :- P1 = P - 1, subseq(X, P1, L, R).

prefixes(X, L, []) :- length(X, LX), L > LX, !.
prefixes(X, L, [R|T]) :- subseq(X, 0, L, R), L1 = L + 1, prefixes(X, L1, T).

all_sublists([], []).
all_sublists([H|T], Q) :- prefixes([H|T], 1, R), all_sublists(T, Z), append(R, Z, Q).

is_pal(X) :- reverse(X, Rx), X = Rx.

all_pals([], []).
all_pals([H|T], [H|R]) :- length(H, L), L > 1, is_pal(H), all_pals(T, R), !.
all_pals([_|T], R) :- all_pals(T, R).

all_palindroms(X, U) :- all_sublists(X, Sx), all_pals(Sx, U).

belongs_to_sublist(Element, [Sublist|_]) :- 
    member(Element, Sublist).
belongs_to_sublist(Element, [_|Sublists]) :- 
    belongs_to_sublist(Element, Sublists).

filter_elements(_, [], []).
filter_elements(Sublists, [H|T], [H|Filtered]) :- 
    not(belongs_to_sublist(H, Sublists)),
    filter_elements(Sublists, T, Filtered).
filter_elements(Sublists, [H|T], Filtered) :- 
    belongs_to_sublist(H, Sublists),
    filter_elements(Sublists, T, Filtered).

member(X, [X|_]).
member(X, [_|Tail]) :- member(X, Tail).

goal
write("Elements of list:"), nl,
read_list(List),
write("list:"), write(List), nl,
all_palindroms(List, Q), write("all palindromes in list: "), write(Q), nl,
filter_elements(Q, List, Res), write("without palindromes: "), write(Res).

修正后的代码(基于索引追踪)

domains
int = integer
int_pair = (int, int)  % (索引, 元素值)
intl = int*
pair_list = int_pair*
intll = intl*
index_set = int*

predicates
read_list(intl)
add_indices(intl, int, pair_list)
reverse(intl, intl)
append(intll, intll, intll)
app(intl, intl, intl)
length(intl, int)
cut(intl, int, intl)
subseq(intl, int, int, intl)
prefixes(intl, int, intll)
all_sublists(intl, intll)
is_pal(intl)
all_pals(intll, intll)
all_palindroms(intl, intll)
get_pal_indices(pair_list, intl, index_set)
collect_delete_indices(pair_list, intll, index_set)
merge_and_dedup(index_set, index_set, index_set)
filter_by_indices(pair_list, index_set, intl)
member(int, intl)

clauses
% 读取用户输入的列表
read_list([Head|Tail]) :- 
    readint(Head), !,
    read_list(Tail).
read_list([]).

% 为列表元素添加从1开始的索引
add_indices([], _, []).
add_indices([H|T], Index, [(Index, H)|Rest]) :-
    NextIndex = Index + 1,
    add_indices(T, NextIndex, Rest).

% 反转列表,用于判断回文
reverse([], []).
reverse([H|T], X) :- reverse(T, Rt), app(Rt, [H], X).

% 拼接子列表集合
append([], X, X).
append([H|T], X, [H|R]) :- append(T, X, R).

% 拼接普通列表
app([], X, X).
app([H|T], X, [H|R]) :- app(T, X, R).

% 计算列表长度
length([], 0).
length([_|T], N) :- length(T, N1), N = N1 + 1.

% 截取列表前L个元素
cut(_, 0, []) :- !.
cut([H|T], L, [H|R]) :- L1 = L - 1, cut(T, L1, R).

% 截取从位置P开始、长度为L的子列表
subseq(X, 0, L, R) :- cut(X, L, R), !.
subseq([_|X], P, L, R) :- P1 = P - 1, subseq(X, P1, L, R).

% 生成列表的所有前缀子列表(长度从L开始递增)
prefixes(X, L, []) :- length(X, LX), L > LX, !.
prefixes(X, L, [R|T]) :- subseq(X, 0, L, R), L1 = L + 1, prefixes(X, L1, T).

% 生成列表的所有子列表
all_sublists([], []).
all_sublists([H|T], Q) :- prefixes([H|T], 1, R), all_sublists(T, Z), append(R, Z, Q).

% 判断是否为回文子列表
is_pal(X) :- reverse(X, Rx), X = Rx.

% 筛选出所有长度大于1的回文子列表
all_pals([], []).
all_pals([H|T], [H|R]) :- length(H, L), L > 1, is_pal(H), all_pals(T, R), !.
all_pals([_|T], R) :- all_pals(T, R).

% 获取列表中所有符合条件的回文子列表
all_palindroms(X, U) :- all_sublists(X, Sx), all_pals(Sx, U).

% 根据回文子列表的元素值,找到对应的原列表索引
get_pal_indices(PairList, SubList, Indices) :-
    get_pal_indices_helper(PairList, SubList, [], Indices).

get_pal_indices_helper(_, [], Acc, Acc).
get_pal_indices_helper([(Idx, Val)|Rest], [Val|SubRest], Acc, Final) :-
    get_pal_indices_helper(Rest, SubRest, [Idx|Acc], Final), !.
get_pal_indices_helper([_|Rest], SubList, Acc, Final) :-
    get_pal_indices_helper(Rest, SubList, Acc, Final).

% 收集所有回文子列表对应的索引,并去重
collect_delete_indices(_, [], []).
collect_delete_indices(PairList, [Pal|Rest], AllIndices) :-
    get_pal_indices(PairList, Pal, PalIndices),
    collect_delete_indices(PairList, Rest, RestIndices),
    merge_and_dedup(PalIndices, RestIndices, AllIndices).

% 合并两个索引列表并去重
merge_and_dedup([], List, List).
merge_and_dedup([H|T], List, Result) :-
    member(H, List), !,
    merge_and_dedup(T, List, Result).
merge_and_dedup([H|T], List, [H|Result]) :-
    merge_and_dedup(T, List, Result).

% 过滤元素:保留不在删除索引集合中的元素
filter_by_indices([], _, []).
filter_by_indices([(Idx, Val)|Rest], DeleteIndices, [Val|Filtered]) :-
    not(member(Idx, DeleteIndices)), !,
    filter_by_indices(Rest, DeleteIndices, Filtered).
filter_by_indices([_|Rest], DeleteIndices, Filtered) :-
    filter_by_indices(Rest, DeleteIndices, Filtered).

% 元素成员判断
member(X, [X|_]).
member(X, [_|Tail]) :- member(X, Tail).

% 主目标逻辑
goal
write("输入列表元素(回车结束输入):"), nl,
read_list(OriginalList),
write("原列表:"), write(OriginalList), nl,
add_indices(OriginalList, 1, IndexedList),
all_palindroms(OriginalList, Palindromes),
write("所有长度>1的回文子列表:"), write(Palindromes), nl,
collect_delete_indices(IndexedList, Palindromes, DeleteIndices),
filter_by_indices(IndexedList, DeleteIndices, Result),
write("移除回文元素后的列表:"), write(Result), nl.

关键修正点

  1. 索引化元素:通过add_indices为每个元素绑定唯一索引,避免值重复导致的误判。
  2. 索引追踪回文:get_pal_indices根据回文子列表的元素值,匹配原列表中对应的索引,确保只标记真正属于回文子列表的元素位置。
  3. 去重删除索引:merge_and_dedup避免同一索引被多次标记,确保每个元素只被判断一次。
  4. 按索引过滤:filter_by_indices根据索引保留元素,最终得到符合预期的结果。

对于示例列表[1,2,1,3,1,4,5,1],修正后的代码会正确保留最后一个1,输出[4,5,1]。

内容的提问来源于stack exchange,提问作者Seryozhka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 09:04:53