Mercurial > lbo > hg > juliaplay
changeset 24:d660fc20d950
DP: shortest common supersequence and longest palindromic subsequence
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Fri, 03 Mar 2023 00:23:39 +0100 |
parents | 41c00af82d66 |
children | 203bb5bbeea5 |
files | julia/dp.jl |
diffstat | 1 files changed, 110 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/julia/dp.jl Thu Mar 02 23:06:32 2023 +0100 +++ b/julia/dp.jl Fri Mar 03 00:23:39 2023 +0100 @@ -402,3 +402,113 @@ min(xfirst, yfirst) end + +function shortest_common_supersequence_track_s(x::AbstractString, y::AbstractString)::String + byL = fill(' ', length(x)+length(y)) + L = shortest_common_supersequence_track(x, y, 1, 1, 0, [length(x)+length(y)], byL) + String(byL[1:L]) +end + +function shortest_common_supersequence_track(x::AbstractString, y::AbstractString, i=1, j=1, L=0, Lmin=[length(x)+length(y)], byL=fill(' ', length(x)+length(y)), mem=Dict{Tuple,Int}())::Int + if (i, j, L) in keys(mem) + return mem[(i,j,L)] + end + if i > length(x) || j > length(y) + L_ = max(length(y)-j+1, length(x)-i+1) + Lmin[1] = min(Lmin[1], L_ + L) + if i > length(x) + byL[L+1:L+L_] .= collect(y[j:end]) + else + byL[L+1:L+L_] .= collect(x[i:end]) + end + mem[(i, j, L)] = L_+L + return L_ + L + end + + # Case 1: current first letters identical + if x[i] == y[j] + L_ = shortest_common_supersequence_track(x, y, i+1, j+1, L+1, Lmin, byL, mem) + if L_ == Lmin[1] + byL[L+1] = x[i] + end + mem[(i, j, L)] = L_ + return L_ + end + + # Case 2: current first letters are not identical: choose shortest supersequence from here. + + # take from x + xfirst = shortest_common_supersequence_track(x, y, i+1, j, L+1, Lmin, byL, mem) + # take from y + yfirst = shortest_common_supersequence_track(x, y, i, j+1, L+1, Lmin, byL, mem) + + if xfirst < yfirst + if xfirst == Lmin[1] + byL[L+1] = x[i] + end + else + if yfirst == Lmin[1] + byL[L+1] = y[j] + end + end + + R = min(xfirst, yfirst) + mem[(i,j,L)] = R + R +end + +function longest_palindromic_subsequence(s::AbstractVector, i=1, j=length(s))::Int + if i > j + return 0 + elseif i == j + return 1 + else + if s[i] == s[j] + 2 + longest_palindromic_subsequence(s, i+1, j-1) + else + right = longest_palindromic_subsequence(s, i, j-1) + left = longest_palindromic_subsequence(s, i+1, j) + max(left, right) + end + end +end + +function longest_palindromic_subsequence_tracking_s(s::AbstractVector{T})::Vector where {T} + byL = zeros(T, length(s)) + l = longest_palindromic_subsequence_tracking(s, 1, length(s), 0, [0], byL) + byL +end + +"""As above, but tracks longest sequence. Note: palindromic length defined here as 1 + length of a half. +""" +function longest_palindromic_subsequence_tracking(s::AbstractVector{T}, i=1, j=length(s), L=0, Lmax=[0], byL=zeros(T, length(s)), mem=Dict{Tuple,Int}())::Int where {T} + if (i,j,L) in keys(mem) + return mem[(i,j,L)] + end + + if i > j + return 0 + elseif i == j + if L+1 > Lmax[1] + Lmax[1] = L+1 + byL[L+1] = s[i] + end + mem[(i,j,L)] = 1 + L + return 1 + L + else + if s[i] == s[j] + L_ = longest_palindromic_subsequence_tracking(s, i+1, j-1, L+1, Lmax, byL, mem) + if L_ == Lmax[1] + byL[L+1] = s[i] + end + mem[(i, j, L)] = L_ + return L_ + else + right = longest_palindromic_subsequence_tracking(s, i, j-1, L, Lmax, byL, mem) + left = longest_palindromic_subsequence_tracking(s, i+1, j, L, Lmax, byL, mem) + m = max(left, right) + mem[(i,j,L)] = m + m + end + end +end