티스토리 뷰

Solved.ac Class 완전정복 프로젝트

Class : 1 ~ 1 ++

 


링크

https://www.acmicpc.net/problem/2675

 

2675번: 문자열 반복

문자열 S를 입력받은 후에, 각 문자를 R번 반복해 새 문자열 P를 만든 후 출력하는 프로그램을 작성하시오. 즉, 첫 번째 문자를 R번 반복하고, 두 번째 문자를 R번 반복하는 식으로 P를 만들면 된다

www.acmicpc.net

문제

문자열 S를 입력받은 후에, 각 문자를 R번 반복해 새 문자열 P를 만든 후 출력하는 프로그램을 작성하시오. , 첫 번째 문자를 R번 반복하고, 두 번째 문자를 R번 반복하는 식으로 P를 만들면 된다. S에는 QR Code "alphanumeric" 문자만 들어있다.

QR Code "alphanumeric" 문자는0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\$%*+-./:이다.

입력
첫째 줄에 테스트 케이스의 개수 T(1 ≤ T ≤ 1,000)가 주어진다. 각 테스트 케이스는 반복 횟수 R(1 ≤ R ≤ 8), 문자열 S가 공백으로 구분되어 주어진다. S의 길이는 적어도 1이며, 20글자를 넘지 않는다.

출력
각 테스트 케이스에 대해 P를 출력한다.

 

접근방법

문자열을 받아 문자 하나씩 반복 횟수 R만큼 반복하여 출력하는 되는 문제이다. 나는 이 문제를 풀 때, 이 외의 곳에서 약한 부분을 찾았는데, 바로 Scanner와 Buffer이다. 입출력에 관한 내용은 나중에 포스팅을 할 예정이니 간단하게 차이점만 설명하자면, Scanner는 짧은 입력에 유리하고 Buffer는 큰 입력에 유리하다. 이번 문제를 통해 그 차이를 한번 확인해보자.

 

1. BufferedReader를 이용한 방법

BufferedReader를 통해 입력값을 받았다. 다음과 같은 방법으로 TC 케이스 수 , R , S를 구별하였다.

  • TC - ReadLine , 자료형 int
  • R , S - ReadLine , 자료형 String []
  • R , S 분리 - solution 메서드 내에서 인덱스를 이용해 분리 , 자료형 R - int S - String 

 

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) throws IOException {

        Main test = new Main();
    }

    public Main() throws IOException {
        //입력
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int cnt = Integer.parseInt(br.readLine().split(" ")[0]);
        String[] sen = new String[cnt];
        //케이스를 한줄로 입력받음
        for (int i = 0; i < cnt; i++) {
            sen[i] = br.readLine();
        }
        //솔루션
        String answer = String.valueOf(solution(cnt, sen));
        //출력
        System.out.println(answer);
    }

    public StringBuilder solution(int cnt, String[] sen) {
        StringBuilder sb = new StringBuilder();
	//TC 케이스 별로 반복
        for (int i = 0; i < cnt; i++) {
        //R , S 분리
        int repeat = Integer.parseInt(sen[i].split(" ")[0]);
            String str = sen[i].split(" ")[1];
		//그만큼 반복하며, 누적 
            for (char word : str.toCharArray()){
                for (int j = 0 ; j < repeat ; j++) {
                    sb.append(word);
                }
            }
            sb.append("\n");
        }

        return sb;
    }

}

 

 

 

 

2. Scanner를 사용하는 방법 

Scanner를 통해 입력받았다. 다음과 같은 방법으로 TC 케이스 수 , R , S를 구별하였다.

  • TC - nextint() , 자료형 - int
  • R , S - nextLine(). split() , 자료형 R - int , S - String

 

 

실패 원인

처음에 그냥 가장 간단히 Scanner를 사용해 문제를 풀었으나, 틀렸다. 이유는 아래와 같다.

그렇다. 바로 공백이었다. 공백에 있을 때, 스캐너 버퍼의 포지션을 바꿔줘야 하는데, 그걸 생각 못해서 처음에 결괏값이 안 나왔다. 무슨 말인지 모르겠다면, 접은 글을 참고 바란다.

더보기

이 방법은 입력 값에서 TC값을 먼저 변수로 구하고,

아래 각 TC 케이스들은 String으로 빼낸 다음 분리하는 구조이다.

import java.util.Scanner;

public class BJ_2675 {

    public static void main(String[] args) {
        BJ_2675 test =new BJ_2675();
    }


    public BJ_2675() {
		//입력
	Scanner sc = new Scanner(System.in);
        int cnt = sc.nextInt();
        int[] repeat = new int[cnt];
        String[] data = new String[cnt];
        for (int i = 0; i < cnt; i++) {
            String[] tmp = sc.nextLine().split(" ");

            repeat[i] =Integer.valueOf(tmp[0]);
            data[i] = tmp[1];

        }

        String[] answer = solution(cnt,data,repeat);
		
        //출력
        for(int i = 0 ; i < cnt ; i ++){
            System.out.println(answer[i]);
        }


    }

    public String[] solution(int cnt, String[] sen, int[] repeat) {
        String[] answer = new String[cnt];
		//TC 만큼 반복
	for (int i = 0; i < cnt; i++){
			//각 TC 의 String 문자열을 하나씩 접근
            for (int j = 0 ; j < sen[i].length() ; j++){
				//문자열을 repeat 만큼 반복하여 삽입
                for(int k = 0 ; k < repeat[i] ; k ++){
                	//단, 초기값 Null 이있으므로 처음엔 초기값 삽입 진행 
                    if (j ==0 && k==0){
                        answer[i] = Character.toString(sen[i].charAt(j));
                    }else{
                        answer[i] += sen[i].charAt(j);
                    }

                }


            }
        }
        
        return answer;
    }

}

 위의 코드가 실패한 이유는 TC 횟수를 받은 다음 넘어가는 과정에서 공백 때문에 포지션이 엔터에 위치해 있게 된다. 스크린 숏을 보자.

스캐너 버퍼를 가르키는 포지션이 \n(엔터)부터 시작하는 상황

 

 현재 상황은 TC 각 케이스에서 첫 번째 케이스를 입력받고, 그것을 반복 횟수 R와 문자열 S로 나누기 위한 작업이다.

그것을 위해 nextLine() 메서드가 실행되야하는데, 현재 Scanner에서 버퍼를 가리키고 있는 position은 1 즉, '\n'(엔터)이다. 그러니 nextLine을 불러오자마자 엔터가 눌리니 String tmp 에는 데이터가 들어가 있을 리가 없다.

nextLine() 메서드를 한번 추가하여, 버퍼 포지션을 바꿔 문제를 해결했다.

 

 

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Main test =new Main();
    }

    public Main() {
        //입력
        Scanner sc = new Scanner(System.in);
        int cnt = sc.nextInt();
        int[] repeat = new int[cnt];
        sc.nextLine();
        String[] data = new String[cnt];
        //R, S 분리
        for (int i = 0; i < cnt; i++) {
            String[] tmp = sc.nextLine().split(" ");

            repeat[i] =Integer.valueOf(tmp[0]);
            data[i] = tmp[1];
        }
        
        //솔루션
        String[] answer = solution(cnt,data,repeat);

        //출력
        for(int i = 0 ; i < cnt ; i ++){
            System.out.println(answer[i]);
        }


    }

    public String[] solution(int cnt, String[] sen, int[] repeat) {
        String[] answer = new String[cnt];
        //TC 케이스 만큼 반복
        for (int i = 0; i < cnt; i++){
            //S 문자열 만큼 반복
            for (int j = 0 ; j < sen[i].length() ; j++){
                //R 만큼 반복
                for(int k = 0 ; k < repeat[i] ; k ++){
                    //answer의 초기값 수정
                    if (j ==0 && k==0){
                        answer[i] = Character.toString(sen[i].charAt(j));
                    }else{
                        //누적
                        answer[i] += sen[i].charAt(j);
                    }

                }


            }
        }


        return answer;
    }

}

 

 

결과

1번 케이스가 메모리나 시간면에서 더 좋은 결과를 낼 수밖에 없다. 변수도 적고, Stringbuilder 차이도 있기 때문에 하지만 그것을 감안하더라도 BufferedReader가 조금 더 빠르다고 생각된다. 위 두 가지 방법 모두 알아두자.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함