[1,3,5,6,7]
の答えになるということです[4,1,3,8,9,5,6,7]
か?IOW、あなたは本当にサブセット、または単なるサブリスト、つまりリストの連続部分を意味しますか?
後者の場合、サブセットは必要ありません。検索は線形です。リスト内で[a,b,c,d,e,f]
それが見つかりd > e
、増加するシーケンスが停止した場合、今[a,b,c,d]
から検索を再開する必要はありません: シーケンスは で壊れます。から検索を続行します。b
d
e
そのため、検索中にいくつかの追加情報を持ち歩くだけです。現在およびこれまでに勝利したサブシーケンス。そしてそれらの長さ。
longest_incr([],0-[]).
longest_incr([A|B],RL-R):- % R is the result, of length RL
longest_aux(B,[],0, [A],1, RL-R).
longest_aux([], Win,N, Curr,K, RL-R):-
( K>N -> RL=K, reverse(Curr,R) ; RL=N, reverse(Win,R) ).
longest_aux([A|B],Win,N, Curr,K, RL-R):- Curr = [X|_], L is K,
( A>X -> longest_aux(B,Win, N, [A|Curr],L+1,RL-R) % keep adding
; L>N -> longest_aux(B,Curr,K, [A], 1, RL-R) % switch the winner
; longest_aux(B,Win, N, [A], 1, RL-R) % winner unbeaten
).
OTOHが本当に最長のサブセットを必要とする場合...そこには矛盾があります。セットはその要素を再配置できるため、特定のリストの最長のサブセットは次のようになります。
longset_subset(L,R):- sort(L,S), R=S.
おそらく、順序を維持する最長のサブシーケンスを意味します。つまり、非連続であってもかまいません。次に、subset
withfindall
または類似の述語に対するすべてのソリューションを収集し、これらの結果を分析できます。
longest_subseq(L,R):-
findall( S, subset(L,S), X),
maplist( longest_incr, X, Y),
keysort( Y, Z),
last( Z, _Len-R).
上記には多くの冗長性があります。増加するサブシーケンスのみを許可することで、その効率を向上させることができます。
incr_subseq([],[]).
incr_subseq([_|X],Y):- incr_subseq(X,Y).
incr_subseq([A|X],[A|Y]):- incr_subseq(X,Y), ( Y=[] ; Y=[B|_], A<B).
上記の述語によって見つかったすべてのサブシーケンスが増加するため、それらlength
の s を取得できます。
lenlist(List,Len-List) :- length(List,Len).
longest_subseq(L,R):-
findall( S, incr_subseq(L,S), X),
maplist( lenlist, X, Y),
keysort( Y, Z),
last( Z, _Len-R).
または、線形検索longest_incr
を微調整して、より効率的なソリューションにすることもできます。勝ったサブシーケンスを 1 つだけ維持する代わりに、入力リストに沿って進行するすべての関連する可能性を維持します。