LeetCode / 97. 交错字符串

97. 交错字符串

题目

  • 给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。

例题

输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”

输出: true

输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”

输出: false

理解:字符串问题用动态规划,逐步思考和上一个字符串的关系

  • 字符串画表,进行路径规划

  • dp[i][j] = dp[i-1][j]&&s1[i-1]==s3[i+j-1] || dp[i][j-1]&&s2[j-1]==s3[i+j-1];

画表画表

解题

img1

  • 初始化列表
  • 路径规划——两条路径,前提条件的保证和选择
  • dp[i][j] = dp[i-1][j]&&s1[i-1]==s3[i+j-1] || dp[i][j-1]&&s2[j-1]==s3[i+j-1]

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool isInterleave(string s1, string s2, string s3) {
if (s1.size() + s2.size() != s3.size())
return false;

int n = s1.size();
int m = s2.size();
vector<vector<bool>>dp(n + 1, vector<bool>(m + 1, false));

dp[0][0] = true;
for (int i = 1; i < n + 1; i++) {
dp[i][0] = dp[i - 1][0] && s1[i - 1] == s3[i - 1];
}
for (int i = 1; i < m + 1; i++) {
dp[0][i] = dp[0][i - 1] && s2[i - 1] == s3[i - 1];
}

for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < m + 1; j++) {
dp[i][j] = dp[i - 1][j] && s1[i - 1] == s3[i + j - 1] ||
dp[i][j - 1] && s2[j - 1] == s3[i + j - 1];
}
}
return dp[n][m];
}

类似题目

416. 分割等和子集

题目

  • 给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

例题

输入: [1, 5, 11, 5]

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].

输入: [1, 2, 3, 5]

输出: false

解释: 数组不能分割成两个元素和相等的子集.

理解:让集合元素相加 target = sum / 2

  • 动态规划:对于依次使用集合中元素,考虑所有能组合成的可能性

  • dp[ i ][ j ] = dp[ i-1 ][ j ] || nums[ i ]==j || dp[ i-1 ][ j - nums[i]]

1.上可以,下不加也一定可以
2.当num[i] =j时也一定可以
3.当 j>nums[i]时,dp[i-1][j-nums[i]]也为真时,其也为真
画表画表
img1

  • 初始化列表
  • 路径规划——三种可能,前提条件的保证和选择
    代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
bool canPartition(vector<int>& nums) {
//求取target
int n = nums.size();
if (n <= 1)return false;

int sum = 0;
for (auto it : nums) {
sum += it;
}
if (sum % 2 == 1)return false;
int target = sum / 2;

vector<vector<bool>>dp(n, vector<bool>(target + 1, 0));
dp[0][0] = true;

//重要:可能会忽略这种情况
//第一行只有这种情况
if (nums[0] <= target) {
dp[0][nums[0]] = true;
}

for (int i = 1; i < n; i++) {
for (int j = 0; j < target + 1; j++) {

dp[i][j] = dp[i - 1][j];//1.对前值得继承
if (nums[i] <= j) {
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
} //三种情况:2.j-num[i]=0,肯定行
} // 3.再减去nums[i],也是行的
if (dp[i][target]) {
return true;
}

}
return dp[n - 1][target];
}

72. 编辑距离

题目:给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

  • 你可以对一个单词进行如下三种操作:
  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

例题
img1

解题

  • 三种移动方法:1.删除 2. 替换 3.插入

  • 删除和替换和插入操作数是一样的为1,但是当插入的新字符 = 对应字符,操作数为0

img1

  • 1.初始化 dp[i][0] = i;

  • 2.

  • int temp1 = dp[i-1][j] + 1;

  • int temp2 = dp[i][j-1] + 1;

  • int temp3 = dp[i-1][j-1];

  • if(word1[i-1]!= word2[j-1])temp3++;

  • dp[i][j] = min(temp1,min(temp2,temp3));

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int minDistance(string word1, string word2) {
//word1转换为word2
int len1 = word1.size();
int len2 = word2.size();

if (len1*len2 == 0)return max(len1, len2);

vector<vector<int>>dp(len1 + 1, vector<int>(len2 + 1));//都要+1 dp[0][0]

for (int i = 0; i < len1 + 1; i++) {
dp[i][0] = i;
}
for (int i = 0; i < len2 + 1; i++) {
dp[0][i] = i;
}
for (int i = 1; i < len1 + 1; i++) {
for (int j = 1; j < len2 + 1; j++) {
int temp1 = dp[i - 1][j] + 1;
int temp2 = dp[i][j - 1] + 1;
int temp3 = dp[i - 1][j - 1];
if (word1[i - 1] != word2[j - 1])
temp3++;
dp[i][j] = min(temp1, min(temp2, temp3));
}
}
return dp[len1][len2];
}

1143. 最长公共子串

题目
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。

例如,”ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。

  • 输入:text1 = “abcde”, text2 = “ace”
  • 输出:3
  • 解释:最长公共子序列是 “ace”,它的长度为 3。
  • 输入:text1 = “abc”, text2 = “def”
  • 输出:0
  • 解释:两个字符串没有公共子序列,返回 0。
  1. 初始化dp [0][ i ] = 0 dp [ j ][0] = 0
  2. dp方程

if(text1[ i-1 ]=text2[ j-1])

dp[ i ][ j ] = dp[i-1 ][ j-1 ] +1;

else

dp[ i ][ j ] = max(dp[i-1 ][ j ],dp[i ][ j-1 ];)
img1

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int longestCommonSubsequence(string text1, string text2) {
int m = text1.size();
int n = text2.size();
vector<vector<int>>dp(m + 1, vector<int>(n + 1, 0));
for (int i = 1; i < m + 1; i++) {
for (int j = 1; j < n + 1; j++) {
if (text1[i - 1] == text2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
}
}
return dp[m][n];
}

718.最长重复子数组

题目
给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
例题

  • 输入:
  • A: [1,2,3,2,1]
  • B: [3,2,1,4,7]
  • 输出:3
  • 解释:
  • 长度最长的公共子数组是 [3, 2, 1] 。
    img1
文章作者: Inter
文章链接: https://zuizichuan.cn/2020/07/18/leetcode4/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Zichuan365' Blog