题目链接:https://www.acwing.com/problem/content/4385/
1. 题解(4382. 快速打字)
y总视频讲解:https://www.acwing.com/video/4743/
类似题目:AcWing 2816. 判断子序列
1.1 双指针:判断子序列 ⭐
时间复杂度O(n),空间复杂度O(1)
【解题思路】:
该题要求我们在字符串 P 中删除某些字符,使 P 成为 I,转念一想,这不就是想找一下字符串 P 中是否存在与字符串 I 一一与之对应的字符。而只要我们想通了这个,那么一切就仿佛迎刃而解了,根据题眼,我们可知字符串 P 的长度是大于等于字符串 I 的长度的,那么如果在字符串 P 中存在字符串 I 这么一个子序列,那么想要使得 P 成为 I,只需要删除掉 P 中没有与 I 对应的字符即可,那么这个删除数即为 P 的长度 减去 I 的长度。(具体示意如上图所示)
……
【实现策略】:
- 创建双指针元素,从0开始遍历 I 和 P;
- 当在 P 中找到与 I 对应的字符后,让指向字符串 I 的指针 i++;
- 无论是否找到对应字符,j 都++;
- 循环结束,判断 i 指针是否已经遍历字符串 I 的末尾,如果是,则说明字符串 P 中存在 I 这么一个子序列,如果不是,则返回 “IMPOSSIBLE”,无论如何删除,字符串 P 都不可能变成 I。
import java.util.*;
class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = Integer.parseInt(sc.nextLine());
int n = 1;
while(n <= T) {
char[] I = sc.nextLine().toCharArray();
char[] P = sc.nextLine().toCharArray();
int i = 0, p = 0; // 双指针
int del = 0;
while (i < I.length && p < P.length) { // P的长度大于等于I的长度
if (I[i] != P[p++]) del++;
else i++;
}
if (i == I.length) System.out.printf("Case #%d: %d\n", n, P.length - p + del);
else System.out.printf("Case #%d: IMPOSSIBLE\n", n);
n++;
}
}
}
看完题解后的精简代码:
import java.util.*;
class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = Integer.parseInt(sc.nextLine());
for (int cases = 1; cases <= T; cases++) {
char[] I = sc.nextLine().toCharArray();
char[] P = sc.nextLine().toCharArray();
int n = I.length;
int m = P.length;
int i = 0, j = 0; // 双指针
while (i < n && j < m) {
if (I[i] == P[j]) i++; // i指针只有在相等时才会增加
j++; // 不管如何,j指针都会增加
}
System.out.printf("Case #%d: ", cases);
if (i == n) System.out.printf("%d\n", m - n); // 当i指针走到了最后,说明P中经删除必有满足I序列的字符串,因此需要删除的字符数也应为 m - n
else System.out.printf("IMPOSSIBLE\n");
}
}
}