乒乓球

思路

拿到这道题,先理解一下规则:给你一串由 'W' 和 'L' 组成的比赛记录,要你分别用 11 分制和 21 分制来模拟,输出每一局的比分。

那什么时候一局结束呢?两个条件同时满足:

  1. 某一方的分数 不小于 目标分数(11 或 21)
  2. 双方比分差 至少为 2

想到这里,是不是觉得其实就是一个简单的模拟?没错,遍历字符串,维护双方得分,每次检查是否满足结局条件就行了。

需要注意什么?

有个小坑:如果字符串读完了但当前这局还没打完(比分差不够 2,或者还没到目标分),也要输出当前比分。这个容易漏掉。

还有输出格式——11 分制输出完之后要有一个空行,再输出 21 分制的结果。

实现步骤

  1. 读入字符串
  2. 分别对 11 分制和 21 分制做一遍模拟:

- 维护 w(旺仔得分)和 l(对手得分)

- 遇到 'W' 就 w++,遇到 'L' 就 l++

- 每次加分后检查:如果 max(w, l) >= target|w - l| >= 2,输出比分并重置

  1. 遍历完后输出剩余未结束的比分
  2. 两种制式之间输出空行

整个思路非常直白,就是按规则一步步模拟。

代码

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    cin >> s;

    for (int target : {11, 21}) {
        int w = 0, l = 0;
        for (char c : s) {
            if (c == 'W') w++;
            else l++;
            if ((w >= target || l >= target) && abs(w - l) >= 2) {
                cout << w << ":" << l << endl;
                w = 0;
                l = 0;
            }
        }
        cout << w << ":" << l << endl;
        if (target == 11) cout << endl;
    }

    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();

        int[] targets = {11, 21};
        for (int t = 0; t < 2; t++) {
            int target = targets[t];
            int w = 0, l = 0;
            for (int i = 0; i < s.length(); i++) {
                if (s.charAt(i) == 'W') w++;
                else l++;
                if ((w >= target || l >= target) && Math.abs(w - l) >= 2) {
                    System.out.println(w + ":" + l);
                    w = 0;
                    l = 0;
                }
            }
            System.out.println(w + ":" + l);
            if (t == 0) System.out.println();
        }
    }
}
s = input()

for target in [11, 21]:
    w = 0
    l = 0
    for c in s:
        if c == 'W':
            w += 1
        else:
            l += 1
        if (w >= target or l >= target) and abs(w - l) >= 2:
            print(f"{w}:{l}")
            w = 0
            l = 0
    print(f"{w}:{l}")
    if target == 11:
        print()
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line));
rl.on('close', () => {
    const s = lines[0];
    const output = [];

    for (const target of [11, 21]) {
        let w = 0, l = 0;
        for (const c of s) {
            if (c === 'W') w++;
            else l++;
            if ((w >= target || l >= target) && Math.abs(w - l) >= 2) {
                output.push(w + ":" + l);
                w = 0;
                l = 0;
            }
        }
        output.push(w + ":" + l);
        if (target === 11) output.push("");
    }

    console.log(output.join("\n"));
});

复杂度分析

  • 时间复杂度: ,遍历两遍字符串,每遍
  • 空间复杂度: ,存储输入字符串

总结

这题就是纯模拟,没有什么复杂的算法。关键是把乒乓球的计分规则理清楚——达到目标分且领先 2 分才算赢一局。代码写起来很短,遍历字符串、计数、判断、输出,一气呵成。唯一要留心的就是字符串结束时未完成的那局别忘了输出,以及两种制式之间的空行格式。