본문 바로가기

Programmers

[프로그래머스][JAVA]Lv. 2 - 파일명 정렬

https://school.programmers.co.kr/learn/courses/30/lessons/17686

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

파일은 HEAD, NUMBER, TAIL 부분으로 나눌 수 있다.

파일명 HEAD NUMBER TAIL
foo9.txt foo 9 .txt
foo010bar020.zip foo 010 bar020.zip
F-15 F- 15 (빈 문자열)

HEAD는 숫자가 아닌 문자로 이루어져 있으며, 최소한 한 글자 이상이다.

NUMBER는 한 글자에서 최대 다섯 글자 사이의 연속된 숫자로 이루어져 있으며, 앞쪽에 0이 올 수 있다.

0부터 99999 사이의 숫자로, 00000이나 0101 등도 가능하다.

TAIL은 그 나머지 부분으로, 여기에는 숫자가 다시 나타날 수도 있으며, 아무 글자도 없을 수 있다.

 

파일명은 우선 HEAD 부분을 기준으로 사전 순으로 정렬한다.

이때, 문자열 비교 시 대소문자 구분을 하지 않는다. MUZI와 muzi, MuZi는 정렬 시에 같은 순서로 취급된다.

파일명의 HEAD 부분이 대소문자 차이 외에는 같을 경우, NUMBER의 숫자 순으로 정렬한다.

9 < 10 < 0011 < 012 < 13 < 014 순으로 정렬된다.

숫자 앞의 0은 무시되며, 012와 12는 정렬 시에 같은 같은 값으로 처리된다.

두 파일의 HEAD 부분과, NUMBER의 숫자도 같을 경우, 원래 입력에 주어진 순서를 유지한다.

MUZI01.zip과 muzi1.png가 입력으로 들어오면, 정렬 후에도 입력 시 주어진 두 파일의 순서가 바뀌어서는 안 된다.

 

조건에 맞게 정렬하기 위해 다음과 같이 코드를 작성했다.

먼저 HEAD, NUMBER, TAIL 부분으로 자르기 위한 메서드를 준비했다.

대소문자 구분을 하지 않기 때문에 .toLowerCase()를 이용하여 소문자로 만들어 준 다음

"a-z", "-", " ", "."인 경우 HEAD에 추가되도록 하였고, 그다음 인덱스가 문자 길이의 끝인 경우 종료, 숫자로 된 경우 NUMBER에 추가되기 시작하도록 하였다.

NUMBER는 길이가 5가 넘어가지 않도록 numberCnt를 따로 두어서 길이가 5가 넘어가게 된다면 TAIL에 저장되도록 하였다.

public String[] process(String file) {
        String[] fileInfo = new String[3];
        StringBuilder HEAD = new StringBuilder();
        StringBuilder NUMBER = new StringBuilder();
        StringBuilder TAIL = new StringBuilder();
        String word = file.toLowerCase();
        int index = 0;
        int process = 0;
        int numberCnt = 0;

        while (index != file.length()) {
            if (process == 0 && ((word.charAt(index) >= 'a' && word.charAt(index) <= 'z')
                    || word.charAt(index) == '-' || word.charAt(index) ==' '
                    || word.charAt(index) == '.')) {
                HEAD.append(word.charAt(index));
                index++;
                if (index == file.length()) break;
                if (word.charAt(index) >= '0' && word.charAt(index) <= '9') process = 1;
            } else if (numberCnt < 5 && process == 1 && (word.charAt(index) >= '0'
            && word.charAt(index) <= '9')) {
                NUMBER.append(word.charAt(index));
                index++;
                numberCnt++;
                if (index == file.length()) break;
                if (word.charAt(index) >= '0' && word.charAt(index) <= '9') continue;
                else process = 2;
            } else {
                TAIL.append(word.charAt(index));
                index++;
            }
        }

        fileInfo[0] = HEAD.toString();
        fileInfo[1] = NUMBER.toString();
        fileInfo[2] = TAIL.toString();

        return fileInfo;
    }

이후 이것을 기반으로 조건 o1, o2를 HEAD, NUMBER, TAIL로 된 배열로 만들고

HEAD를 비교하여 정렬, 만약 HEAD 조건이 같다면 NUMBER를 int형으로 구분하여 조건에 맞게 정렬하였다.

Arrays.sort(files, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        String[] o1Info = process(o1);
        String[] o2Info = process(o2);

        if (o1Info[0].compareTo(o2Info[0]) < 0) return -1;
        else if (o1Info[0].compareTo(o2Info[0]) == 0) {
            return Integer.parseInt(o1Info[1]) - Integer.parseInt(o2Info[1]);
        }
        else if (o1Info[0].compareTo(o2Info[0]) > 0) return 1;
        else return 0;
    }
});

그런데 TAIL은 조건과 아무런 관련이 없다. 그래서 process()에서 TAIL과 관련된 부분은 없어도 될 것이다.

아래는 전체 코드이다. 여기서 TAIL과 관련된 부분을 수정하고 TAIL을 처리하는 부분에서 break를 해도 될 것이다.

import java.util.Arrays;
import java.util.Comparator;
class Solution {
    public String[] solution(String[] files) {
         Arrays.sort(files, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                String[] o1Info = process(o1);
                String[] o2Info = process(o2);

                if (o1Info[0].compareTo(o2Info[0]) < 0) return -1;
                else if (o1Info[0].compareTo(o2Info[0]) == 0) {
                    return Integer.parseInt(o1Info[1]) - Integer.parseInt(o2Info[1]);
                }
                else if (o1Info[0].compareTo(o2Info[0]) > 0) return 1;
                else return 0;
            }
        });

        return files;
    }

    public String[] process(String file) {
        String[] fileInfo = new String[3];
        StringBuilder HEAD = new StringBuilder();
        StringBuilder NUMBER = new StringBuilder();
        StringBuilder TAIL = new StringBuilder();
        String word = file.toLowerCase();
        int index = 0;
        int process = 0;
        int numberCnt = 0;

        while (index != file.length()) {
            if (process == 0 && ((word.charAt(index) >= 'a' && word.charAt(index) <= 'z')
                    || word.charAt(index) == '-' || word.charAt(index) ==' '
                    || word.charAt(index) == '.')) {
                HEAD.append(word.charAt(index));
                index++;
                if (index == file.length()) break;
                if (word.charAt(index) >= '0' && word.charAt(index) <= '9') process = 1;
            } else if (numberCnt < 5 && process == 1 && (word.charAt(index) >= '0'
            && word.charAt(index) <= '9')) {
                NUMBER.append(word.charAt(index));
                index++;
                numberCnt++;
                if (index == file.length()) break;
                if (word.charAt(index) >= '0' && word.charAt(index) <= '9') continue;
                else process = 2;
            } else {
                TAIL.append(word.charAt(index));
                index++;
            }
        }

        fileInfo[0] = HEAD.toString();
        fileInfo[1] = NUMBER.toString();
        fileInfo[2] = TAIL.toString();

        return fileInfo;
    }
}