Перейти к содержанию

Реализации алгоритмов/Наибольшая общая подпоследовательность

Материал из Викиучебника — открытых книг для открытого мира

Динамическое программирование

[править]

Примеры реализации простого алгоритма динамического программирования со сложностью O(nm), где n, m — размеры строк.

    string getLongestCommonSubsequence(const string& a, const string& b)
    {
        vector<vector<int> > max_len;
        max_len.resize(a.size() + 1);
        for(int i = 0; i <= static_cast<int>(a.size()); i++)
            max_len[i].resize(b.size() + 1);
        for(int i = static_cast<int>(a.size()) - 1; i >= 0; i--)
        {
            for(int j = static_cast<int>(b.size()) - 1; j >= 0; j--)
            {
                if(a[i] == b[j])
                {
                    max_len[i][j] = 1 + max_len[i+1][j+1];
                }
                else
                {
                    max_len[i][j] = max(max_len[i+1][j], max_len[i][j+1]);
                }
            }
        }
        string res;
        for(int i = 0, j = 0; max_len[i][j] != 0 && i < static_cast<int>(a.size()) && j < static_cast<int>(b.size()); )
        {
            if(a[i] == b[j])
            {
                res.push_back(a[i]);
                i++;
                j++;
            }
            else
            {
                if(max_len[i][j] == max_len[i+1][j])
                    i++;
                else
                    j++;
            }
        }
        return res;
    }
#>> a = "aaaaabbbb34354354345"
#>> b = "abbb34aaabbbb"
#>> longest_common_subsequence(a, b)
#=> "aaaabbbb"
  def longest_common_subsequence(a, b)
    max_len = Array.new(a.size + 1, 0)
    max_len.map! {Array.new(b.size + 1, 0)}

    (a.size - 1).downto(0) do |i|
      (b.size - 1).downto(0) do |j|
        if a[i] == b[j]
          max_len[i][j] = 1 + max_len[i+1][j+1]
        else
          max_len[i][j] = [max_len[i+1][j], max_len[i][j+1]].max
        end
      end
    end

    res = ""
    i = 0
    j = 0
    while max_len[i][j] != 0 && i < a.size && j < b.size
      if a[i] == b[j]
        res << a[i]
        i += 1
        j += 1
      else
        if max_len[i][j] == max_len[i+1][j]
          i += 1
        else
          j += 1
        end
      end
    end

    res
  end
require 'diff/lcs'
def lcs(x, y)
  Diff::LCS.LCS(x, y).join
end
lcs(x = 'dggfgffegsss345265', y = 'vdfspkddssf4563')
#=> "dfsss456"

'''ещё один вариант:'''
def lcs(x, y)
  dp = Array.new(x.length + 1){Array.new(y.length + 1){''}}
  x.each_char.with_index do |c, i|
  y.each_char.with_index do |d, j|
  result = [dp[i][j], dp[i][j + 1], dp[i + 1][j]].max_by(&:length)
      if c == d 
        result = dp[i][j] + c
      end
      dp[i + 1][j + 1] = result
    end
  end
 dp[-1][-1]
end
lcs(x = 'dggfgffegsss345265', y = 'vdfspkddssf4563')
#=> "dfsss456"
import Data.Array
import Data.Function
import Data.List

yoba listY listX = reverse $ arr ! (lenY, lenX)

  where lenY = length listY
        lenX = length listX

        arrY = listArray (1, lenY) listY
        arrX = listArray (1, lenX) listX

        arr = listArray ((0, 0), (lenY, lenX)) [value y x | y <- [0 .. lenY], x <- [0 .. lenX]]

        value y x | y == 0 || x == 0     = []
                  | arrY ! y == arrX ! x = (arrY ! y :) $ arr ! (pred y, pred x)
                  | otherwise            = maximumBy (compare `on` length) [arr ! (y, pred x), arr ! (pred y, x)]


main = print $ yoba "aaaaabbbb34354354345" "abbb34aaabbbb"
lcs([], _) ->
    "";
lcs(_, []) ->
    "";
lcs([X | T1], [X | T2]) ->
    [X | lcs(T1, T2)];
lcs([X | T1] = L1, [Y | T2] = L2) when X =/= Y ->
    longest(lcs(L1, T2), lcs(T1, L2)).

longest(T1, T2) when length(T1) >= length(T2) ->
    T1;
longest(_, T2) ->
    T2.