개발자는 기록이 답이다

[백준/BOJ][Java][2744] 대소문자 바꾸기 본문

알고리즘/백준

[백준/BOJ][Java][2744] 대소문자 바꾸기

slow-walker 2023. 8. 21. 13:02

2023.08.21 - [Java] - Java String 이해

 

Java String 이해

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

strong-park.tistory.com

 


 

 

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

 

2744번: 대소문자 바꾸기

영어 소문자와 대문자로 이루어진 단어를 입력받은 뒤, 대문자는 소문자로, 소문자는 대문자로 바꾸어 출력하는 프로그램을 작성하시오.

www.acmicpc.net

내가 푼 풀이

  • 시간 복잡도 면에서는 입력 문자열의 길이에 선형으로 비례하는 O(n)의 복잡도를 가진다. 여기서 n은 입력 문자열의 길이이다.
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String a = sc.next();

        StringBuilder answer = new StringBuilder();
        for (int i = 0; i < a.length(); i++) {
            // 대문자의 아스키코드 값
            if (a.charAt(i) >= 65 && a.charAt(i) <= 90) {
                answer.append(String.valueOf(a.charAt(i)).toLowerCase());
            // 소문자의 아스키 코드 값
            } else if (a.charAt(i) >= 97 && a.charAt(i) <= 122) {
                answer.append(String.valueOf(a.charAt(i)).toUpperCase());
            }
        }
        System.out.println(answer);

    }
}

 

메모리 시간 언어 코드 길이
17580KB 200ms Java 11 619B

풀이 설명

나는 아스키 코드의 숫자를 기억해서 분기처리를 했는데,

아스키 코드를 외우는 것보다 ‘문자’로 비교하는게 코드상으로 직관적이라 좋다고 한다

그리고 맨 처음에는 += 연산으로 String에 더해주려고 했는데,

더하기 연산을 할때마다 새로운 인스턴스를 생성한다고 해서 StringBuildeer를 사용했다.

다른 사람 풀이

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));
        char[] temp = br.readLine().toCharArray();

        for ( int i = 0; i < temp.length; i++ )
        {
            if ( temp[i] >= 'a' )
                System.out.print((char) (temp[i] - 32));
            else
                System.out.print((char) (temp[i] + 32));
        }
        System.out.println();
	}
}

 

메모리 시간 언어 코드 길이
12804KB 68ms Java 8 471B

다른 사람 풀이랑 비교(GPT)

첫 번째 코드에서는 **StringBuilder**를 사용하여 변환된 문자열을 하나씩 추가했지만,

두 번째 코드에서는 각 문자의 ASCII 값에 따라 변환을 수행하고 바로 출력했습니다.

두 코드의 성능 차이는 매우 미세합니다.

두 코드 모두 문자열을 한 번 순회하며 대소문자 변환이 수행되므로, 시간 복잡도 측면에서 큰 차이가 없습니다.

 

두 번째 코드의 장점은 **StringBuilder**를 사용하지 않아도 되므로 메모리 사용량이 적습니다.

하지만 문자열을 하나씩 변환하고 출력하는 것으로 인해 IO 작업의 오버헤드가 조금 발생할 수 있습니다.

 

32는 대문자와 소문자의 ASCII 코드 값의 차이입니다.

대문자 A의 ASCII 코드 값은 65이고, 소문자 a의 ASCII 코드 값은 97입니다.

이 두 값의 차이는 32입니다. 즉, 대문자와 소문자 사이의 차이는 32입니다.

 

따라서 대문자를 소문자로 변환하기 위해서는 해당 문자의 ASCII 코드 값에서 32를 더하면 되고,

소문자를 대문자로 변환하기 위해서는 해당 문자의 ASCII 코드 값에서 32를 빼면 됩니다.

두 번째 코드에서 **temp[i] - 32**는 대문자를 소문자로 변환하는 부분이며,

**temp[i] + 32**는 소문자를 대문자로 변환하는 부분입니다.

강의 풀이

ASCII Code

char x = 65;
        System.out.println('Z' - 'A'); // 25
        System.out.println(x); // A
        System.out.println((int)x); // 65
        System.out.println((char)65); // A
        System.out.println(x + 25); // 90
        System.out.println((char)(x+25)); // Z

ASCII Code를 이용한 대소문자 변환

  • base(소문자라면 'a' or 대문자라면 'A') 로부터 몇 번째 알파벳(idx)인지를 찾아서 더한다
for (int i = 0; i < str.length(); i++) {
            // 대문자니?
            if ('A' <= str.charAt(i) && str.charAt(i) <= 'Z') {
                // int dist = str.charAt(i) = 'A';
                // int lower_ascii = 'a' + dist;
                System.out.println((char)('a' + str.charAt(i) - 'A'));
            } else {
                System.out.println((char)('A' + str.charAt(i) - 'a'));

            }
        }

답안 풀이

  • 문자열을 캐릭터배열로 바뀐 뒤, 해당하는 인덱스 값을 대소문자로 바로 변환
  • StringBuilder를 사용하지 않고 바로 문자열을 출력하는 방식을 채택하여, 조금 더 메모리를 절약할 수 있다
import java.util.Scanner;

class Main
{
    public static void main (String[] args)
    {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        char[] ans = str.toCharArray();
        for (int i = 0; i < str.length(); i++) {
            if ('a' <= ans[i] && ans[i] <= 'z')
                ans[i] = (char)('A' + ans[i] - 'a');
            else ans[i] = (char)('a' + ans[i] - 'A');
        }
        System.out.println(ans);
    }
}

 

강의 답안 풀이랑 비교(GPT)

StringBuilder를 사용하는 것과 str.toCharArray()로 배열을 만드는 것 간의 메모리 차이는 크게 미미합니다.

 

StringBuilder는 문자열을 더하는 과정에서 내부적으로 가변 크기 버퍼를 사용하여 문자열을 조작합니다.

이렇게 함으로써 메모리 할당과 해제의 오버헤드를 줄이고 문자열 조작 속도를 향상시킬 수 있습니다. 하지만 문자열을 많이 조작하는 경우에만 효과적이며, 여기서는 단순히 대소문자 변환만 하는 경우로써 StringBuilder를 사용하지 않는 것이 좋을 수 있습니다.

 

str.toCharArray()는 문자열을 문자 배열로 변환하는 메소드입니다. 문자 배열은 문자열을 수정하지 않는 한 고정된 크기를 가지며, 이 과정에서 새로운 배열이 할당되어 메모리가 소비됩니다. 하지만 대부분의 문자열에서는 크기가 크게 커지지 않는 경우가 많기 때문에 메모리 차이가 크지 않습니다.

 

즉, 이러한 간단한 작업에서는 메모리 차이가 크게 중요하지 않으며, 어느 쪽을 사용하든 메모리 사용량은 큰 영향을 미치지 않을 것입니다. 선택 기준은 주로 코드의 가독성과 작성 편의성일 것입니다.