即尋找兩個字符串之間的編輯距離。編輯距離定義:函數
編輯距離是針對二個字符串(例如英文字)的差別程度的量化量測,量測方式是看至少須要多少次的處理才能將一個字符串變成另外一個字符串。
如:kitten
和sitting
的最小編輯距離是3。spa
經典動態規劃問題。將長度爲m
字符串S
變成長度爲n
字符串T
,其狀態轉移方程爲:code
$$ f(i,j) = \begin{cases} \sum_{k=1}^i CostOfDel(T_k) & \text{if $j = 0$ } \\[2ex] \sum_{k=1}^j CostOfIns(S_k) & \text{if $i = 0$ } \\[2ex] min \begin{cases} f(i-1,j)+CostOfDel(T_i) \\[2ex] f(i,j-1)+CostOfIns(S_j) \\[2ex] f(i-1,j-1)+CostOfSub(S_j,T_i) & \text{if $S_j \neq T_i$ } \\[2ex] f(i-1,j-1) & \text{if $S_j = T_i$ } \\[2ex] \end{cases} & \text{ others } \\[2ex] \end{cases} $$ip
f(i,j)
表明字符串S
的長度爲j
的前綴子串變成字符串T
的長度爲i
的前綴子串的最小編輯代價。leetcode
答案即f(n,m)
。狀態數mn
個,狀態轉移複雜度O(1)
,所以時間複雜度爲O(mn)
,空間複雜度爲O(min(m,n))
。
此題中全部Cost*
函數的返回值都是1
。則狀態轉移方程可簡化爲字符串
$$ f(i,j) = \begin{cases} i & \text{if $j = 0$ } \\[2ex] j & \text{if $i = 0$ } \\[2ex] f(i-1,j-1) & \text{if $S_j = T_i$ } \\[2ex] min \begin{cases} f(i-1,j)+1 \\[2ex] f(i,j-1)+1 \\[2ex] f(i-1,j-1)+1 \\[2ex] \end{cases} & \text{if $S_j \neq T_i$ } \\[2ex] \end{cases} $$get
#include <algorithm> class Solution { typedef int len_type; public: int minDistance(const string& src, const string& dest) { if (dest.size() > src.size()) { return minDistance(dest, src); } if (!dest.size()) return src.size(); if (!src.size()) return dest.size(); len_type len_src = src.size(), len_dest = dest.size(); len_type* const pc = new len_type[len_dest]; char c = src[0]; pc[0] = (c != dest[0]); for (len_type j = 1; j < len_dest; ++j) pc[j] = std::min((c != dest[j]) + j, pc[j - 1] + 1); for (len_type i = 1; i < len_src; ++i) { char c = src[i]; len_type lastj = pc[0]; pc[0] = std::min((c != dest[0]) + i, lastj + 1); for (len_type j = 1; j < len_dest; ++j) { len_type samej = pc[j]; pc[j] = std::min((c != dest[j]) + lastj, std::min(pc[j - 1], samej) + 1); lastj = samej; } } len_type dist = pc[len_dest - 1U]; delete [] pc; return dist; } };
主要應用了動態規劃的思想。string