《算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。
每日一题汇总:http://oj.ecustacm.cn/viewnews.php?id=1023
“ 村庄与部落” ,链接: http://oj.ecustacm.cn/problem.php?id=1823
题目描述
【题目描述】 n个村庄坐落成一条直线,A和B两个部落生活在这里。
每个村庄要么无人居住,要么被两个部落之一所占据。
如果一个无人居住的村庄两侧都是被部落A占据的村庄,那么这个村庄也视作被部落A占据;部落B亦同。
请求出被部落A和B分别占据的村庄个数。
【输入格式】 第一行为正整数T,表示存在T组测试数据,1≤T≤20。
每组测试数据输入一行,包含一个字符串s,表示每个村庄的状态,|s|≤100000
字符串仅包含A、B、. 三种字符,分别表示被部落A占据、被部落B占据,以及无人居住。
【输出格式】 每组测试数据输出两个整数,分别表示被部落A和B控制的村庄数量。
【输入样例】
4
A..A..B...B
..A..
A....A
..B..B..B..
【输出样例】
4 5
1 0
6 0
0 7
题解
这是典型的尺取法题目,用“快慢指针”对字符串做同向扫描,扫描过程中计算答案。设定两个指针i和j,其中快指针i在前,慢指针j在后。代码的步骤和逻辑是:
(1)i每次往前扫描一个新字符,直到遇到字符A或B;j在后,停留在后面的一个A或B上。
(2)若i、j指针指向的字符相同,例如都是A,那么统计A增加的村庄。
(3)若i、j指针指向的字符不同,例如i指向A,j指向B,那么A的村庄加1。
(4)在(2)、(3)之后,让j的新值等于i,开始下一轮的扫描。
【重点】 尺取法。
C++代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int T; cin >> T;
while(T--){
string s; cin >> s;
int ansA = 0, ansB = 0;
int j = -1; //j是慢指针,初始值-1
for(int i = 0; i < s.size(); i++) { //i是快指针,从第一个字符s[0]开始扫描
if(s[i] != '.') { //i停在A或B上
if(j != -1 && s[j] == s[i]) {
if(s[i] == 'A') ansA += i - j;
else ansB += i - j;
}
else if(s[i] == 'A') ansA++;
else ansB++;
j = i; //这一轮计算结束,开始下一轮
}
}
cout<<ansA<<" "<<ansB<<endl;
}
return 0;
}
Java代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
while (T-- > 0) {
String s = sc.next();
int ansA = 0, ansB = 0;
int j = -1;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != '.') {
if (j != -1 && s.charAt(j) == s.charAt(i)) {
if (s.charAt(i) == 'A') ansA += i - j;
else ansB += i - j;
}
else if (s.charAt(i) == 'A') ansA++;
else ansB++;
j = i;
}
}
System.out.println(ansA + " " + ansB);
}
sc.close();
}
}
Python代码
T = int(input())
for _ in range(T):
s = input()
ansA, ansB = 0, 0
j = -1 #j是慢指针,初始值-1
for i in range(len(s)): #i是快指针,从第一个字符s[0]开始扫描
if s[i] != '.': #i停在A或B上
if j != -1 and s[j] == s[i]:
if s[i] == 'A': ansA += i - j
else: ansB += i - j
elif s[i] == 'A': ansA += 1
else: ansB += 1
j = i #这一轮计算结束,开始下一轮
print(ansA, ansB)