본문 바로가기

Programming/알고리즘 파이썬 문제풀이

[Python/LeetCode] 937. Reorder Data in Log Files

https://leetcode.com/problems/reorder-data-in-log-files/description/

로그를 재정렬하라. 기준은 다음과 같다.

1. 로그의 가장 앞 부분은 식별자다.

2. 문자로 구성된 로그가 숫자 로그보다 앞에 온다.

3. 문자 로그는 내용물들 가지고 사전식 순서대로 하되, 내용물들이 동일할 경우 식별자 가지고 사전식 순서대로 한다.

4. 숫자 로그는 입력 순서대로 한다.

 

입력 : 문자열 logs

출력 : 주어진 조건에 따라 재정렬된 문자열을 return

Input: logs = ["dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3 art zero"]
Output: ["let1 art can","let3 art zero","let2 own kit dig","dig1 8 1 5 1","dig2 3 6"]

직관 및 접근

 

리스트 내 요소들을 가지고, 걔네들의 두 번째 단어를 가지고 일단 정렬할거임.

숫자인 놈들은 나중에 한꺼번에 리스트에 append하면 될거고, 

문자인 놈들 먼저 재정렬해서 리스트에 append 하자.

문자냐 숫자냐는 isdigit() 써서 반환값 체크하자.

 

근데, 이거 앞에서부터 훑을 건데, 숫자인 놈을 어떻게 나중에 append할까?

-> 걍, 숫자 리스트 따로 하나 만들어놓고, 나중에 그거 합치자. 그거밖에 없을듯.=

class Solution:
    def reorderLogFiles(self, logs: List[str]) -> List[str]:
        letters, digits = [], []
        for log in logs:
            if log.split()[1].isdigit():
                digits.append(log)
            else:
                letters.append(log)

일단 여기까지는 맞다.

 

이제, 

1. letters 리스트를 재정렬하고

2. 두 리스트를 합치면 된다.

 

두 리스트를 합치는 것 자체는 그냥 

`return letters + digits` 하면 된다. 리스트끼리의 덧셈은, 그냥 요소들을 합친 새로운 리스트를 반환하기 때문.

그럼 어떻게 letters 리스트를 재정렬할 수 있을까?

 

-> list의 메서드 sort()를 사용하자.

-> 근데, 어떻게 잘 사용해야 내부 문자 사전식으로 정렬 가능할까?

-> 우리가 그냥 sorted() 함수나 sort() 메서드에 매개변수 없이 사용하면,

앞에서부터 각 문자로 사전식 비교하므로 우리가 원하는 게 아니다.

우리가 원하는 건 두 번째 단어부터 비교하다가, 모두 같으면 첫 번째 단어로 비교하는 거임.

-> 임시적으로 첫 번째 단어를 제일 뒤로 밀고, 두 번째 단어부터를 앞으로 가져온 뒤에 sort()로 비교하자!!

-> sort()의 key에 위 연산을 적용한 리스트를 반환하는 함수를 집어넣자.

 

책에 따른 정답은, 다음과 같음.

`letters.sort(key=lambda x: (x.split()[1:], x.split()[0]))`

그냥 우리가 함수 정의해서 써도 되나, 여기서는 람다로 간결하게 표기했음.

실전에서는 람다 굳이 안 써도 되니까, 부담 nono.

 

튜플 `(x.split()[1:], x.split()[0])`를 key로 쓴단 건, 튜플의 첫 요소로 먼저 비교하고, 같으면 두 번째 요소로 비교한다는 거.

참고 : https://0xffffffff.tistory.com/59

 

여기서 핵심은 람다가 아니라, `첫 단어를 제일 뒤로 민다는 아이디어`임.


공부내용

* sort() 메서드의 매개변수

- key (선택적): 정렬 기준을 지정하는 함수입니다. 각 요소에 대해 key 함수를 호출한 결과를 기준으로 정렬합니다.

key에 람다식을 많이 사용하는데, 튜플을 대입할 경우 튜플의 원소 순대로 비교함.

- reverse (선택적): True이면 내림차순으로 정렬합니다. 기본값은 False(오름차순).

 


람다 쓴 풀이

class Solution:
    def reorderLogFiles(self, logs: List[str]) -> List[str]:
        letters, digits = [], []
        for log in logs:
            if log.split()[1].isdigit():
                digits.append(log)
            else:
                letters.append(log)

        letters.sort(key=lambda x: (x.split()[1:], x.split()[0]))
        return letters + digits

람다 안 쓴 풀이

class Solution:
    def reorderLogFiles(self, logs: List[str]) -> List[str]:
        def get_sort_key(log: str):
            # 식별자와 내용을 분리
            return x.split()[1], x.split()[0]
            
            ...
            
        letters.sort(key=get_sort_key)

아까 풀이를 람다식을 안쓰고 함수 선언해 쓰면 위와 같음.

 

 


해당 글은 "파이썬 알고리즘 인터뷰(박상길)"을 공부한 내용과 책의 코드가 포함되어 있습니다.

https://github.com/onlybooks/python-algorithm-interview/tree/master