ID photo of Ciro Santilli taken in 2013 right eyeCiro Santilli OurBigBook logoOurBigBook.com  Sponsor 中国独裁统治 China Dictatorship 新疆改造中心、六四事件、法轮功、郝海东、709大抓捕、2015巴拿马文件 邓家贵、低端人口、西藏骚乱
cpp/longest_common_subsequence.cpp
#include <algorithm>    // TODO why required?
#include <cassert>
#include <iostream>     // cout, endl
#include <tuple>
#include <vector>

/**
 * @param[in]  input0, input1  The input strings.
 * @param[out] output          The longest substring.
 * 
 *     In case that there are multiple possible outputs
 * 
 * @tparam T The data type of the values of each string. Must implement `==`.
*/
template<typename T>
void longest_common_subsequence(
        const std::vector<T>& input0,
        const std::vector<T>& input1,
        std::vector<typename std::vector<T>::size_type>& output) {
    typedef typename std::vector<T>::size_type SizeType;
    typedef char PreviousDirectionType;
    const PreviousDirectionType kUp   = 0;
    const PreviousDirectionType kLeft = 1;
    const PreviousDirectionType kDiag = 2;
    SizeType input0_size = input0.size();
    SizeType input1_size = input1.size();
    std::vector<std::vector<PreviousDirectionType>> previous(
            input0_size + 1, std::vector<PreviousDirectionType>(input1_size + 1));
    std::vector<SizeType> length_cur(input1_size + 1, 0);
    std::vector<SizeType> length_prev(input1_size + 1, 0);
    SizeType i, j;
    for (i = 1; i <= input0_size; ++i) {
        for (j = 1; j <= input1_size; ++j) {
            if (input0[i - 1] == input1[j - 1]) {
                previous[i][j] = kDiag;
                length_cur[j]  = length_prev[j - 1] + 1;
            } else {
                if (length_cur[j - 1] < length_prev[j]) {
                    previous[i][j] = kUp;
                    length_cur[j]  = length_prev[j];
                } else {
                    previous[i][j] = kLeft;
                    length_cur[j]  = length_cur[j - 1];
                }
            }
        }
        length_prev = length_cur;
    }
    output = std::vector<SizeType>(length_cur[input1_size]);
    i = input0_size;
    j = input1_size;
    auto it = output.rbegin();
    while (it != output.rend()) {
        switch (previous[i][j]) {
            case kLeft: {
                --j;
                break;
            }
            case kUp: {
                --i;
                break;
            }
            case kDiag: {
                *it = input0[i - 1];
                ++it;
                --i;
                --j;
                break;
            }
        }
    }
}

int main() {
    typedef int InputType;
    typedef std::vector<std::vector<InputType>::size_type> OutputType;
    typedef std::tuple<std::vector<InputType>,
                       std::vector<InputType>,
                       OutputType> IO;
    IO in_outs[]{
        IO{
            {0},
            {0},
            {0},
        },
        IO{
            {0},
            {1},
            {},
        },
        IO{
            {2, 0, 1},
            {0, 2, 1, 0, 3},
            {0, 1},
        },
    };
    OutputType output;
    for (auto& in_out : in_outs) {
        auto& input0           = std::get<0>(in_out);
        auto& input1           = std::get<1>(in_out);
        auto& expected_output  = std::get<2>(in_out);
        longest_common_subsequence(input0, input1, output);
        assert(output == expected_output);
    }
}