자판으로 영어를 칠 때 글자마다 치는 손이 정해져 있다.
왼손 글자는 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
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
문자열을 한 글자씩 돌며 "바로 앞 글자의 손"과 "지금 글자에서 끝나는 덩이의 길이"만 들고 가면 돼요. 글자 하나를 꺼내는 법: Python·JS·TS·C#·크레이콘 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, 크레이콘 .소문자로변환()으로 바꾼 다음 손 표에서 찾아요. 표에서 찾는 법도 달라요: Python c in LEFT, JS·TS LEFT.includes(c), Java·C# LEFT.indexOf(c) >= 0(C# IndexOf), C strchr, C++ find != npos, 크레이콘 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 Nones = 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);