프로그래머스 문제풀이/Level 2

파일명 정렬 (자바, Java)

뮤츠 2024. 1. 31. 20:36

 

 

 

오랜만에 포스팅한다. 다름아닌, 모범답안을 기록하기 위해...

문제를 보고 처음에 들었던 생각은, '정규 표현식을 이용하면 좋지 않을까?' 였고,

이후 떠오른 생각은 '정규 표현식을 사용할 수 없다면, 반복문을 통해

숫자가 처음 나오는 인덱스, 다시 숫자가 나오지 않는 인덱스를 구하면 되지 않을까?' 였다.

정규 표현식은 암기하고 있지 않기도 하고, 어차피 chatgpt로 딸깍 물어보면 알려주긴 하니까...후자로 풀어보기로 했다.

 

중간에 효율적인 방법을 고민하다 정답을 이것저것 참조했는데,

배열보다 생성자를 활용하는 방법을 썼다. 배열이 좀 더 효율적인 느낌은 들지만,

자료형이 다른 변수들을 묶어 관리하기에는 아무래도 생성자를 활용하는 편이 편했다. 객체지향적인 깔끔한 코드가 되는 것은 덤.

 

내가 본 정답에서는 string을 단순하게 더해 이어붙여주는 방법을 썼다. 나는 보통 반복문으로 문자열을 추가할 경우 stringbuilder를 즐겨쓰지만, 이번에는 시작과 끝의 index만 알면 그냥 substring으로 처리할 수 있기에, 사용하지 않았다.

 

import java.util.*;

class Solution {
    
    class File {
        String name;
        String head;
        int num;
        
        public File(String name, String head, int num) {
            this.name = name;
            this.head = head;
            this.num = num;
        }
    }
    
    public String[] solution(String[] files) {
        
        File[] arr = new File[files.length];
        
        for (int i=0; i<files.length; i++) {
            int start = 0;
            int end = 0;
            int l = files[i].length();
            
            for (int j=0; j<l; j++) {
                char ch = files[i].charAt(j);
                if (start==0 && Character.isDigit(ch)) {
                    start = j;
                    end = j;
                } else if (start!=0 && Character.isDigit(ch)) {
                    end++;
                } else if (start!=0 && !Character.isDigit(ch)) break;
                    
            }
            
            arr[i] = new File(files[i], files[i].substring(0, start).toLowerCase(), 
                              Integer.parseInt(files[i].substring(start, end+1)));
        }
        
        Arrays.sort(arr, (o1, o2) -> {
            if (o1.head.equals(o2.head)) return o1.num-o2.num;
            else return o1.head.compareTo(o2.head);
        });
        
        String[] answer = new String[files.length];
        
        for (int i=0; i<answer.length; i++) {
            answer[i] = arr[i].name;
        }
        return answer;
    }
}

 

 

그리고 이 글을 쓴 이유...정규표현식을 쓴 풀이가 있었다!

chatGPT를 통해 알게된, pattern과 matcher 클래스를 이용한 풀이였다.

 

import java.util.*;
import java.util.regex.*;

class Solution {
    public String[] solution(String[] files) {
        Pattern p = Pattern.compile("([a-z\\s.-]+)([0-9]{1,5})");

        Arrays.sort(files, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                Matcher m1 = p.matcher(s1.toLowerCase());
                Matcher m2 = p.matcher(s2.toLowerCase());
                m1.find();
                m2.find();

                if(!m1.group(1).equals(m2.group(1))) {
                    return m1.group(1).compareTo(m2.group(1));
                } else {
                    return Integer.parseInt(m1.group(2)) - Integer.parseInt(m2.group(2));
                }
            }
        });

        return files;
    }
}

 

코드가 한참 간결해졌다는 장점이 있다. 내친김에 성능테스트에 들어갔는데...

 

반전! 성능은 꽝이었다.

 

원래 내 코드의 성능을 비교해보면...

 

 

시간, 메모리 사용 모두 우수하게 나타났다.

이러한 차이는 왜 나타났을까?

가끔 프로그래머스에서 한줄코딩에 집착하여 stream으로 떡칠하는 경우가 있는데,

마찬가지로 성능저하가 일어난 경우가 많았다.

성능과 적은 코드, 이 사이에서 늘 고민이다. 굳이 따지면 나는 성능충이지만,

코드의 가독성이 과하게 차이나는 경우에는 꼭 성능최적화가 답이라고 볼 순 없으니..case by case로 접근해야하지 않을까.