Skip to content

C++ source code

Brute force

不记录具体操作

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int min(int a, int b, int c)
{
    return min(a, min(b, c));
}

int minDistance(string &word1, size_t index1, string &word2, size_t index2)
{
    if (index1 == -1)
    {
        return index2 + 1;
    }
    if (index2 == -1)
    {
        return index1 + 1;
    }
    int distance = 0;
    if (word1[index1] == word2[index2])
    {
        return minDistance(word1, index1 - 1, word2, index2 - 1);
    }
    else
    {
        return min(minDistance(word1, index1, word2, index2 - 1) + 1, // 增
        minDistance(word1, index1 - 1, word2, index2) + 1, // 删
        minDistance(word1, index1 - 1, word2, index2 - 1) + 1 // 改
                        );
    }
}

int minDistance(string word1, string word2)
{
    return minDistance(word1, word1.size() - 1, word2, word2.size() - 1);
}

int main()
{
    string word1 = "horse", word2 = "ros";
    cout << minDistance(word1, word2) << endl;
    word1 = "intention", word2 = "execution";
    cout << minDistance(word1, word2) << endl;
    word1 = "rad", word2 = "apple";
    cout << minDistance(word1, word2) << endl;
}
// g++ test.cpp -g

输出如下:

3
5
5

记录具体操作

#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <exception>
using namespace std;

/**
 * @brief 动态二维数组,便于记录解
 *
 * @tparam T
 */
template<typename T>
class TwoDimensionArray
{
public:
    TwoDimensionArray(std::size_t row, std::size_t col) :
                    m_row { row }, m_col { col }
    {
        m_data.resize(m_row * m_col);
    }
    T& at(std::size_t row_index, std::size_t col_index)
    {
        if (row_index < m_row && col_index < m_col)
        {
            return m_data[row_index * m_col + col_index];
        }
        else
        {
            std::stringstream s;
            s << "无效的索引:[" << row_index << "," << col_index << "]";
            throw std::logic_error(s.str());
        }
    }
private:

    std::size_t m_row { 0 }; // 行数
    std::size_t m_col { 0 }; // 列数
    std::vector<T> m_data;
};
// 0 代表啥都不做
// 1 代表插入
// 2 代表删除
// 3 代表替换
// nil 是初始值
enum Operation
{
    do_nothing = 0, insert, delete_operation, update, nil
};
static const char *OperationStrArray[] = { "do_nothing", "insert", "delete", "update" };
/**
 * @brief 记录解
 *
 */
struct Record
{
    int val { 0 }; // edit distance
    Operation choice { Operation::nil }; // 执行的操作
    Record(int v, Operation c) :
                    val { v }, choice { c }
    {
    }
    Record() = default;

};
bool operator >(const Record &left, const Record &right)
{
    return left.val > right.val;
}
bool operator==(const Record &left, const Record &right)
{
    return left.val == right.val;
}
bool operator<(const Record &left, const Record &right)
{
    return left.val < right.val;
}
Record min(Record a, Record b, Record c)
{
    return min(a, min(b, c));
}
/**
 * @brief 从solution中,跟踪出解
 *
 * @param Solution
 * @param index1
 * @param index2
 */
void TraceSolution(TwoDimensionArray<Record> &Solution, size_t index1, size_t index2)
{
    if (index1 == 0 && index2 == 0)
    {
        Record &r = Solution.at(index1, index2);
        std::cout << "在位置[" << index1 << "]处执行的操作为:" << OperationStrArray[r.choice] << std::endl;
        return;
    }
    else
    {
        Record &r = Solution.at(index1, index2);
        if (r.choice == Operation::delete_operation)
        {
            TraceSolution(Solution, index1 - 1, index2);
        }
        else if (r.choice == Operation::do_nothing)
        {
            TraceSolution(Solution, index1 - 1, index2 - 1);
        }
        else if (r.choice == Operation::insert)
        {
            TraceSolution(Solution, index1, index2 - 1);
        }
        else if (r.choice == Operation::update)
        {
            TraceSolution(Solution, index1 - 1, index2 - 1);
        }
        else
        {
            throw std::logic_error("进入到了不可能的分支");
        }
        std::cout << "在位置[" << index1 << "]处执行的操作为:" << OperationStrArray[r.choice] << std::endl;
    }

}

int minDistance(string &word1, size_t index1, string &word2, size_t index2, TwoDimensionArray<Record> &solution)
{
    if (index1 == -1)
    {
        return index2 + 1;
    }
    if (index2 == -1)
    {
        return index1 + 1;
    }
    if (word1[index1] == word2[index2])
    {
        int distance = minDistance(word1, index1 - 1, word2, index2 - 1, solution);
        Record &r = solution.at(index1, index2);
        r.choice = Operation::do_nothing;
        r.val = distance;
        return distance;
    }
    else
    {
        int AddDistance = minDistance(word1, index1, word2, index2 - 1, solution) + 1;  // 增
        Record AddNode { AddDistance, Operation::insert };
        int DeleteDistance = minDistance(word1, index1 - 1, word2, index2, solution) + 1; // 删
        Record DeleteNode { DeleteDistance, Operation::delete_operation };
        int UpdateDistance = minDistance(word1, index1 - 1, word2, index2 - 1, solution) + 1; // 改
        Record UpdateNode { UpdateDistance, Operation::update };
        Record MinimalNode = min(AddNode, DeleteNode, UpdateNode);
        solution.at(index1, index2) = MinimalNode;

        return MinimalNode.val;
    }
}

int minDistance(string word1, string word2)
{
    TwoDimensionArray<Record> Solution { word1.size(), word2.size() };
    int Res = minDistance(word1, word1.size() - 1, word2, word2.size() - 1, Solution);
    TraceSolution(Solution, word1.size() - 1, word2.size() - 1);
    std::cout << "[" << word1 << "]和[" << word2 << "]的最小编辑距离为:" << Res << std::endl;
    return Res;

}

int main()
{
    string word1 = "horse", word2 = "ros";
    minDistance(word1, word2);
    word1 = "intention", word2 = "execution";
    minDistance(word1, word2);
    word1 = "rad", word2 = "apple";
    minDistance(word1, word2);
}
// g++ --std=c++11 test.cpp

输出如下:

在位置[0]处执行的操作为:update
在位置[1]处执行的操作为:do_nothing
在位置[2]处执行的操作为:delete
在位置[3]处执行的操作为:do_nothing
在位置[4]处执行的操作为:delete
[horse][ros]的最小编辑距离为:3
在位置[0]处执行的操作为:update
在位置[1]处执行的操作为:update
在位置[2]处执行的操作为:delete
在位置[3]处执行的操作为:do_nothing
在位置[4]处执行的操作为:update
在位置[4]处执行的操作为:insert
在位置[5]处执行的操作为:do_nothing
在位置[6]处执行的操作为:do_nothing
在位置[7]处执行的操作为:do_nothing
在位置[8]处执行的操作为:do_nothing
[intention][execution]的最小编辑距离为:5
terminate called after throwing an instance of 'std::logic_error'
  what():  无效的索引:[0,18446744073709551615]
Aborted (core dumped)

Memoization

Dynamic programing

记录具体操作的

#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <exception>
using namespace std;

/**
 * @brief 动态二维数组,便于记录解
 *
 * @tparam T
 */
template<typename T>
class TwoDimensionArray
{
public:
    TwoDimensionArray(std::size_t row, std::size_t col) :
                    m_row { row }, m_col { col }
    {
        m_data.resize(m_row * m_col);
    }
    T& at(std::size_t row_index, std::size_t col_index)
    {
        if (row_index < m_row && col_index < m_col)
        {
            return m_data[row_index * m_col + col_index];
        }
        else
        {
            std::stringstream s;
            s << "无效的索引:[" << row_index << "," << col_index << "]";
            throw std::logic_error(s.str());
        }
    }
private:

    std::size_t m_row { 0 }; // 行数
    std::size_t m_col { 0 }; // 列数
    std::vector<T> m_data;
};
// 0 代表啥都不做
// 1 代表插入
// 2 代表删除
// 3 代表替换
// nil 是初始值
enum Operation
{
    do_nothing = 0, insert, delete_operation, update, nil
};
static const char *OperationStrArray[] = { "do_nothing", "insert", "delete", "update" };
/**
 * @brief 记录解
 *
 */
struct Record
{
    int val { 0 }; // edit distance
    Operation choice { Operation::nil }; // 执行的操作
    Record(int v, Operation c) :
                    val { v }, choice { c }
    {
    }
    Record() = default;

};
bool operator >(const Record &left, const Record &right)
{
    return left.val > right.val;
}
bool operator==(const Record &left, const Record &right)
{
    return left.val == right.val;
}
bool operator<(const Record &left, const Record &right)
{
    return left.val < right.val;
}
Record min(Record a, Record b, Record c)
{
    return min(a, min(b, c));
}
/**
 * @brief 从solution中,跟踪出解
 *
 * @param Solution
 * @param index1
 * @param index2
 */
void TraceSolution(TwoDimensionArray<Record> &Solution, size_t index1, size_t index2)
{
    if (index1 == 0 && index2 == 0)
    {
        Record &r = Solution.at(index1, index2);
        std::cout << "在位置[" << index1 << "]处执行的操作为:" << OperationStrArray[r.choice] << std::endl;
        return;
    }
    else
    {
        Record &r = Solution.at(index1, index2);
        if (r.choice == Operation::delete_operation)
        {
            TraceSolution(Solution, index1 - 1, index2);
        }
        else if (r.choice == Operation::do_nothing)
        {
            TraceSolution(Solution, index1 - 1, index2 - 1);
        }
        else if (r.choice == Operation::insert)
        {
            TraceSolution(Solution, index1, index2 - 1);
        }
        else if (r.choice == Operation::update)
        {
            TraceSolution(Solution, index1 - 1, index2 - 1);
        }
        else
        {
            throw std::logic_error("进入到了不可能的分支");
        }
        std::cout << "在位置[" << index1 << "]处执行的操作为:" << OperationStrArray[r.choice] << std::endl;
    }

}

int minDistance(string &word1, size_t index1, string &word2, size_t index2, TwoDimensionArray<Record> &solution)
{
    if (index1 == -1)
    {
        return index2 + 1;
    }
    if (index2 == -1)
    {
        return index1 + 1;
    }
    if (word1[index1] == word2[index2])
    {
        int distance = minDistance(word1, index1 - 1, word2, index2 - 1, solution);
        Record &r = solution.at(index1, index2);
        r.choice = Operation::do_nothing;
        r.val = distance;
        return distance;
    }
    else
    {
        int AddDistance = minDistance(word1, index1, word2, index2 - 1, solution) + 1;  // 增
        Record AddNode { AddDistance, Operation::insert };
        int DeleteDistance = minDistance(word1, index1 - 1, word2, index2, solution) + 1; // 删
        Record DeleteNode { DeleteDistance, Operation::delete_operation };
        int UpdateDistance = minDistance(word1, index1 - 1, word2, index2 - 1, solution) + 1; // 改
        Record UpdateNode { UpdateDistance, Operation::update };
        Record MinimalNode = min(AddNode, DeleteNode, UpdateNode);
        solution.at(index1, index2) = MinimalNode;

        return MinimalNode.val;
    }
}

int minDistance(string word1, string word2)
{
    std::size_t len1 = word1.size(), len2 = word2.size();
    TwoDimensionArray<Record> DPTable { len1 + 1, len2 + 1 };
    DPTable.at(0, 0) = { 0, Operation::do_nothing };

    /**
     * S1非空,S2为空,显然,直接删除S1即可
     */
    for (int i = 1; i <= len1; ++i)
    {
        DPTable.at(i, 0) = { i, Operation::delete_operation };
    }
    /**
     * S1空,S2非空,显然,直接插入S2即可
     */
    for (int j = 1; j <= len2; ++j)
    {
        DPTable.at(0, j) = { j, Operation::insert };
    }
    for (int i = 1; i <= len1; ++i)
        for (int j = 1; j <= len2; ++j)
        {
            if (word1[i - 1] == word2[j - 1])
            {
                DPTable.at(i, j) = { DPTable.at(i - 1, j - 1).val, Operation::do_nothing };
            }
            else
            {
                DPTable.at(i, j) = min( { DPTable.at(i - 1, j - 1).val + 1, Operation::update }, { DPTable.at(i - 1, j).val + 1, Operation::delete_operation }, { DPTable.at(i, j - 1).val + 1, Operation::insert });
            }
        }
    TraceSolution(DPTable, len1, len2);
    int Res = DPTable.at(len1, len2).val;
    std::cout << "[" << word1 << "]和[" << word2 << "]的最小编辑距离为:" << Res << std::endl;
    return Res;

}

int main()
{
    string word1 = "horse", word2 = "ros";
    minDistance(word1, word2);
    word1 = "intention", word2 = "execution";
    minDistance(word1, word2);
    word1 = "rad", word2 = "apple";
    minDistance(word1, word2);
}
// g++ --std=c++11 test.cpp

输出如下:

在位置[0]处执行的操作为:do_nothing
在位置[1]处执行的操作为:update
在位置[2]处执行的操作为:do_nothing
在位置[3]处执行的操作为:delete
在位置[4]处执行的操作为:do_nothing
在位置[5]处执行的操作为:delete
[horse][ros]的最小编辑距离为:3
在位置[0]处执行的操作为:do_nothing
在位置[1]处执行的操作为:update
在位置[2]处执行的操作为:update
在位置[3]处执行的操作为:update
在位置[4]处执行的操作为:update
在位置[5]处执行的操作为:update
在位置[6]处执行的操作为:do_nothing
在位置[7]处执行的操作为:do_nothing
在位置[8]处执行的操作为:do_nothing
在位置[9]处执行的操作为:do_nothing
[intention][execution]的最小编辑距离为:5
在位置[0]处执行的操作为:do_nothing
在位置[0]处执行的操作为:insert
在位置[0]处执行的操作为:insert
在位置[1]处执行的操作为:update
在位置[2]处执行的操作为:update
在位置[3]处执行的操作为:update
[rad][apple]的最小编辑距离为:5

不记录具体操作的、标准答案

#include <string>
#include <iostream>
using namespace std;

class Solution
{
public:
    int minDistance(string word1, string word2)
    {
        int n = word1.length();
        int m = word2.length();

        // 有一个字符串为空串
        if (n * m == 0)
            return n + m;

        // DP 数组
        int D[n + 1][m + 1];

        // 边界状态初始化
        for (int i = 0; i < n + 1; i++)
        {
            D[i][0] = i;
        }
        for (int j = 0; j < m + 1; j++)
        {
            D[0][j] = j;
        }

        // 计算所有 DP 值
        for (int i = 1; i < n + 1; i++)
        {
            for (int j = 1; j < m + 1; j++)
            {
                int left = D[i - 1][j] + 1;
                int down = D[i][j - 1] + 1;
                int left_down = D[i - 1][j - 1];
                if (word1[i - 1] != word2[j - 1])
                    left_down += 1;
                D[i][j] = min(left, min(down, left_down));

            }
        }
        return D[n][m];
    }
};

int main()
{
    Solution s;
    string word1 = "horse", word2 = "ros";
    std::cout << s.minDistance(word1, word2) << std::endl;
    word1 = "intention", word2 = "execution";
    std::cout << s.minDistance(word1, word2) << std::endl;
    word1 = "rad", word2 = "apple";
    std::cout << s.minDistance(word1, word2) << std::endl;
}