Algorithms-UCSanDiego

Data Structures and Algorithms by UCSanDiego

View project on GitHub

4. Longest Common Subsequence

Problem

Solutions

CPP

    #include <iostream>
    #include <sstream>
    #include <iterator>
    #include <algorithm>
    #include <string>
    #include <vector>
    #include <unordered_map>
    #include <cassert>

    using namespace std;

    using Collection = vector< int >;

    namespace TopDown {
        class Solution {
        public:
            using PII = pair< int,int >;
            struct Hash {
                size_t operator()( const PII& p ) const {
                    return 101 * p.first + p.second;
                }
            };
            using Memo = unordered_map< PII, int, Hash >;
            int lcs( const Collection& A, const Collection& B, Memo memo={} ){
                auto M = static_cast< int >( A.size() ),
                     N = static_cast< int >( B.size() );
                return go( A, B, M-1, N-1, memo );
            }
        private:
            int go( const Collection& A, const Collection& B, int i, int j, Memo& memo ){
                if( memo.find({ i,j }) != memo.end() )
                    return memo[{ i,j }];
                if( i < 0 || j < 0 )
                    return memo[{ i,j }] = 0;
                if( A[ i ] == B[ j ] )
                    return memo[{ i,j }] = 1 + go( A, B, i-1, j-1, memo );
                return memo[{ i,j }] =
                    max( go( A, B, i-1, j, memo ),
                         go( A, B, i, j-1, memo ));
            }
        };
    }
    namespace BottomUp {
        class Solution {
        public:
            using VI = vector< int >;
            using VVI = vector< VI >;
            int lcs( const Collection& A, const Collection& B ){
                auto M = static_cast< int >( A.size() ),
                     N = static_cast< int >( B.size() );
                VVI dp( M+1, VI( N+1, 0 ));
                for( auto i{ 1 }; i <= M; ++i )
                    for( auto j{ 1 }; j <= N; ++j )
                        if( A[ i-1 ] == B[ j-1 ] )
                            dp[ i ][ j ] = 1 + dp[ i-1 ][ j-1 ];
                        else
                            dp[ i ][ j ] = max( dp[ i-1 ][ j ], dp[ i ][ j-1 ] );
                return dp[ M ][ N ];
            }
        };
    }

    int main() {
        Collection A, B;
        auto M{ 0 }; cin >> M; copy_n( istream_iterator< int >( cin ), M, back_inserter( A ));
        auto N{ 0 }; cin >> N; copy_n( istream_iterator< int >( cin ), N, back_inserter( B ));
        auto ans1 = TopDown::Solution().lcs( A, B );
        auto ans2 = BottomUp::Solution().lcs( A, B );
        assert( ans1 == ans2 );
        cout << ans1 << endl;
        return 0;
    }

Python3

    from typing import List, Dict

    class RECSolution:
        Memo = Dict[ int,int ]
        def hash( self, i: int, j: int ) -> int:
            return 101 * i + j
        def lcs( self, A: List[int], B: List[int], M: int, N: int, memo: Memo={} ) -> int:
            return self.go( A, B, M-1, N-1, memo )
        def go( self, A: List[int], B: List[int], i: int, j: int, memo: Memo ) -> int:
            key = self.hash( i,j )
            if i < 0 or j < 0:
                memo[ key ] = 0
            if key in memo:
                return memo[ key ]
            if A[ i ] == B[ j ]:
                memo[ key ] = 1 + self.go( A, B, i-1, j-1, memo )
            else:
                memo[ key ] = max( self.go( A, B, i-1, j, memo ), self.go( A, B, i, j-1, memo ))
            return memo[ key ]

    class DPSolution:
        def lcs( self, A: List[int], B: List[int], M: int, N: int ) -> int:
            dp = [[ 0 ] * ( N+1 ) for _ in range( M+1 ) ]
            for i in range( 1, M+1 ):
                for j in range( 1, N+1 ):
                    if A[ i-1 ] == A[ j-1 ]:
                        dp[ i ][ j ] = 1 + dp[ i-1 ][ j-1 ]
                    else:
                        dp[ i ][ j ] = max( dp[ i-1 ][ j ], dp[ i ][ j-1 ] )
            return dp[ M ][ N ]

    if __name__ == '__main__':
        rec_solution = RECSolution()
        dp_solution = DPSolution()
        M, A = int( input() ), list( map( int, input().split() ))
        N, B = int( input() ), list( map( int, input().split() ))
        ans1 = rec_solution.lcs( A, B, M, N )
        ans2 = dp_solution.lcs( A, B, M, N )
        assert( ans1 == ans2 )
        print( ans1 )