개발자는 기록이 답이다
[백준/BOJ][Java][9086]문자열 본문
2023.08.21 - [Java] - Java, String의 constant pool과 Heap의 차이
https://www.acmicpc.net/problem/9086
내가 푼 풀이
풀고나서 문제점들이 많이 보여서 어떤 거 였는지 적어보력 한다. 💩
1. 안해도 되는데 길이가 1일때를 굳이 분기처리했습니다.
- 어차피 "0"으로 들어온 문자열의 첫번째 인덱스와 마지막 인덱스를 붙이면 "00"이 되는데, 분기처리를 해버렸다.
2. 문자열 분리와 결합으로 성능적으로 봤을 때 메모리,시간, 코드길이가 전부 좋지 않았다.
- 나는 입력값을 하나씩 받으려고 sc.next();를 3번써서 저렇게 한건데, 다른 사람들 코드보니까 입력 한번에 받고 For문 안에서 처리했다.
- 입력된 세 개의 문자열을 합치고, 문자열을 분리해서 배열에 저장하는 부분이 성능적으로 비효율적이다.
- 문자열을 분리하는 과정에서 정규식이나 split 함수를 사용하는 것은 문자열의 길이에 따라 성능이 크게 영향을 받을 수 있다.
- 또한 문자열 결합은 문자열의 크기에 따라 성능 저하를 유발할 수 있다.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
String str1 = sc.next();
String str2 = sc.next();
String str3 = sc.next();
String ans = "";
String total = str1+ "," + str2 + ","+ str3;
String[] strSplit = total.split(",");
for (int i = 0; i < num; i++) {
if (strSplit[i].length() == 1) {
String s = String.valueOf(strSplit[i].charAt(0));
ans = s + s;
}
else {
String start = String.valueOf(strSplit[i].charAt(0));
String end = String.valueOf(strSplit[i].charAt(strSplit[i].length()-1));
ans = start + end;
}
System.out.println(ans);
}
}
}
메모리 | 시간 | 언어 | 코드 길이 |
18504MB |
236ms | Java11 | 870B |
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
String str1 = sc.next();
String str2 = sc.next();
String str3 = sc.next();
String ans = "";
String total = str1 + "," + str2 + "," + str3;
String[] strSplit = total.split(",");
for (int i = 0; i < num; i++) {
String start = String.valueOf(strSplit[i].charAt(0));
String end = String.valueOf(strSplit[i].charAt(strSplit[i].length()-1));
ans = start + end;
System.out.println(ans);
}
}
}
메모리 | 시간 | 언어 | 코드 길이 |
18600MB | 236ms | Java11 | 684B |
다른 사람 풀이 1
String으로 더하기 연산해서 인스턴스를 계속 생성하는것 보다, StringBuffer, StringBuilder의 append를 쓰는게 훨씬 좋은것 같다.
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 t = Integer.parseInt( br.readLine() );
StringBuffer sb = new StringBuffer("");
for(int i=0; i<t; i++) {
String str = br.readLine();
sb.append( str.charAt( 0 )+"" + str.charAt( str.length()-1 )+"" + "\n");
}
System.out.print( sb.toString() );
}
}
메모리 | 시간 | 언어 | 코드 길이 |
12776MB | 64ms | Java8 | 512B |
다른 사람 풀이 2 (static 사용에 대한 GPT풀이)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
// [백준] 9086. 문자열 (Java)
public class Main {
static int t;
static StringBuilder sb;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
t = Integer.parseInt(br.readLine());
sb = new StringBuilder();
for(int i = 0; i < t; i++){
String str = br.readLine();
sb.append(str.charAt(0)).append(str.charAt(str.length() - 1)).append("\n");
}
System.out.println(sb);
}
}
메모리 | 시간 | 언어 | 코드 길이 |
11300MB | 68ms | Java8 | 639B |
여러가지 측면에서 static을 사용했을 때 성능이 향상될 수 있습니다:
- 메모리 사용량 감소: 인스턴스 변수를 생성하지 않고 static 변수를 사용하면 객체마다 인스턴스 변수를 할당하는 비용이 들지 않습니다. 따라서 객체마다 중복된 데이터를 가지지 않고 하나의 변수를 여러 객체에서 공유하므로 메모리 사용량이 감소하게 됩니다.
- 속도 향상: static 메서드는 인스턴스를 생성하지 않고 바로 호출할 수 있기 때문에, 메서드 호출 시간이 더 짧을 수 있습니다.
그러나 성능 향상을 위해 static을 무작정 사용하는 것은 좋은 방법은 아닙니다. static 변수나 메서드는 공유되는 특성을 가지므로, 데이터의 무결성을 유지하고 의도치 않은 부작용을 피하기 위해 신중하게 사용해야 합니다.
제공해주신 코드에서 static을 사용한 부분은 성능에 직접적인 영향을 주진 않습니다. 이 코드에서는 static을 사용하여 t와 sb 변수를 클래스 수준에서 선언하고 사용하였는데, 이는 반복문 내에서 인스턴스를 생성하지 않고 공유하는 용도로 사용한 것입니다. 이런 경우 메모리 사용량이나 속도 면에서 약간의 이점이 있을 수 있습니다.
다른 사람 풀이 3
문자열 분리와 결합 대신에 배열이나 리스트를 사용하고, 반복문 내에서 문자열 연산을 최소화하는 방법을 고려했다. 배열을 사용하되 이렇게 for문 내에서 입력값을 받아주면 좋은 것 같다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader( new InputStreamReader(System.in ) );
int t = Integer.parseInt( br.readLine() );
String[] array = new String[ t ];
for( int i=0; i<t; i++ ) {
array[i] = br.readLine();
}
for( int i=0; i<t; i++ ) {
System.out.println( array[i].charAt(0) + "" + array[i].charAt( array[i].length() - 1) );
}
}
}
메모리 | 시간 | 언어 | 코드 길이 |
11308MB | 68ms | Java8 | 508B |
응용 풀이
- 같은 코드인데도 불구하고 Scanner 대신 BufferedReader를 쓰는 것만으로도 성능이 확 좋아지는것 같다. 다음 코드부터는 BufferedReader를 사용해야겠다.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
String[] strings = new String[num];
for (int i = 0; i < num; i++) {
strings[i] = sc.next();
}
for (int i = 0; i < num; i++) {
String start = String.valueOf(strings[i].charAt(0));
String end = String.valueOf(strings[i].charAt(strings[i].length() - 1));
System.out.println(start + end);
}
}
}
메모리 | 시간 | 언어 | 코드 길이 |
17556MB |
216ms | Java11 | 553B |
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader( new InputStreamReader(System.in ) );
int num = Integer.parseInt(br.readLine());
String[] strings = new String[num];
for (int i = 0; i < num; i++) {
strings[i] = br.readLine();
}
for (int i = 0; i < num; i++) {
String start = String.valueOf(strings[i].charAt(0));
String end = String.valueOf(strings[i].charAt(strings[i].length() - 1));
System.out.println(start + end);
}
}
}
메모리 | 시간 | 언어 | 코드 길이 |
14072MB | 124ms | Java11 | 683B |
와 그리고 바로 위에 똑같은 코드를 자바버전을 11이 아닌 8로 하니까 속도가 엄청빠르다...왜 그럴까?
메모리 | 시간 | 언어 | 코드 길이 |
11300MB | 76ms | Java8 | 683B |
출력 속도를 비교한 아래 백준 사이트를 참고해보자
https://www.acmicpc.net/blog/view/57
'알고리즘 > 백준' 카테고리의 다른 글
[백준/BOJ][Java][2908] 상수 (0) | 2023.08.24 |
---|---|
[백준/BOJ][Java][10809] 알파벳 찾기 (1) | 2023.08.24 |
[백준/BOJ][Java][13223] 소금 폭탄 (0) | 2023.08.24 |
[백준/BOJ][Java][1543] 문서 검색 (0) | 2023.08.23 |
[백준/BOJ][Java][11720] 숫자의 합 (0) | 2023.08.23 |