{ }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 で英字かどうかを先に聞いてから手の表を探します。
一つ目の落とし穴は行の終わりです。
かたまりが切れたときだけいちばん長いものと比べると、行の終わりまで続いた最後のかたまりを見落とします。
文字ごとに比べればこの心配はありません。
二つ目に、同じ長さなら左のものなので > で比べます(>= だと右のものが残ります)。
三つ目に、手が替わると新しいかたまりはその文字から始まるので、長さは 0 ではなく 1 です。
四つ目に、英字でないものを「左手でなければ右手」とすると数字や空白がかたまりに入り、手の替わりを「最後に見た英字」と比べると空白の向こうまで数えてしまいます。
入力行の前後の空白は消さずにそのまま読みます(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);