赞
踩
确定状态表示 -> dp[i][j]
的含义
dp[i]j]
:p
的[0, j]
区间内的子串能否匹配s
的[0, i]
区间内的子串推导状态转移方程:根据最后一个位置的情况,分情况讨论
结论
推导过程
本题若直接按照如下的状态转移方程去写,时间复杂度会到 O ( N 3 ) O(N^3) O(N3)
所以需要想办法优化
优化:
方法一:数学推导
方法二:根据状态表示以及实际情况,优化状态转移方程 -> 抽象,难理解:(
*
,把状态传递给前面初始化:
确定填表顺序:从上往下,从左往右
确定返回值:dp[n][m]
bool isMatch(string s, string p) { int n = s.size(), m = p.size(); s = " " + s, p = " " + p; vector<vector<bool>> dp(n + 1, vector<bool>(m + 1)); // Init dp[0][0] = true; for(int i = 2; i <= m; i += 2) { if(p[i] == '*') { dp[0][i] = true; } else { break; } } // DP for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(p[j] == '*') { dp[i][j] = dp[i][j - 2] || (p[j - 1] == '.' || p[j - 1] == s[i]) && dp[i - 1][j]; } else { dp[i][j] = (p[j] == s[i] || p[j] == '.') && dp[i - 1][j - 1]; } } } return dp[n][m]; }
预处理:s1 = " " + s1, s2 = " " + s2, s3 = " " + s3
s1
和s2
的下标就计算到s3
的的下标思路:
确定状态表示 -> dp[i][j]
的含义
dp[i]j]
:s1
的[1, i]
区间内的字符串以及s2
的[1, j]
区间内的字符串,能否拼接凑成s3
的[1, i + j]
区间内的字符串推导状态转移方程:根据最后一个位置的情况,分情况讨论
初始化:
确定填表顺序:从上往下,从左往右
确定返回值:dp[n][m]
bool isInterleave(string s1, string s2, string s3) { int n = s1.size(), m = s2.size(); if(n + m != s3.size()) return false; s1 = " " + s1, s2 = " " + s2, s3 = " " + s3; vector<vector<bool>> dp(n + 1, vector<bool>(m + 1)); // Init dp[0][0] = true; for(int i = 1; i <= m; i++) // 第一行 { if(s2[i] == s3[i]) { dp[0][i] = true; } else { break; } } for(int i = 1; i <= n; i++) // 第一列 { if(s1[i] == s3[i]) { dp[i][0] = true; } else { break; } } // DP for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { dp[i][j] = (s1[i] == s3[i + j] && dp[i - 1][j]) || (s2[j] == s3[i + j] && dp[i][j - 1]); } } return dp[n][m]; }
确定状态表示 -> dp[i][j]
的含义
dp[i]j]
:s1
的[0, i]
区间以及s2
的[0, j]
区间内的所有的子序列里,公共子序列ASCII最大和推导状态转移方程:根据最后一个位置的情况,分情况讨论
初始化:vector<vector<int>> dp(n + 1, vector<int>(m + 1))
确定填表顺序:从上往下,从左往右
确定返回值:
sum
sum - dp[n][m] * 2
int minimumDeleteSum(string s1, string s2) { int n = s1.size(), m = s2.size(); vector<vector<int>> dp(n + 1, vector<int>(m + 1)); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); if(s1[i - 1] == s2[j - 1]) { dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + s1[i - 1]); } } } int ret = 0; for(auto& ch : s1) { ret += ch; } for(auto& ch : s2) { ret += ch; } return ret - dp[n][m] * 2; }
确定状态表示 -> dp[i][j]
的含义
dp[i]
:选取[0, i]
一段区间内的所有子数组 ×
dp[i][j]
:nums1[i]
中以i
位置元素为结尾的所有的子数组以及nums2
中以j
位置元素为结尾的所有的子数组中,最长重复子数组的长度推导状态转移方程:根据最后一个位置的情况,分情况讨论
初始化:vector<vector<int>> dp(n + 1, vector<int>(m + 1))
确定填表顺序:从上往下
确定返回值:dp
表里面的最大值
int findLength(vector<int>& nums1, vector<int>& nums2) { int n = nums1.size(), m = nums2.size(); vector<vector<int>> dp(n + 1, vector<int>(m + 1)); int ret = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(nums1[i - 1] == nums2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; ret = max(ret, dp[i][j]); } } } return ret; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。