最长公共前缀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class LCP { vector<vector<int>> dp; public: LCP(const string& s) { dp.resize(s.size()+1, vector<int>(s.size()+1)); for(int j=s.size()-1;j>=0;j--) { for(int i=j;i>=0;i--) { dp[i][j]=(s[i]==s[j]?dp[i+1][j+1]+1:0); } } }
int operator()(int i, int j) const { return dp[min(i,j)][max(i,j)]; } };
|
这个算法本身本身就是动态规划,并不难,而有时这个问题会嵌套于另一个问题里,使整体变得略复杂,而如果能想到LCP问题可以用O(n^2)预处理,则复杂问题迎刃而解。
6195. 对字母串可执行的最大删除数 - 力扣(LeetCode)
一个朴素的解法是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: int deleteString(string s) { int n = s.size(); vector<int> dp(n, 1); for(int i=n-2;i>=0;i--) { for(int j=1;j<=(n-i)/2;j++) { if(memcmp(&s[i], &s[i+j], j) == 0) { dp[i] = max(dp[i], 1+dp[i+j]); } } } return dp[0]; } };
|
如果将memcmp(&s[i], &s[i+j], j)视为O(n)的复杂度,那么算法整体是O(n^3)复杂度。
但如果我们预处理得到s所有后缀的最长公共前缀的长度,就可以判断长度是否>=j来代替判断子串相等
从而把O(n3)的复杂度降到O(n2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: int deleteString(string s) { int n = s.size(); LCP lcp(s); vector<int> dp(n, 1); for(int i=n-2;i>=0;i--) { for(int j=1;j<=(n-i)/2;j++) { if(lcp(i, i+j)>= j) { dp[i] = max(dp[i], 1+dp[i+j]); } } } return dp[0]; } };
|