Obtain The String题解
C. Obtain The String
You are given two strings \(s\) and \(t\) consisting of lowercase Latin letters. Also you have a string \(z\) which is initially empty. You want string \(z\) to be equal to string \(t\). You can perform the following operation to achieve this: append any subsequence of \(s\) at the end of string \(z\). A subsequence is a sequence that can be derived from the given sequence by deleting zero or more elements without changing the order of the remaining elements. For example, if \(z = ac\), \(s = abcde\) you may turn \(z\) into following strings in one operation:
- \(z=acace\) (if we choose subsequence \(ace\));
- \(z=acbcd\) (if we choose subsequence \(bcd\));
- \(z=acbce\) (if we choose subsequence \(bce\)).
Note that after this operation string \(s\) doesn't change.
Calculate the minimum number of such operations to turn string \(z\) into string \(t\)
Input
The first line contains the integer \((1≤T≤100)\) — the number of test cases.
The first line of each testcase contains one string \(s\) (\(1≤|s|≤10^5\)) consisting of lowercase Latin letters.
The second line of each testcase contains one string \(t\) (\(1≤|t|≤10^5\)) consisting of lowercase Latin letters.
It is guaranteed that the total length of all strings 𝑠s and 𝑡t in the input does not exceed \(2⋅10^5\).
Output
For each testcase, print one integer — the minimum number of operations to turn string \(z\) into string \(t\). If it's impossible print −1.
题目比较好理解,就是抽取一个字符串的子序列构成另一个字符串, 对于字符串 S 的子序列的特点是抽取的子序列是按照 S 的本身的顺序抽取的, 对于字符串的题目一般都会想到动态规划的方法,关键就是找好动态规划中的 \(dp[i][j]\) 最关键的是找好, i 与 j 分别代表什么,对于字符串,往往代表的无非是位置或者是字母本身对应的序号, 在这一题中可以这样写,
我们用 i 表示字符在字符串的下标, 然后用 j 表示字符(字母)对应的数字, 然后 \(dp[i][j]\) 表示的是从位置 i 向后, 第一次出现字符 j 的字符串 S 的下标,用动态规划构建这个二维数组也十分的方便,
for(i = length; i>=0; i--)
{
for(j = 0; j< 26; j++)
{
dp[i][j] = dp[i+1][j]; // 每一个下标和前一个下标相同
}
if(i == 0)
{
break; // 字符串数组的第一个位置是我们留出来的一个0,用于判断
}
dp[i][str[length] - 'a'] = i; // 改下标自己对应的字母需要改变
}
接下来就是贪心算法了, 我们可以将 Z 序列分成若干个 S 序列, 那么就是对于某个序列 \(S_i\) 我们从下标0开始找, 每次找离该下标最近的一个下标,包含 \(S[i][j]\) 字符的下标. 用代码表示就是
current = 0;
for(i = 1; i <= length2; i++)
{
int temp = zrt[i] - 'a';
if(dp[0][temp] == No_way) // 如果从 0 开始找不到,说明字符串没有该字符
{
result = -1;
break;
}
if(dp[current][temp] == No_way) // 如果从该下标current, 没有找到,说明要从头开始找,需要新的子序列, result ++;
{
result++;
current = 0;
}
current = dp[current][temp] + 1;
// 每次找到一个后,下一个下标就是当前下标之后的一个下标,
}