{ }codelper
文字列の反転P0316

半分ずつ逆にする暗号メモ

友だちどうしでメモをやり取りするときに使う暗号がある。
単語の長さを L とし、L を 2 で割った商を h とする。
単語の前の h 文字を逆順に書き、後ろの h 文字も別に逆順に書く。
L が奇数ならちょうど真ん中に 1 文字残るが、この文字はそのままの位置に置く。
たとえば notebook は note と book をそれぞれ逆にして etonkoob になる。
pencils は pen と ils をそれぞれ逆にし、真ん中の c はそのままにして nepcsli になる。
だから長さが 3 以下の単語は暗号にしても変わらない。
一行目に単語の数 n が、続く n 行に単語が一つずつ与えられる。
単語ごとに、暗号にした文字列を一行に出力せよ。

入力
1 ≤ n ≤ 100。
単語の長さは 1~1,000 で、英大文字・英小文字・数字だけからなる
出力
n 行、各行に暗号にした単語
例 1 · stdin
4
notebook
pencils
ab
x
stdout
etonkoob
nepcsli
ab
x
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

文字列の一部分を逆にする方法は言語ごとに違います。
Python は s[:h][::-1](逆向きに読んだ新しい文字列)、JS・TS は文字列に reverse がないので [...t].reverse().join("")、Java は new StringBuilder(t).reverse().toString()、C# は char[] に変えて Array.Reverse(a, 開始, 個数)、C は両端から真ん中へ進みながら 2 文字を入れ替えるループ、C++ は std::reverse(s.begin(), s.begin() + h)、Craykon は s.切り出す(0, h).逆に()。
Python・JS・Java・Craykon の解答は逆にした新しい文字列を作ってつなぎ、C・C++・C#(char 配列)の解答はその場で書き換えます。
部分を指す二つの数の意味も違います。
Python s[a:b]、JS slice(a, b)、Java substring(a, b)、C++ std::reverse(最初, 終わり) は(開始, 終わり)で、終わりの位置は含みません。
C# Array.Reverse(配列, 開始, 個数) と Craykon 切り出す(開始, 個数) は(開始, 個数)です。
落とし穴は六つ:① 後ろ半分を h 番目の位置から取ると、長さが奇数のとき真ん中の文字まで逆になります(例の pencils が nepslic に)。
後ろ半分は(長さ − h)番目の位置からです。
② Python s[-h:] と JS s.slice(-h) は「末尾の h 文字」ですが、h が 0 だと -0 は 0 なので文字列全体になります(例の x が xx に)。
③ Python reversed(t) は文字列ではなくイテレータを返します。
str(reversed(t)) は <reversed object at …> という文字になるので、"".join(reversed(t)) でつなぎます。
④ JS の配列の reverse() は新しい配列を返さず、その配列自体を逆にします。
一つの配列を逆にしたあとでまた切り出すと、すでに逆になったものを切り出すことになります。
⑤ C で入れ替えのループを範囲の真ん中で止めずに最後まで回すと、二回入れ替わって元のままです(notebook がそのまま出ます)。
⑥(開始, 個数)を受け取るところに終わりの位置を渡す間違い:C# Array.Reverse(a, 長さ − h, 長さ) は配列をはみ出して ArgumentException で止まり、Craykon s.切り出す(h, 長さ − h) はエラーにならず、真ん中の文字に後ろ半分までつけて切り出します(notebook が etonbookkoob に)。

Pythonmain.py · 8 行
n = int(input())for _ in range(n):    s = input().strip()    h = len(s) // 2    # 앞쪽 h글자, 한가운데(길이가 홀수일 때만 한 글자), 뒤쪽 h글자    front, middle, back = s[:h], s[h:len(s) - h], s[len(s) - h:]    # [::-1]은 거꾸로 읽은 새 문자열을 만든다    print(front[::-1] + middle + back[::-1])
JavaScriptmain.js · 15 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);// 문자열에는 reverse가 없어서 글자 배열로 바꿔 뒤집고 다시 잇는다const reversed = (t) => [...t].reverse().join("");const out = [];for (let i = 1; i <= n; i++) {  const s = lines[i].trim();  const h = Math.floor(s.length / 2);  // 앞쪽 h글자, 한가운데(길이가 홀수일 때만 한 글자), 뒤쪽 h글자  const front = s.slice(0, h);  const middle = s.slice(h, s.length - h);  const back = s.slice(s.length - h);  out.push(reversed(front) + middle + reversed(back));}console.log(out.join("\n"));
TypeScriptmain.ts · 16 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);// 문자열에는 reverse가 없어서 글자 배열로 바꿔 뒤집고 다시 잇는다const reversed = (t: string): string => [...t].reverse().join("");const out: string[] = [];for (let i = 1; i <= n; i++) {  const s: string = lines[i].trim();  const h: number = Math.floor(s.length / 2);  // 앞쪽 h글자, 한가운데(길이가 홀수일 때만 한 글자), 뒤쪽 h글자  const front: string = s.slice(0, h);  const middle: string = s.slice(h, s.length - h);  const back: string = s.slice(s.length - h);  out.push(reversed(front) + middle + reversed(back));}console.log(out.join("\n"));
JavaMain.java · 27 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    // String은 고칠 수 없어서 StringBuilder에 담아 뒤집는다    static String reversed(String t) {        return new StringBuilder(t).reverse().toString();    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            String s = in.readLine().trim();            int len = s.length();            int h = len / 2;            // substring(시작, 끝): 끝 자리는 들어가지 않는다            String front = s.substring(0, h);            String middle = s.substring(h, len - h);            String back = s.substring(len - h);            out.append(reversed(front)).append(middle).append(reversed(back)).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 22 行
using System;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        var sb = new StringBuilder();        for (int i = 0; i < n; i++)        {            // string은 고칠 수 없어서 char 배열로 바꿔 그 자리에서 뒤집는다            char[] a = Console.ReadLine().Trim().ToCharArray();            int h = a.Length / 2;            // Array.Reverse(배열, 시작, 개수): 셋째 값은 끝 자리가 아니라 개수다            Array.Reverse(a, 0, h);            Array.Reverse(a, a.Length - h, h);            sb.Append(new string(a)).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 17 行
#include <algorithm>#include <iostream>#include <string> int main() {    int n;    std::cin >> n;    for (int i = 0; i < n; i++) {        std::string s;        std::cin >> s;        auto h = s.size() / 2;        // std::reverse(시작, 끝): 끝은 들어가지 않는다. 그 자리에서 뒤집는다        std::reverse(s.begin(), s.begin() + h);        std::reverse(s.end() - h, s.end());        std::cout << s << '\n';    }}
Cmain.c · 28 行
#include <stdio.h>#include <string.h> /* s[from] ~ s[to]를 그 자리에서 뒤집는다. 양 끝에서 가운데로 오며 맞바꾼다 */static void reverse_range(char *s, int from, int to) {    while (from < to) {        char tmp = s[from];        s[from] = s[to];        s[to] = tmp;        from++;        to--;    }} int main(void) {    int n;    static char s[1001];    scanf("%d", &n);    for (int i = 0; i < n; i++) {        scanf("%1000s", s);        int len = (int)strlen(s);        int h = len / 2;        reverse_range(s, 0, h - 1);         /* 앞쪽 h글자 */        reverse_range(s, len - h, len - 1); /* 뒤쪽 h글자 */        printf("%s\n", s);    }    return 0;}
Craykonmain.cray · 11 行
n = コンソール.行読み().数に();繰り返す (i = 0; i < n; i++){    s = コンソール.行読み().空白除去();    h = 数学.商(s.長さ, 2);    // 부분문자열(시작, 개수): 둘째 값은 끝 자리가 아니라 글자 수다    앞쪽 = s.切り出す(0, h);    가운데 = s.切り出す(h, s.長さ - 2 * h);    뒤쪽 = s.切り出す(s.長さ - h, h);    コンソール.書く(앞쪽.逆に() + 가운데 + 뒤쪽.逆に());}