Task: Word break problem


C++: #include <algorithm>
#include <iostream>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <vector>

struct string_comparator {
    using is_transparent = void;
    bool operator()(const std::string& lhs, const std::string& rhs) const {
        return lhs < rhs;
    }
    bool operator()(const std::string& lhs, const std::string_view& rhs) const {
        return lhs < rhs;
    }
    bool operator()(const std::string_view& lhs, const std::string& rhs) const {
        return lhs < rhs;
    }
};

using dictionary = std::set<std::string, string_comparator>;

template <typename iterator, typename separator>
std::string join(iterator begin, iterator end, separator sep) {
    std::string result;
    if (begin != end) {
        result += *begin++;
        for (; begin != end; ++begin) {
            result += sep;
            result += *begin;
        }
    }
    return result;
}

auto create_string(const std::string_view& s,
                   const std::vector<std::optional<size_t>>& v) {
    auto idx = s.size();
    std::vector<std::string_view> sv;
    while (v[idx].has_value()) {
        size_t prev = v[idx].value();
        sv.push_back(s.substr(prev, idx - prev));
        idx = prev;
    }
    std::reverse(sv.begin(), sv.end());
    return join(sv.begin(), sv.end(), ' ');
}

std::optional<std::string> word_break(const std::string_view& str,
                                      const dictionary& dict) {
    auto size = str.size() + 1;
    std::vector<std::optional<size_t>> possible(size);
    auto check_word = [&dict, &str](size_t i, size_t j)
            -> std::optional<size_t> {
        if (dict.find(str.substr(i, j - i)) != dict.end())
            return i;
        return std::nullopt;
    };
    for (size_t i = 1; i < size; ++i) {
        if (!possible[i].has_value())
            possible[i] = check_word(0, i);
        if (possible[i].has_value()) {
            for (size_t j = i + 1; j < size; ++j) {
                if (!possible[j].has_value())
                    possible[j] = check_word(i, j);
            }
            if (possible[str.size()].has_value())
                return create_string(str, possible);
        }
    }
    return std::nullopt;
}

int main(int argc, char** argv) {
    dictionary dict;
    dict.insert("a");
    dict.insert("bc");
    dict.insert("abc");
    dict.insert("cd");
    dict.insert("b");
    auto result = word_break("abcd", dict);
    if (result.has_value())
        std::cout << result.value() << '\n';
    return 0;
}







VB: Module Module1

    Structure Node
        Private ReadOnly m_val As String
        Private ReadOnly m_parsed As List(Of String)

        Sub New(initial As String)
            m_val = initial
            m_parsed = New List(Of String)
        End Sub

        Sub New(s As String, p As List(Of String))
            m_val = s
            m_parsed = p
        End Sub

        Public Function Value() As String
            Return m_val
        End Function

        Public Function Parsed() As List(Of String)
            Return m_parsed
        End Function
    End Structure

    Function WordBreak(s As String, dictionary As List(Of String)) As List(Of List(Of String))
        Dim matches As New List(Of List(Of String))
        Dim q As New Queue(Of Node)
        q.Enqueue(New Node(s))
        While q.Count > 0
            Dim node = q.Dequeue()
            REM check if fully parsed
            If node.Value.Length = 0 Then
                matches.Add(node.Parsed)
            Else
                For Each word In dictionary
                    REM check for match
                    If node.Value.StartsWith(word) Then
                        Dim valNew = node.Value.Substring(word.Length, node.Value.Length - word.Length)
                        Dim parsedNew As New List(Of String)
                        parsedNew.AddRange(node.Parsed)
                        parsedNew.Add(word)
                        q.Enqueue(New Node(valNew, parsedNew))
                    End If
                Next
            End If
        End While
        Return matches
    End Function

    Sub Main()
        Dim dict As New List(Of String) From {"a", "aa", "b", "ab", "aab"}
        For Each testString In {"aab", "aa b"}
            Dim matches = WordBreak(testString, dict)
            Console.WriteLine("String = {0}, Dictionary = {1}. Solutions = {2}", testString, dict, matches.Count)
            For Each match In matches
                Console.WriteLine(" Word Break = [{0}]", String.Join(", ", match))
            Next
            Console.WriteLine()
        Next

        dict = New List(Of String) From {"abc", "a", "ac", "b", "c", "cb", "d"}
        For Each testString In {"abcd", "abbc", "abcbcd", "acdbc", "abcdd"}
            Dim matches = WordBreak(testString, dict)
            Console.WriteLine("String = {0}, Dictionary = {1}. Solutions = {2}", testString, dict, matches.Count)
            For Each match In matches
                Console.WriteLine(" Word Break = [{0}]", String.Join(", ", match))
            Next
            Console.WriteLine()
        Next
    End Sub

End Module