{ }codelper
문자열 길이문자열 뒤집기P0143

두 줄의 바뀐 곳 표시하기

첫 줄에 a, 둘째 줄에 b가 주어진다. 두 줄이 어디서 다른지 글자 칸을 맞춰 보여 주려고 한다. 먼저 a와 b를 맨 앞에서부터 한 글자씩 맞대어 보며 같은 글자가 이어지는 가장 긴 길이를 p라 하자. 다음으로 a와 b에서 앞의 p글자를 뺀 나머지 두 문자열을 맨 뒤에서부터 한 글자씩 맞대어 보며 같은 글자가 이어지는 가장 긴 길이를 s라 하자. 그래서 p + s는 두 줄 중 짧은 쪽의 길이를 넘지 않는다. 출력의 첫 줄에 p와 s를 빈칸 하나로 띄어 출력하라. a와 b가 완전히 같으면 그것으로 끝이다(이때 s는 0이다). 다르면 이어서 세 줄을 더 출력한다. 둘째 줄은 "- " 뒤에 a, 셋째 줄은 "+ " 뒤에 b다. 넷째 줄은 빈칸 (2 + p)개 뒤에 ^ 를 w개 쓴 것이다. w는 a의 바뀐 부분 길이(a의 길이 − p − s)와 b의 바뀐 부분 길이(b의 길이 − p − s) 중 큰 값이다.

입력
줄마다 길이 1 ~ 1000이고 ASCII 글자(코드 32~126)만 쓴다.
줄의 맨 앞과 맨 끝은 빈칸이 아니다
출력
한 줄(같을 때) 또는 네 줄
예시 1 · stdin
the quick brown fox
the quack brown fox
stdout
6 12
- the quick brown fox
+ the quack brown fox
        ^
예시 2 · stdin
aa
aaa
stdout
2 0
- aa
+ aaa
    ^
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

함정이 셋이에요.
첫째, 뒤에서 같은 부분을 문자열 전체에서 세면 앞에서 같은 부분과 겹쳐요.
"aa"와 "aaa"는 앞에서 2글자, 전체 뒤에서도 2글자가 같아서 바뀐 부분 길이가 −2가 돼요.
앞의 p글자를 떼고 남은 것끼리 세야 해요.
둘째, ^ 너비를 한쪽 줄로만 정하면 "print(x)" → "print(x, y)"처럼 끼워 넣기만 한 경우에 ^ 가 하나도 안 나와요.
셋째, 두 줄이 같을 때는 첫 줄만 써야 해요.
뒤집기는 Python t[::-1], Java new StringBuilder(t).reverse(), C# Array.Reverse로 글자 배열을 뒤집어 new string(c), C++ std::string(t.rbegin(), t.rend()), 크레이콘 t.뒤집기()예요.
JS·TS 문자열에는 reverse가 없어서 [...t].reverse().join("")처럼 배열을 거쳐요.
C는 뒤집지 않고 a[la - 1 - s]처럼 끝에서부터 세는 게 자연스러워요.
길이는 Python len(t), JS·TS·크레이콘 t.length·t.길이, Java t.length(), C# t.Length, C strlen(t), C++ t.size()예요.
C++ size()는 부호 없는 수라서 a.size() - p - s가 음수가 되면 아주 큰 수로 넘어가요.
겹치지 않게 센다면 음수가 될 일이 없어요.
문자열 같음은 Java만 equals를 써야 해요(==는 같은 객체인지를 물어요).

Pythonmain.py · 18 줄
def common_prefix(x, y):    k = 0    while k < len(x) and k < len(y) and x[k] == y[k]:        k += 1    return k  a = input()b = input()p = common_prefix(a, b)# 앞에서 같은 부분을 뺀 나머지를 뒤집으면, 뒤에서 같은 부분이 앞에서 같은 부분이 된다s = common_prefix(a[p:][::-1], b[p:][::-1])print(p, s)if a != b:    print("- " + a)    print("+ " + b)    width = max(len(a) - p - s, len(b) - p - s)    print("  " + " " * p + "^" * width)
JavaScriptmain.js · 19 줄
const [a, b] = require("fs").readFileSync(0, "utf8").split("\n"); function commonPrefix(x, y) {  let k = 0;  while (k < x.length && k < y.length && x[k] === y[k]) k++;  return k;}// 문자열에는 reverse가 없어서 배열로 바꿔 뒤집고 다시 잇는다const reverse = (t) => [...t].reverse().join(""); const p = commonPrefix(a, b);const s = commonPrefix(reverse(a.slice(p)), reverse(b.slice(p)));const out = [`${p} ${s}`];if (a !== b) {  out.push("- " + a, "+ " + b);  const width = Math.max(a.length - p - s, b.length - p - s);  out.push("  " + " ".repeat(p) + "^".repeat(width));}console.log(out.join("\n"));
TypeScriptmain.ts · 20 줄
import { readFileSync } from "node:fs";const [a, b]: string[] = readFileSync(0, "utf8").split("\n"); function commonPrefix(x: string, y: string): number {  let k = 0;  while (k < x.length && k < y.length && x[k] === y[k]) k++;  return k;}// 문자열에는 reverse가 없어서 배열로 바꿔 뒤집고 다시 잇는다const reverse = (t: string): string => [...t].reverse().join(""); const p: number = commonPrefix(a, b);const s: number = commonPrefix(reverse(a.slice(p)), reverse(b.slice(p)));const out: string[] = [`${p} ${s}`];if (a !== b) {  out.push("- " + a, "+ " + b);  const width: number = Math.max(a.length - p - s, b.length - p - s);  out.push("  " + " ".repeat(p) + "^".repeat(width));}console.log(out.join("\n"));
JavaMain.java · 31 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    static int commonPrefix(String x, String y) {        int k = 0;        while (k < x.length() && k < y.length() && x.charAt(k) == y.charAt(k)) k++;        return k;    }     static String reverse(String t) {        return new StringBuilder(t).reverse().toString();    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        String a = in.readLine(), b = in.readLine();        int p = commonPrefix(a, b);        int s = commonPrefix(reverse(a.substring(p)), reverse(b.substring(p)));        StringBuilder out = new StringBuilder();        out.append(p).append(' ').append(s).append('\n');        if (!a.equals(b)) { // == 는 같은 객체인지를 묻는다            out.append("- ").append(a).append('\n');            out.append("+ ").append(b).append('\n');            int width = Math.max(a.length() - p - s, b.length() - p - s);            out.append("  ").append(" ".repeat(p)).append("^".repeat(width)).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 33 줄
using System; class Program{    static int CommonPrefix(string x, string y)    {        int k = 0;        while (k < x.Length && k < y.Length && x[k] == y[k]) k++;        return k;    }     static string Reverse(string t)    {        char[] c = t.ToCharArray();        Array.Reverse(c);        return new string(c);    }     static void Main()    {        string a = Console.ReadLine(), b = Console.ReadLine();        int p = CommonPrefix(a, b);        int s = CommonPrefix(Reverse(a.Substring(p)), Reverse(b.Substring(p)));        Console.WriteLine($"{p} {s}");        if (a != b)        {            Console.WriteLine("- " + a);            Console.WriteLine("+ " + b);            int width = Math.Max(a.Length - p - s, b.Length - p - s);            Console.WriteLine("  " + new string(' ', p) + new string('^', width));        }    }}
C++main.cpp · 25 줄
#include <algorithm>#include <iostream>#include <string> size_t commonPrefix(const std::string& x, const std::string& y) {    size_t k = 0;    while (k < x.size() && k < y.size() && x[k] == y[k]) k++;    return k;} int main() {    std::string a, b;    std::getline(std::cin, a);    std::getline(std::cin, b);    size_t p = commonPrefix(a, b);    // 앞에서 같은 p글자를 뺀 나머지를 거꾸로(rbegin~rend) 만든다    std::string ra(a.rbegin(), a.rend() - p), rb(b.rbegin(), b.rend() - p);    size_t s = commonPrefix(ra, rb);    std::cout << p << ' ' << s << '\n';    if (a != b) {        std::cout << "- " << a << "\n+ " << b << '\n';        size_t width = std::max(a.size() - p - s, b.size() - p - s);        std::cout << "  " << std::string(p, ' ') << std::string(width, '^') << '\n';    }}
Cmain.c · 25 줄
#include <stdio.h>#include <string.h> int main(void) {    static char a[1100], b[1100];    if (!fgets(a, sizeof a, stdin) || !fgets(b, sizeof b, stdin)) return 0;    a[strcspn(a, "\n")] = '\0';    b[strcspn(b, "\n")] = '\0';    int la = (int)strlen(a), lb = (int)strlen(b);    int p = 0;    while (p < la && p < lb && a[p] == b[p]) p++;    /* 뒤집지 않고 끝에서부터 센다. 앞에서 같은 p글자는 다시 세지 않는다 */    int s = 0;    while (s < la - p && s < lb - p && a[la - 1 - s] == b[lb - 1 - s]) s++;    printf("%d %d\n", p, s);    if (strcmp(a, b) != 0) {        printf("- %s\n+ %s\n", a, b);        int ma = la - p - s, mb = lb - p - s;        int width = ma > mb ? ma : mb;        printf("  %*s", p, "");        for (int k = 0; k < width; k++) putchar('^');        putchar('\n');    }    return 0;}
Craykonmain.cray · 23 줄
a = 콘솔.줄읽기();b = 콘솔.줄읽기();p = commonPrefix(a, b);// 앞에서 같은 부분을 뺀 나머지를 뒤집으면, 뒤에서 같은 부분이 앞에서 같은 부분이 된다s = commonPrefix(a.부분문자열(p).뒤집기(), b.부분문자열(p).뒤집기());콘솔.쓰기(p + " " + s);만약 (a != b){    콘솔.쓰기("- " + a);    콘솔.쓰기("+ " + b);    width = 수학.큰수(a.길이 - p - s, b.길이 - p - s);    콘솔.쓰기("  " + " ".되풀이(p) + "^".되풀이(width));} commonPrefix(x, y){    k = 0;    동안 (k < x.길이 && k < y.길이 && x[k] == y[k])    {        k += 1;    }    돌려주기 k;}