650. 只有两个键的键盘
class Solution {
public:
int minSteps(int n) {
// dp[i]表示,通过复制粘贴操作,得到 i 个字符,最少需要几步操作。
// 如果一个数是素数,那么最少操作就是一开始复制一个,最后一个个粘贴;
// 如果一个数不是素数,那么最少操作就可以按它的因数分解一下,简化操作。
// 其实可以发现,因子相同的情况下,交换因子相乘的顺序,需要的步骤是一样的。所以我们可以简化一下分解的步骤,只需要找到小于sqrt(n)的因子即可。
// 假设找到的因子是 j ,那么需要的最小步骤就是 dp[j] + dp[i/j],其中,dp[j]表示需要多少步生成这个因子,dp[i/j]表示需要多少步基于这个因子得到 i
if(n == 0 || n == 1){
return 0;
}
int dp[n+1]; // 表示第i次操作后最多能显示多少个A,次数最多就是复制一次,全部粘贴
memset(dp, 0, sizeof(dp));
int half = (int)sqrt(n);
for(int i = 2; i <= n; i++){
dp[i] = i;
for(int j = 2; j <= half; j++){
if(i % j == 0){
dp[i] = dp[j] + dp[i/j];
break;
}
}
}
return dp[n];
}
};
10. 正则表达式匹配
方法1: 递归
class Solution {
public:
bool isMatch(string s, string p) {
if(p.empty()) return s.empty();
bool first_match = !s.empty() && (s[0] == p[0] || p[0] == '.');
if(p.length()>1 && p[1]=='*'){
// 匹配0次,跳过该字符和* 或者 s[0] == p[0],移动text
return isMatch(s,p.substr(2)) || first_match && isMatch(s.substr(1),p);
}else{
return first_match && isMatch(s.substr(1),p.substr(1));
}
}
};
方法2:dp table
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.length();
int n = p.length();
bool dp[m+1][n+1]; // dp数组表示 前s[i] p[j]是否匹配
memset(dp, false, sizeof(dp));
dp[0][0] = true;
for(int i = 0; i <= m; i++){
for(int j = 1; j <= n; j++){
if(j > 1 && p[j-1] == '*'){ // 前一个是*,匹配0个或者多个
if(i > 0){
dp[i][j] = dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.');
}
dp[i][j] = dp[i][j] || dp[i][j-2];
}else if(i > 0){ // 匹配
dp[i][j] = dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.');
}
}
}
return dp[m][n];
}
};
class Solution {
public:
bool isMatch(string s, string p) {
s=" "+s;//防止该案例:""\n"c*"
p=" "+p;
int m=s.size(),n=p.size();
bool dp[m+1][n+1];
memset(dp,false,(m+1)*(n+1));
dp[0][0]=true;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(s[i-1]==p[j-1] || p[j-1]=='.'){
dp[i][j]=dp[i-1][j-1];
}
else if(p[j-1]=='*'){
if(s[i-1]!=p[j-2] && p[j-2]!='.')
dp[i][j]=dp[i][j-2];
else{
dp[i][j]=dp[i][j-1] || dp[i][j-2] || dp[i-1][j];
}
}
}
}
return dp[m][n];
}
};
44. 通配符匹配
这道题目跟上一道题目的思路是差不多的 dp的定义也是一样的
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.length();
int n = p.length();
bool dp[m+1][n+1]; // 表示 s 的前 i 个字符和 p 的前 j 个字符是否匹配 (true 的话表示匹配)
memset(dp, false, sizeof(dp));
// 初始化
dp[0][0] = true; // dp[0][0] 表示什么都没有,其值为 true
for (int i = 1; i <= n; i++) {
dp[0][i] = dp[0][i - 1] && p[i-1] == '*'; //第一行 dp[0][i],换句话说,s 为空,与 p 匹配,所以只要 p 开始为 * 才为 true
}
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
if(s[i-1] == p[j-1] || p[j-1] == '?'){
dp[i][j] = dp[i-1][j-1];
}else if(p[j-1] == '*'){
dp[i][j] = dp[i-1][j] || dp[i][j-1]; // *代表非空字符, *代表空字符
}
}
}
return dp[m][n];
}
};