ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [프로그래머스 1단계] 알고리즘 12. 문자열 내림차순으로 배치하기
    24년 11월 이전/레거시-알고리즘(3) 2018. 3. 22. 13:19
    반응형

    문제 출처는 프로그래머스 알고리즘 연습 에서 볼 수 있습니다!(https://programmers.co.kr/learn/challenges)


    알고리즘 12. 문자열 내림차순으로 배치하기

    reverseStr 메소드는 String형 변수 str을 매개변수로 입력받습니다.
    str에 나타나는 문자를 큰것부터 작은 순으로 정렬해 새로운 String을 리턴해주세요. str는 영문 대소문자로만 구성되어 있으며, 대문자는 소문자보다 작은 것으로 간주합니다. 예를들어 str이 Zbcdefg gfedcbZ을 리턴하면 됩니다.


    public class ReverseStr {
        public String reverseStr(String str){
            
            return "";
        }

        // 아래는 테스트로 출력해 보기 위한 코드입니다.
        public static void main(String[] args) {
            ReverseStr rs = new ReverseStr();
            System.out.println( rs.reverseStr("Zbcdefg") );
        }
    }


    풀이:

    이틀 연속으로 자바다! 당연히 나는 자바8 Stream API를 이용하여 문제를 풀어보려 한다. 이 문제의 핵심은 주어진 문자열을 역순으로 정렬하는 것이다. 다행히도 대문자가 소문자보다 작은것으로 간주되기 때문에 다른것을 생각할 필요가 없다. 왜냐하면 소문자 'a'는 97 대문자 'A' 는 65이다.  나머지 알파벳은 여기에다 1씩 커진것과 같다.  가령 'b'는 98 'B'는 66이다. 즉 그냥 역순으로 정렬하는 문제이다. 먼저 내가 생각한 문제 해결 방식은 다음과 같다.


    1. String을 Stream<Character>로 바꾼다.

    2. Stream<Character>을 역순으로 정렬한다.

    3. 다시 Stream<Character>를 String으로 바꾼다.


    코드는 아래와 같다.


    public String reverseStr(String str){

        return str.chars()
         .mapToObj(i -> (char)i)
            .sorted(Comparator.reverseOrder())
            .map( c -> c.toString())
            .reduce("", (a, b) -> a+b);
    }


    1. Sting -> Stream<Character>

    str.chars() 메소드는 주어진 문자열을 IntStream으로 바꾼다. 그 IntStream을 다시 IntStream.mapToObj()메소드로 Stream<Character>로 바꾼다.  mapToObj에서 IntStream의 각 요소 int를 모두 char로 바꿨는데 자동으로 Character형으로 박싱되는것 같다.  


    2. Stream<Character> 역순 정렬

    그 후 Stream<Character>.sorted()를 이용하여 정렬하는데 Comparator.reverseOrder()를 파라미터로 넘겨주면 역순으로 스트림 요소들을 정렬 시켜준다. 


    3. Stream<Character> -> String

    이제 Stream<Character>.map()을 통해서 각 요소들을 Character -> String 으로 변환 시킨다. 그 후 Stream<String>.reduce()를 통해서 스트림 요소들을 집계한다. reduce메소드는 사용자가 정의한 방식으로 스트림 요소들을 하나로 모아주는 함수이다. 첫 요소로 초기값을 받고 그 후 두번째 인자로 집계 방식을 결정하는 람다(혹은 메소드)를 받는다. 즉 "" 부터 시작해서 Stream 요소들을 차례로 합친 문자열을 반환해준다. 이렇게 해서 문제를 끝냈는데 나보다 더 간단하게 스트림을 이용하신 분이 계셔서 그 코드 역시 소개할까 한다. 기본 개념은 같으니 내 코드를 이해했으면 바로 이해가 갈것이다. 


    public String reverseStr(String str){
    return Stream.of(str.split(""))
                        .sorted(Comparator.reverseOrder())
                        .collect(Collectors.joining());
    }


    이 코드를 해석하면 다음과 같다.

    1. Sting -> Stream<String>

    str.split("")를 통해서 문자열의 각 문자들을 char[]로 바꾼다. 예를 들어서 "abc" 문자열이 있다면 "abc".split("") = ["a", "b", "c"]) 이런 결과를 반환한다. 그 것을 Stream.of()를 통해서 얻은 char [] 을 Stream<String> 로 바꾼다.


    2. Stream<String> 역순 정렬

    이것은 같으니 생략하겠다. Comparator클래스는 아마도 기본 타입과 그 래퍼 타입 그리고 String까지는 정렬시켜주는 메소드들이 존재하는 것 같다.


    3. Stream<String> -> String

    나는 Stream<Character> -> Stream<String> 작업이 존재하는데 이 코드는 바로 Stream<String>이 되기 때문에 문자열을 합쳐주기만하면 된다. 나처럼 커스텀 집계를 정의해줘도 되지만 이 사람은 Stream<String>.collect()를 통해서 String을 모아주는데Collectors.joining()를 파라미터로 넘겨준다. 이 joining()는 파라미터 없이 호출하면 ["a", "b", "c"] 배열을 "abc"로 모아진다. (만약 joining("!!")를 했다면 "a!!b!!c"가 된다는 것을 알아두자.)


    728x90
Designed by Tistory.