文章目录
前言
本来上完晚课回来要写的,但是看舍友在打麻将,就玩了一个小时麻将,写完都12点了。。
麻将挺好玩的,下次不玩了……
1. 一次编辑
1.1 动态规划:编辑距离
直接用编辑距离的模板:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
−
1
]
[
j
−
1
]
+
d
i
f
f
,
d
p
[
i
−
1
]
[
j
]
+
1
,
d
p
[
i
]
[
j
−
1
]
+
1
)
dp[i][j] = min(dp[i - 1][j - 1] + diff,dp[i - 1][j] + 1, dp[i][j - 1] + 1)
dp[i][j]=min(dp[i−1][j−1]+diff,dp[i−1][j]+1,dp[i][j−1]+1)
class Solution {
public:
bool oneEditAway(string first, string second) {
int n = first.size();
int m = second.size();
if (n == 0 && m == 0) return true;
if (abs(n - m) > 2) return false;
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; i++) {
dp[i][0] = i;
}
for (int i = 1; i <= m; i++) {
dp[0][i] = i;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int diff = first[i - 1] != second[j - 1];
dp[i][j] = min(dp[i - 1][j - 1] + diff,
min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
}
}
return dp[n][m] <= 1;
}
};
1.2 优秀的解法:分类讨论
- 如果长度相同,遍历字符串,如果有两个及以上不同就报错;
- 如果长度差1,遍历字符串,如果有不同,长的加一,有两处以上不同就报错;
- 其他长度直接寄
class Solution {
public:
bool oneEditAway(string first, string second) {
int m = first.size(), n = second.size();
if (n - m == 1) {
return oneInsert(first, second);
} else if (m - n == 1) {
return oneInsert(second, first);
} else if (m == n) {
bool foundDifference = false;
for (int i = 0; i < m; i++) {
if (first[i] != second[i]) {
if (!foundDifference) {
foundDifference = true;
} else {
return false;
}
}
}
return true;
} else {
return false;
}
}
bool oneInsert(string shorter, string longer) {
int length1 = shorter.size(), length2 = longer.size();
int index1 = 0, index2 = 0;
while (index1 < length1 && index2 < length2) {
if (shorter[index1] == longer[index2]) {
index1++;
}
index2++;
if (index2 - index1 > 1) {
return false;
}
}
return true;
}
};
2. 丑数 II
2.1 动态规划
第i个丑数是当前的dp2 * 2, dp3 * 3, dp4 * 5中的最小值,然后对应的dp指向的数组下标加一。
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> v(n);
int count = 1;
v[0] = 1;
int dp2 = v[0];
int dp3 = v[0];
int dp5 = v[0];
int p2 = 0, p3 = 0, p5 = 0;
while (count < n) {
int curMin = min(dp2 * 2, min(dp3 * 3, dp5 * 5));
v[count] = curMin;
if (curMin == dp2 * 2) dp2 = v[++p2];
if (curMin == dp3 * 3) dp3 = v[++p3];
if (curMin == dp5 * 5) dp5 = v[++p5];
count++;
}
return v[n - 1];
}
};
3. 不同的二叉搜索树
3.1 动态规划
当值为i的时候,除了root外会挂i-1个子节点,那么有可能是一边挂i-1个,一边挂0个;一边挂i-2个,一边挂1个……地推公式:
-
d
p
[
i
]
=
2
∗
Σ
d
p
[
i
−
j
−
1
]
∗
d
p
[
j
]
dp[i] = 2 * Σdp[i - j - 1] * dp[j]
dp[i]=2∗Σdp[i−j−1]∗dp[j]
其中i-j-1与j不能相等,因为相等的情况下出现了重复计算,所以相等时只加上一倍的乘积,注意到这点就没啥了……
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
int getCount(int i, vector<int>& dp) {
int ans = 2 * dp[i];
// if ()
int l = 1;
int r = i - 1;
while (l <= r) {
int left = dp[l];
int right = dp[r];
if (l == r) ans += left * right;
else ans += 2 * left * right;
l++;
r--;
}
return ans;
}
int numTrees(int n) {
vector<int> dp(n + 1);
dp[1] = 1;
if (n == 1) return 1;
for (int i = 2; i <= n; i++) {
dp[i] = getCount(i - 1, dp);
}
return dp[n];
}
};
总结
丑数想了很久,终于想出来了,很开心!