3 minute read


입출력 예시

Input-1
“3people unFollowed me”
Output-1
“3people Unfollowed Me”

Input-2
“for the last week”
Output-2
“For The Last Week”


문제 풀이

주어진 문자열에서 단어의 첫문자를 대문자로 바꾸어 반환해야 한다.
이 때, 첫 문자는 숫자가 아니어야 한다.
그리고 단어 중 첫 문자가 아닌 문자가 대문자일 땐 소문자로 변환해야 한다.

먼저 주어진 문자열을 모두 소문자로 변경하면 첫문자가 아닌 문자를 일일이 소문자로 변환할 필요가 없다.
주어진 문자열 s를 char형 배열로 변환하여 공백을 제외한 모든 문자를 소문자로 변환하여 저장하였다.

1
2
3
4
5
char[] arr = s.toCharArray();        
for(int i=0; i<arr.length; i++) {
    if(arr[i]==' ') arr[i] = ' ';
    else arr[i] = Character.toLowerCase(arr[i]);
}

이제 첫 문자가 아닌 문자가 대문자일 경우를 고려하지 않아도 된다.
다음으로 소문자로 변환된 arr을 반복하며 단어의 첫문자일 때 대문자로만 변경해주면 된다.

어떻게 단어의 첫문자인지 알 수 있을까?

주어진 문자열 “for the last week”로 예를 들어서 설명하자면,
arr 배열에는 [‘f’,’o’,’r’,’ ‘,’t’,’h’,’e’,’ ‘,’w’,’e’,’e’,’k’]로 담길 것이다.
이 arr 배열을 순회하며 현재 인덱스의 값이 ‘ ‘(공백)이라면 다음 인덱스의 값을 대문자로 변환하면 되고
위 조건을 만족하지 못했다면 현재 인덱스 값을 그대로 넣으면 될 것이라 생각했다.

1
2
3
4
5
6
7
8
9
10
for(int i=0; i<arr.length; i++) {
    if(i<arr.length-1) {
        if(arr[i]==' ' && Character.isLowerCase(arr[i+1])) { // 첫 단어 검증
            answer += " " + Character.toUpperCase(arr[i+1]);
            i+=2; 
        }
    }
    if(i==0 && Character.isLowerCase(arr[0])) answer += Character.toUpperCase(arr[i]); // 제일 첫번째 글자
    else answer += arr[i];
}

위 코드와 같이 배열에서 공백값을 검증하여 다음 문자를 대문자로 변환하여 answer에 담도록 하였다.

그러나, 다른 테스트케이스를 테스트하며 문제가 있음을 알게 되었다.

오류 발견



위 디버깅은 “f o r for”라는 문자열로 테스트를 해본 내용이다.
위 사진과 같이 중간의 단어 r이 대문자로 변환되지 않았다.
이외 다른 문자열로 테스트했을 때도 비슷하게 중간 단어들의 대문자 변환이 이루어지지 않았다.

위 코드 반복문 내에서 첫 단어를 검증할 때 단어의 첫문자를 대문자를 변환하여 저장하고 인덱스를 증가시킨다.
이 인덱스를 증가시키고 맨 위 if문부터 수행문이 동작되는줄 알았지만, 아니었다.

1
2
3
4
5
6
7
8
9
10
for(int i=0; i<arr.length; i++) {
    if(i<arr.length-1) {
        if(arr[i]==' ' && Character.isLowerCase(arr[i+1])) { //1
            answer += " " + Character.toUpperCase(arr[i+1]);
            i+=2; // 오류가 발생한 증가문, 인덱스 증가후 밑의 조건문으로 빠진다.
        }
    }
    if(i==0 && Character.isLowerCase(arr[0])) answer += Character.toUpperCase(arr[i]); //2
    else answer += arr[i]; 
}
1
2
3
4
5
arr = ['f',' ','o',' ','r',' ','f','o','r'], length:9
i = 0 = 'f', answer="F"
i = 1 = ' ', answer="F O", i는 2증가
i = 3 = ' ', answer="F O r" //여기서 반복문 내 수행문을 제대로 수행하지 못함, 2번 조건문의 else문을 타버림.
... 이하 생략

오류 해결

반복문 코드가 잘못되었음을 인지하였고, 그렇다면 접근방식이 달라져야 한다고 생각했고 아래의 아이디어를 도출하였다.

  • 현재 인덱스가 공백이 아닌 현재 인덱스-1의 값이 공백일 경우를 고려하자.

위 로직대로라면 arr 배열을 반복하며 현재 인덱스의 값이 문자이고 이전 인덱스의 값이 ‘ ‘(공백)이라면
현재 인덱스의 값을 대문자로 변환하여 answer에 담고 인덱스를 증가시킬 필요가 없게 된다.

1
2
3
4
for(int i=1; i<arr.length; i++) {
    if(Character.isLowerCase(arr[i]) && arr[i-1]==' ') answer += Character.toUpperCase(arr[i]); 
    else answer += arr[i];
}

위와 같이 로직을 변경하여 테스트해보니 발생한 오류를 정상적으로 해결할 수 있었다.


작성 코드

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
31
32
import java.util.*;

class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        long start = System.currentTimeMillis();
        solution(s);
        long end = System.currentTimeMillis();
        System.out.println("\n수행시간 = " + (end-start));
    }

    public static String solution(String s) {
        String answer = "";
        char[] arr = s.toCharArray();
        
        for(int i=0; i<arr.length; i++) {
            if(arr[i]==' ') arr[i] = ' ';
            else arr[i] = Character.toLowerCase(arr[i]);
        }
        
        if(Character.isLowerCase(arr[0])) answer += Character.toUpperCase(arr[0]); 
        else answer += arr[0];
        
        for(int i=1; i<arr.length; i++) {
            if(Character.isLowerCase(arr[i]) && arr[i-1]==' ') answer += Character.toUpperCase(arr[i]); 
            else answer += arr[i];
        }
        
        return answer;
    }
}

회고

  • 여러개의 공백까지 포함된 문자열을 String[] arr = str.split(“”, -1)식의 방법도 있겠지만, char형 배열을 활용해 대문자 및 소문자 제어가 편하도록 하였다.
  • for문 내 조건문에서 인덱스를 증가시키면 처음부터 수행문을 다시 수행하는 줄 알았는데 아니었다. 반복문 내에서 인덱스를 증가시킬 때 유의해서 사용해야 겠다.