{ }codelper
遍历字符串大小写包含判断P0269

用一只手打出的最长一段

用键盘打英文时,每个字母由哪只手打是固定的。
左手字母是 q w e r t a s d f g z x c v b 这 15 个,右手字母是 y u i o p h j k l n m 这 11 个。
大写字母和对应的小写字母用同一只手打。
不是英文字母的字符(数字、空格、标点)不属于任何一只手。
给出一行字符串。
字符串中由 1 个以上紧挨着、中间不夹其他字符的英文字母组成,且这些字母全都属于同一只手的部分,叫做单手段。
输出三行。
第一行输出最长单手段的长度。
第二行按输入中的原样(大小写也不变)输出这一段。
最长的段有多个时,输出最左边的那个。
如果一个英文字母都没有,第一行输出 0,第二行输出 "-"。
第三行输出紧挨着的两个字符都是英文字母、且属于不同手的位置个数。
两个英文字母之间只要夹着一个其他字符,这两个就不算紧挨着。

输入
一行,长度在 1 以上 100,000 以下。
只使用从空格(编码 32)到 ~(编码 126)的键盘字符。
行的前后可能有空格。
输出
三行:最长单手段的长度、那一段(没有则为 -)、换手位置的个数
样例 1 · stdin
Hello, minimum stewardess!
stdout
10
stewardess
2
样例 2 · stdin
Ab yo QAh
stdout
2
Ab
1
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

逐个字符遍历字符串,只需带着“前一个字符的手”和“在当前字符结束的段的长度”。
取出一个字符:Python、JS、TS、C#、Craykon 用 s[i],Java 用 s.charAt(i),C/C++ 用 s[i](C 是一个 char,其他语言是长度为 1 的字符串或 char)。
要忽略大小写,先用 Python ch.lower()、JS/TS toLowerCase()、Java Character.toLowerCase、C# char.ToLowerInvariant、C/C++ tolower、Craykon .小写() 转换,再到手的表里查。
查表的方法也不同:Python c in LEFT,JS/TS LEFT.includes(c),Java/C# LEFT.indexOf(c) >= 0(C# 是 IndexOf),C strchr,C++ find != npos,Craykon LEFT.包含(c)。
C 的 strchr 连末尾的 '\0' 也会找到,所以 strchr(LEFT, '\0') 也为真。
C 的解法先用 isalpha 问是不是英文字母,再去查手的表。
第一个陷阱是行尾。
只在段断开时才和最长的比较,会漏掉一直延续到行尾的最后一段。
每个字符都比较就没有这个问题。
第二,长度相同取最左边的,所以用 > 比较(用 >= 会留下右边的)。
第三,换手时新段从这个字符开始,长度是 1 而不是 0。
第四,把非字母当作“不是左手就是右手”,数字和空格会混进段里;把换手和“最后看到的字母”比较,会隔着空格也算进去。
输入行前后的空格不要删掉,原样读入(C 的 fgets 会连换行一起读入,只删掉它)。

Pythonmain.py · 34 行
LEFT = set("qwertasdfgzxcvb")RIGHT = set("yuiophjklnm") def hand(ch):    """영어 글자면 "L"·"R", 아니면 None. 대문자는 소문자로 바꿔 찾는다."""    c = ch.lower()    if c in LEFT:        return "L"    if c in RIGHT:        return "R"    return None s = input()best_len, best_start = 0, -1run = 0          # 지금 글자에서 끝나는 한 손 덩이의 길이switches = 0prev = None      # 바로 앞 글자의 손(글자가 아니면 None)for i, ch in enumerate(s):    h = hand(ch)    if h is None:        run = 0    elif h == prev:        run += 1    else:        if prev is not None:            switches += 1   # 바로 붙은 두 글자의 손이 다르다        run = 1             # 새 덩이는 이 글자부터    # 글자마다 견주면 줄 끝에서 끝나는 덩이도 놓치지 않는다. >라서 같으면 왼쪽 것이 남는다    if run > best_len:        best_len, best_start = run, i - run + 1    prev = hprint(best_len)print(s[best_start:best_start + best_len] if best_len else "-")print(switches)
JavaScriptmain.js · 21 行
const s = require("fs").readFileSync(0, "utf8").split("\n")[0].replace(/\r$/, "");const LEFT = "qwertasdfgzxcvb", RIGHT = "yuiophjklnm";// 영어 글자면 "L"·"R", 아니면 null. 대문자는 소문자로 바꿔 찾는다// (includes는 부분 문자열을 찾으니 빈칸·기호 한 글자도 들어갈 수 없게 글자 하나만 넘긴다)const hand = (ch) => {  const c = ch.toLowerCase();  return LEFT.includes(c) ? "L" : RIGHT.includes(c) ? "R" : null;};let bestLen = 0, bestStart = -1, run = 0, switches = 0, prev = null;for (let i = 0; i < s.length; i++) {  const h = hand(s[i]);  if (h === null) run = 0;  else if (h === prev) run++;  else {    if (prev !== null) switches++;    run = 1;  }  if (run > bestLen) { bestLen = run; bestStart = i - run + 1; } // 같으면 왼쪽 것  prev = h;}console.log(`${bestLen}\n${bestLen ? s.slice(bestStart, bestStart + bestLen) : "-"}\n${switches}`);
TypeScriptmain.ts · 23 行
import { readFileSync } from "node:fs";const s: string = readFileSync(0, "utf8").split("\n")[0].replace(/\r$/, "");const LEFT = "qwertasdfgzxcvb", RIGHT = "yuiophjklnm";type Hand = "L" | "R" | null;// 영어 글자면 "L"·"R", 아니면 null. 대문자는 소문자로 바꿔 찾는다const hand = (ch: string): Hand => {  const c = ch.toLowerCase();  return LEFT.includes(c) ? "L" : RIGHT.includes(c) ? "R" : null;};let bestLen = 0, bestStart = -1, run = 0, switches = 0;let prev: Hand = null;for (let i = 0; i < s.length; i++) {  const h: Hand = hand(s[i]);  if (h === null) run = 0;  else if (h === prev) run++;  else {    if (prev !== null) switches++;    run = 1;  }  if (run > bestLen) { bestLen = run; bestStart = i - run + 1; } // 같으면 왼쪽 것  prev = h;}console.log(`${bestLen}\n${bestLen ? s.slice(bestStart, bestStart + bestLen) : "-"}\n${switches}`);
JavaMain.java · 35 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    static final String LEFT = "qwertasdfgzxcvb", RIGHT = "yuiophjklnm";     // 영어 글자면 'L'·'R', 아니면 0. 대문자는 소문자로 바꿔 찾는다    static char hand(char ch) {        char c = Character.toLowerCase(ch);        if (LEFT.indexOf(c) >= 0) return 'L';        if (RIGHT.indexOf(c) >= 0) return 'R';        return 0;    }     public static void main(String[] args) throws IOException {        String s = new BufferedReader(new InputStreamReader(System.in)).readLine();        int bestLen = 0, bestStart = -1, run = 0, switches = 0;        char prev = 0;        for (int i = 0; i < s.length(); i++) {            char h = hand(s.charAt(i));            if (h == 0) run = 0;            else if (h == prev) run++;            else {                if (prev != 0) switches++;                run = 1;            }            if (run > bestLen) { bestLen = run; bestStart = i - run + 1; } // 같으면 왼쪽 것            prev = h;        }        System.out.println(bestLen);        System.out.println(bestLen > 0 ? s.substring(bestStart, bestStart + bestLen) : "-");        System.out.println(switches);    }}
C#Main.cs · 38 行
using System; class Program{    const string Left = "qwertasdfgzxcvb", Right = "yuiophjklnm";     // 영어 글자면 'L'·'R', 아니면 '\0'. 대문자는 소문자로 바꿔 찾는다    static char Hand(char ch)    {        char c = char.ToLowerInvariant(ch);        if (Left.IndexOf(c) >= 0) return 'L';        if (Right.IndexOf(c) >= 0) return 'R';        return '\0';    }     static void Main()    {        string s = Console.ReadLine();        int bestLen = 0, bestStart = -1, run = 0, switches = 0;        char prev = '\0';        for (int i = 0; i < s.Length; i++)        {            char h = Hand(s[i]);            if (h == '\0') run = 0;            else if (h == prev) run++;            else            {                if (prev != '\0') switches++;                run = 1;            }            if (run > bestLen) { bestLen = run; bestStart = i - run + 1; } // 같으면 왼쪽 것            prev = h;        }        Console.WriteLine(bestLen);        Console.WriteLine(bestLen > 0 ? s.Substring(bestStart, bestLen) : "-");        Console.WriteLine(switches);    }}
C++main.cpp · 33 行
#include <cctype>#include <iostream>#include <string> const std::string LEFT = "qwertasdfgzxcvb", RIGHT = "yuiophjklnm"; // 영어 글자면 'L'·'R', 아니면 0. 대문자는 소문자로 바꿔 찾는다char hand(char ch) {    char c = (char)std::tolower((unsigned char)ch);    if (LEFT.find(c) != std::string::npos) return 'L';    if (RIGHT.find(c) != std::string::npos) return 'R';    return 0;} int main() {    std::string s;    std::getline(std::cin, s);    if (!s.empty() && s.back() == '\r') s.pop_back();    int bestLen = 0, bestStart = -1, run = 0, switches = 0;    char prev = 0;    for (int i = 0; i < (int)s.size(); i++) {        char h = hand(s[i]);        if (h == 0) run = 0;        else if (h == prev) run++;        else {            if (prev != 0) switches++;            run = 1;        }        if (run > bestLen) { bestLen = run; bestStart = i - run + 1; } // 같으면 왼쪽 것        prev = h;    }    std::cout << bestLen << '\n' << (bestLen > 0 ? s.substr(bestStart, bestLen) : "-") << '\n' << switches << '\n';}
Cmain.c · 35 行
#include <ctype.h>#include <stdio.h>#include <string.h> static char line[100005]; /* 영어 글자면 'L'·'R', 아니면 0. strchr는 끝의 '\0'도 찾으니 글자인지 먼저 본다 */static char hand(char ch) {    if (!isalpha((unsigned char)ch)) return 0;    char c = (char)tolower((unsigned char)ch);    return strchr("qwertasdfgzxcvb", c) ? 'L' : 'R';} int main(void) {    if (!fgets(line, sizeof line, stdin)) return 0;    line[strcspn(line, "\r\n")] = '\0'; /* fgets는 줄바꿈까지 담는다 */    int best_len = 0, best_start = -1, run = 0, switches = 0;    char prev = 0;    for (int i = 0; line[i]; i++) {        char h = hand(line[i]);        if (h == 0) run = 0;        else if (h == prev) run++;        else {            if (prev != 0) switches++;            run = 1;        }        if (run > best_len) { best_len = run; best_start = i - run + 1; } /* 같으면 왼쪽 것 */        prev = h;    }    printf("%d\n", best_len);    if (best_len > 0) printf("%.*s\n", best_len, line + best_start);    else puts("-");    printf("%d\n", switches);    return 0;}
Craykonmain.cray · 62 行
LEFT = "qwertasdfgzxcvb";RIGHT = "yuiophjklnm"; // 영어 글자면 "L"·"R", 아니면 "". 대문자는 소문자로 바꿔 찾는다// (있나는 부분 문자열을 찾으니 늘 한 글자만 넘긴다)손(ch){    c = ch.小写();    如果 (LEFT.包含(c))    {        返回 "L";    }    如果 (RIGHT.包含(c))    {        返回 "R";    }    返回 "";} s = 控制台.读行();bestLen = 0;bestStart = -1;run = 0; // 지금 글자에서 끝나는 한 손 덩이의 길이switches = 0;prev = ""; // 바로 앞 글자의 손("": 글자가 아님)循环 (i = 0; i < s.长度; i++){    h = 손(s[i]);    如果 (h == "")    {        run = 0;    }    否则 如果 (h == prev)    {        run++;    }    否则    {        如果 (prev != "")        {            switches++;        }        run = 1;    }    // 글자마다 견주면 줄 끝에서 끝나는 덩이도 놓치지 않는다. >라서 같으면 왼쪽 것    如果 (run > bestLen)    {        bestLen = run;        bestStart = i - run + 1;    }    prev = h;}控制台.输出(bestLen);如果 (bestLen > 0){    控制台.输出(s.截取(bestStart, bestLen));}否则{    控制台.输出("-");}控制台.输出(switches);