개발자는 기록이 답이다

[백준/BOJ][Java][2675] 문자열 반복 본문

알고리즘/백준

[백준/BOJ][Java][2675] 문자열 반복

slow-walker 2023. 8. 24. 19:48

2023.08.21 - [Java] - Java, String의 constant pool과 Heap의 차이

 

Java, String의 constant pool과 Heap의 차이

Java String 문자열? 순서를 가진 문자들의 집합 “쌍따옴표를 통해 나타낼 수 있음” 글자, 단어, 문장, 문서 등 문자로 구성된 자료형 // 기본 자료형 int var_integer = 10; double var_real - 3.141592; char var_ch

strong-park.tistory.com


 

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

 

2675번: 문자열 반복

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

www.acmicpc.net

 

내가 푼 풀이

- 3중 for문 말고 다른 방법을 생각해보려고 했는데, 모르겠어서 다른 사람꺼 보고 공부하려고 했더니 전부 중첩 반복문 쓰신 것 같다.

- 자바 11부터 repeat()함수가 있다고 하는데, 나는 자바 8로 하는 중이라 for문을 하나 더 쓸 수 밖에 없었다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        for (int i = 0; i < N; i++) {
            String str = br.readLine();
            String[] split = str.split(" ");
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < split[1].length(); j++) {
                int count = Integer.parseInt(split[0]);
                for (int k = 0; k < count; k++) {
                    sb.append(split[1].charAt(j));
                }
            }
            System.out.println(sb);
        }
    }
}

 

메모리 시간 언어 코드 길이
11488KB 84ms Java8 787B

 

 

다른 사람 풀이 1

 

1. BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); 에 대해서 알게 되었다.

- 그리고 BufferedWriter를 쓰려면 flush(), close()함수를 꼭 써주자.

BufferedWriter는 출력을 버퍼에 모아두었다가 한 번에 출력하는 역할을 하는 Java의 클래스입니다. BufferedWriter를 사용하는 이유는 프로그램의 효율성과 성능을 향상시키기 위해서입니다.

표준 출력(System.out)으로 직접 출력할 때는 매번 출력할 때마다 입출력 작업이 수행되기 때문에 속도가 느릴 수 있습니다. 반면, BufferedWriter를 사용하면 출력을 임시로 저장하는 버퍼에 쌓아두었다가 버퍼가 가득 찼거나 작업이 끝나면 한 번에 출력을 수행합니다. 이로써 입출력 작업의 횟수를 줄이고 프로그램의 성능을 향상시킬 수 있습니다.

따라서 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));는 표준 출력을 버퍼링하여 프로그램의 출력 성능을 개선하기 위해 사용된 것입니다. 출력 작업이 빈번하게 발생하는 상황에서 특히 유용합니다.
1. bw.flush(): 버퍼에 남아있는 데이터를 강제로 출력합니다. 이를 호출하지 않으면 버퍼에 쌓아둔 데이터가 출력되지 않을 수 있습니다. 프로그램이 끝나기 전에 모든 출력이 확실하게 처리되도록 하기 위해서 flush()를 사용하는 것이 좋습니다.

2. bw.close(): BufferedWriter를 사용한 후에는 반드시 닫아주어야 합니다. 이 메서드는 내부적으로 flush()를 호출하여 남아있는 버퍼의 데이터를 모두 출력하고 자원을 정리합니다. 만약 close()를 호출하지 않으면 버퍼가 비워지지 않고 남을 수 있으며, 이는 원하지 않는 동작을 초래할 수 있습니다.

따라서 BufferedWriter를 사용한 후에는 코드 마지막에 bw.flush()와 bw.close()를 호출하여 데이터를 확실하게 출력하고 자원을 해제하는 것이 좋습니다.

2. 메소드 분리로 가독성이 좋아지긴 했지만, setData() 메서드 내에서 중첩된 반복문을 사용하여 resultArray 배열을 채우는 방식으로 구현되어있어서 중첩 반복문을 직접 사용하여 문자를 출력했던 나의  방식과 비슷한 것 같다.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {

	private static int T;
	private static int repeat; 
	private static char[] chArray, resultArray;
	
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	
		T = Integer.parseInt(br.readLine());
		
		for(int t = 1 ; t <= T ; t++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			repeat = Integer.parseInt(st.nextToken());
			chArray = st.nextToken().toCharArray();
			
			resultArray = new char[repeat*chArray.length];
			
			setData();
			print(bw);
		}
		bw.flush();
		bw.close();
	}
	
	private static void setData() {
		int index = 0;
		for(int i = 0 ; i < chArray.length ; i++) {
			for(int j = 0 ; j < repeat ; j++) {
				resultArray[index++] = chArray[i];
			}
		}
	}
	
	private static void print(BufferedWriter bw) throws Exception {
		for(int i = 0 ; i < resultArray.length ; i++) {
			bw.write(String.valueOf(resultArray[i]));
		}
		bw.newLine();
	}
}
메모리 시간 언어 코드 길이
13000KB 64ms Java8 1287B

 

 

다른 사람 풀이 1을 응용한 풀이1

- 코드 길이는 길어지지만 split()함수 대신에 StringTokenizer을 사용하는게 훨씬 더 속도가 빠른 것 같다.

- 공백을 기준으로 앞에 있는 입력값은 숫자로 받고, 뒤에 있는 입력값은 toCharArray()로 받으면 되는것 같다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    private static int repeat;
    private static char[] chArray;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int N = Integer.parseInt(br.readLine());

        for (int i = 0; i < N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            repeat = Integer.parseInt(st.nextToken()); // 3
            chArray = st.nextToken().toCharArray(); // [A, B, C]
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < chArray.length; j++) {
                for (int k = 0; k < repeat; k++) {
                    sb.append(chArray[j]);
                }
            }
            System.out.println(sb);
        }
    }
}
메모리 시간 언어 코드 길이
11320KB 76ms Java8 938B

 

 

다른 사람 풀이 1을 응용한 풀이2

- BufferedWriter를 사용하는 코드로 수정해봤는데, 성능이 좋아진것 같진 않은데, 입출력의 양이 많지 않아서 그런걸까?

import java.io.*;
import java.util.StringTokenizer;

public class Main {
    private static int repeat;
    private static char[] chArray;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int N = Integer.parseInt(br.readLine());

        for (int i = 0; i < N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            repeat = Integer.parseInt(st.nextToken()); // 3
            chArray = st.nextToken().toCharArray(); // [A, B, C]
            for (int j = 0; j < chArray.length; j++) {
                for (int k = 0; k < repeat; k++) {
                    bw.write(chArray[j]);
                }
            }
            bw.newLine();
        }
        bw.flush();
        bw.close();
    }
}
메모리 시간 언어 코드 길이
11396KB 76ms Java8 916B

 

 

다른 사람 풀이 2

- 내가 푼 풀이랑 비슷한데, 마지막에 sb.delete(0, sb.length());가 있다. 이것의 역할과 사용 목적은 무엇일까?

 

StringBuilder 객체 내의 특정 문자열 부터 데이터를 삭제하는 작업을 수행하는 코드입니다.

delete(start, end)는 StringBuilder에 저장된 문자열의 start Index에서 end Index 직전까지 삭제합니다. 즉, 삭제 대상에서 start는 포함하며, end는 포함하지 않습니다.

1. 이전 테스트 케이스의 결과 삭제: 코드는 각 테스트 케이스마다 문자열을 StringBuilder에 누적해서 추가하고, 출력한 뒤 StringBuilder를 비워주는 역할을 합니다. 이렇게 함으로써 다음 테스트 케이스의 결과가 현재 테스트 케이스의 결과와 혼동되지 않게 됩니다.

2. 메모리 관리 및 성능 향상: StringBuilder 객체는 내부적으로 버퍼를 사용하여 문자열을 처리합니다. delete() 메서드를 사용하여 이전 테스트 케이스의 결과를 삭제함으로써 버퍼 내의 데이터를 지우고 재활용할 수 있습니다. 이로써 메모리 관리 및 성능 향상을 이룰 수 있습니다.

즉, sb.delete(0, sb.length());은 이전 테스트 케이스의 결과를 제거하고 StringBuilder 객체를 초기화하는 역할을 합니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

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

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		int testCase = Integer.parseInt(br.readLine());
		for (int i = 0; i < testCase; i++) {
			String[] input = br.readLine().split(" ");
			int repeat = Integer.parseInt(input[0]);
			char[] chars = input[1].toCharArray();
			for (int j = 0; j < chars.length; j++) {
				for (int k = 0; k < repeat; k++) {
					sb.append(chars[j]);
				}
			}
			System.out.println(sb);
			sb.delete(0, sb.length());
		}

	}
}
메모리 시간 언어 코드 길이
12728KB 68ms Java8 705B

 

참고 링크 :

https://devaily.tistory.com/11

 

[Java] BufferedWriter와 System.out.print

코드업을 통해 자바 문법을 공부하는데 시간 초과로 문제를 통과하지 못하였다. 여태 많지 않은 출력을 냈기 때문에 시간에서 큰 차이가 없었지만, for() 문을 세 번 사용해 많은 양의 문장을 출

devaily.tistory.com

https://code0xff.tistory.com/10

 

2. BufferedWriter와 System.out.println() 의 비교와 사용법

잘 구현된 알고리즘은 속도면에서 그리고 메모리면에서 최적화되어 있어야 합니다. 만일 문제는 잘 풀어놓고도 많은 입력과 출력을 감당하지 못해서 실행 속도가 느려진다면 복장이 터질겁니

code0xff.tistory.com

https://developer-talk.tistory.com/689

 

[Java]StringBuilder 마지막 문자 제거하는 방법

StringBuilder 마지막 문자 제거하는 방법 이번 포스팅은 StringBuilder 클래스에서 제공하는 메서드를 사용하여 마지막 문자를 제거하는 방법을 소개합니다. 방법 1. deleteCharAt 메서드 다음 예제처럼 배

developer-talk.tistory.com

https://codechacha.com/ko/java-stringbuilder-clear/

 

Java - StringBuilder 초기화, 모든 문자열 삭제

StringBuilder.setLength(0)는 StringBuilder에 저장된 문자열의 길이를 0으로 변경합니다. 즉 문자열을 empty로 만든다는 것은 이전에 저장한 문자열을 모두 제거한다는 것입니다. 이렇게 StringBuilder를 초기

codechacha.com