题目
Ksenia 非常喜欢读书,因此每天她都会从自己最喜欢的书中选取一段内容进行阅读,然后再开始她早晨的其他活动。
一段内容可以看作是整个文本中的一个子字符串。
Ksenia 有点迷信,她坚信如果阅读的这段内容是以字符串 KICK
开头,然后中间包含 0 个或更多个字符,最后以字符串 START
结尾,即使这段内容没什么意义,她的一天也会非常的幸运。
给定这本书的全部文本内容,请你数一数在这本书变得破旧不堪,Ksenia 不得不再买新书之前,共有多少个幸运片段可供她阅读。
只要两个片段的起始位置或结束位置不同,就认为这两个片段是不同的,即使它们包含的内容完全相同。
还需注意,不同片段之间可能会有重叠部分。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据共一行,包含一个仅由大写字母构成的字符串 S。
输出格式
每组数据输出一个结果,每个结果占一行。
结果表示为 Case #x: y
,其中 x 为组别编号(从 1 开始),y 为幸运片段的数量。
数据范围
1 ≤ T ≤ 100,
1 ≤ |S| ≤ 105
输入样例:
3
AKICKSTARTPROBLEMNAMEDKICKSTART
STARTUNLUCKYKICK
KICKXKICKXSTARTXKICKXSTART
输出样例:
Case #1: 3
Case #2: 0
Case #3: 5
解题思路
题目要求求 “KICK” 和 “START” 的对的数量,且必须 “KICK” 在前,“START” 在后;
- 对于每个 “START” ,只有在 “START” 前的 “KICK” 才能与之配对,且配对数量等于该 “START” 前的 “KICK” 的数量,即每遇到一个 “KICK”,“KICK”计数加一;
- “KICK” 和 “START” 的对的数量只需要将每个 “START” 可以配对的数量进行加总即可,即每遇到一个 “START” ,就在总数上加上当前位置前的 “KICK” 数;
- 查找 “KICK” 和 “START” 可以直接调用 substr() 函数或使用字符数组每位进行对比;
- 注意:“KICK” 末位的 “K” 也可以作为 “KICK” 的首位,所以当遇到 “KICK” 跳过部分字符时,不可以将末位的 “K” 跳过。
AC代码
Java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
InputReader in = new InputReader(System.in);
PrintWriter out = new PrintWriter(System.out);
int t = in.nextInt();
int res = 0; // 当前的“KICK”“START”对的数量
int cnt = 0; // 当前位置前的“KICK”数量
char[] ch;
for(int i = 1; i <= t; i++) {
ch = in.next().toCharArray();
res = 0;
cnt = 0;
for(int j = 0; j + 4 < ch.length; j++) {
if(ch[j] == 'K' && ch[j + 1] == 'I' && ch[j + 2] == 'C' && ch[j + 3] == 'K') {
cnt++; // 当前位置前的“KICK”数量加一
j += 2; // 因为末位也是‘K’,所以只需后移两位
}
else if(ch[j] == 'S' && ch[j + 1] == 'T' && ch[j + 2] == 'A' && ch[j + 3] == 'R' && ch[j + 4] == 'T') {
res += cnt; // 当前的“START”一共能和“KICK”组成 cnt 对
j += 4;
}
}
out.println("Case #" + i + ": " + res);
}
out.flush();
}
public static class InputReader {
BufferedReader reader;
StringTokenizer tokenizer;
public InputReader(InputStream in) {
reader = new BufferedReader(new InputStreamReader(in));
}
public String next() throws IOException {
while(tokenizer == null || !tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
public int nextInt() throws IOException {
return Integer.parseInt(next());
}
}
}
c++
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t = 0;
cin >> t;
string s;
int res = 0; // 当前的“KICK”“START”对的数量
int cnt = 0; // 当前位置前的“KICK”数量
for(int i = 1; i <= t; i++)
{
cin >> s;
res = 0;
cnt = 0;
for(int j = 0; j + 4 < s.size(); j++)
{
if(s.substr(j, 4) == "KICK")
{
cnt++; // 当前位置前的“KICK”数量加一
j += 2; // 因为末位也是‘K’,所以只需后移两位
}
else if(s.substr(j, 5) == "START")
{
res += cnt; // 当前的“START”一共能和“KICK”组成 cnt 对
j += 4;
}
}
cout << "Case #" << i << ": " << res << endl;
}
return 0;
}