[알고리즘] 문자열 마음대로 정렬하기

DongGyu Jung·2021년 11월 14일
0
post-thumbnail

※ 본 사진과 해당 게시글 내용의 문제 모두 프로그래머스[Programmers]사이트에 발췌해왔습니다.

💬 들어가기 앞서..

(주의!) 이번 게시물엔 개인적으로 풀어보다 정확도에서 실패한 코드이지만 배운 점과 알아볼 부분이 있어 정답 코드 외 요상한(?) 코드가 출현합니다..

해당문제가 개편되서 다른분들의 풀이가 틀리는 경우가 많았던 것 같아
다른 풀이에서 첫번째로 사용할 코드의 경우는 현재 오답으로 처리되는 코드입니다..!!

❓ 문제

문자열로 구성된 리스트 strings와, 정수 n이 주어졌을 때, 
각 문자열의 인덱스 n번째 글자를 기준으로 오름차순 정렬하려 합니다.
예를 들어 strings가 ["sun", "bed", "car"]이고 n이 1이면 
각 단어의 인덱스 1의 문자 "u", "e", "a"로 strings를 정렬합니다.

제한 조건 : 
strings는 길이 1 이상, 50이하인 배열입니다.
strings의 원소는 소문자 알파벳으로 이루어져 있습니다.
strings의 원소는 길이 1 이상, 100이하인 문자열입니다.
모든 strings의 원소의 길이는 n보다 큽니다.
인덱스 1의 문자가 같은 문자열이 여럿 일 경우, 
사전순으로 앞선 문자열이 앞쪽에 위치합니다.

<입출력 >
strings			| n	| return
["sun", "bed", "car"]	| 1	| ["car", "bed", "sun"]
["abce", "abcd", "cdx"]	| 2	| ["abcd", "abce", "cdx"]


제한 조건 : 
[입출력 예]
예 1
"sun", "bed", "car"의 1번째 인덱스 값은 각각 "u", "e", "a" 입니다.
이를 기준으로 strings를 정렬하면 ["car", "bed", "sun"] 입니다.
예 2
"abce"와 "abcd", "cdx"의 2번째 인덱스 값은 "c", "c", "x"입니다.
따라서 정렬 후에는 "cdx"가 가장 뒤에 위치합니다.
"abce"와 "abcd"는 사전순으로 정렬하면 "abcd"가 우선하므로,
답은 ["abcd", "abce", "cdx"] 입니다.

❗ 풀이

My Code

정답

def solution(strings, n):
    mix = []
    for s in strings :
        mix.append(s[n]+s)
    mix.sort()  
    answer = []
    for s in mix :
        answer.append(s[1:])
    return answer

곧 설명할 예정이지만
밑에 있는 여러 코드들의 실패를 맛보고 해당 문제를 서치하며 다른 분들의 코드를 참고하여 풀게되었다.

우선 결론부터 말해보자면 strings 내부에 있는 단어들의n 인덱스를 가진 글자만 가져와 각 단어들의 에 붙인 후,
붙인 상태에서 정렬한 다음, 다시 분리하여 반환하는 방식이다.

for문을 통해
각 단어들에서 조건(n)위치의 글자를 기존 단어들 앞에 붙여 (.append(s[n]+s))
미리 선언해둔 빈 리스트(mix)에 넣어준 후, 정렬(.sort())한다.
정렬하는 과정은 다른 변수에 대입하지 않고 자체 단독 명령을 해주어야한다.
그 후,
정답으로 반환할 리스트에 붙였던 조건 위치의 글자를 제외한 원래 단어들만 추출해서 넣어주고 정답으로 return한다.


실패

# (1)    
# 정확도 낮음(25%)
def solution(strings, n):
    words = [[word[n:],word] for word in strings]
    words.sort(key=lambda x: x[0])
    answer = []
    for ls in words :
        answer.append(ls[1])
    return answer
 
# (2) 
# 정확도 낮음(25%)
def solution(strings, n):
    mix = []
    for s in strings :
        mix.append([s[n:], s])
    mix = sorted(mix, key=lambda x: x[0])
    return [ls[1] for ls in mix]

우선 놀라웠던 점은..
sort()new_list = mix.sort()와 같이
다른 리스트에 선언하면 안되고 단독 명령해야한다는 점이였다...
NoneType 오류가 발생하는지 궁금해서 더 알아봐야 겠다는 생각이 들었다.

1번부터 살펴 보자면
.sort()를 사용하는 부분까지는 근접했고
key라는 인수로 정렬기준을 지정해서 작성해보았지만 NoneType 오류가 발생한 코드이다.
조건 중 "인덱스 1의 문자가 같은 문자열이 여럿 일 경우,
사전순으로 앞선 문자열이 앞쪽에 위치합니다."
라는 조건 때문에
조건위치의 문자가 같을 경우 를 대비해 뒤따라 오는 글자들까지 같이 합쳐 비교하려했다.
그렇게 [ (정렬 기준 문자) , (기존 문자) ] 로 이루어진 리스트를 가진 이중 리스트를 생성하고
이 리스트를 요소의 첫 번째 값을 기준으로 정렬해주었다.(.sort(key = lambda x:x[0]))
정렬한 후,
다시 각 리스트들의 2번째 값만 따로 추출해서 반환하여 테스트 코드는 통과했지만 제출했을 때 실패하였다.

2번 코드 또한
테스트 코드는 통과했지만 제출했을 때 실패한 코드이다.
비슷해보이지만 다른 점이라 한다면
sorted()라는 메서드를 사용하여 재선언하였고
return은 위 코드와 동일하게 작성하였다.


❣ 다른 풀이

(1)

def strange_sort(strings, n):
    '''strings의 문자열들을 n번째 글자를 기준으로 정렬해서 return하세요'''

    min = []
    result = []
    for i in strings:
        min.append(i[n])
        sorted_min = sorted(min)

    while len(result) != len(strings):
        for j in range(0, len(strings)):
            for k in range(0, len(strings)):
                if sorted_min[j] in strings[k][n]:
                    index = k
                    result.append(strings[index])
                    continue

    return result

현재는 실행시간이 10초가 초과되어서 틀린 답으로 나온 코드이지만
for문과 while문을 중첩시키면서 고민하셨을 노고와 끈기가 대단하신 것 같아 가져왔습니다...!!

위 풀이도 조건위치 글자가 동일할 경우를 대비해서 while문을 사용한 경우이다.
결과를 담을 result 리스트가 기준 글자를 담은 min 리스트의 길이가 다를 동안 돌아가는 while문이다.
중첩 for문으로 가지를 쳐 "string리스트의 길이의 2승"만큼 돌아가는데
각 단어마다 기준 index의 글자를 "정렬된 기준 글자 리스트(min)" 가 있으면 .append 하고 넘어가는(continue) 형식이다.
이렇게 정렬된 순서대로 확인하여 해당하는 글자를 append하는 방법을 사용했다.


(2)

from operator import itemgetter

def solution(strings, n):
    return sorted(sorted(strings), key=itemgetter(n))

operator.itemgetter 모듈은 주로 sorted와 같은 정렬 함수의 key 매개변수에 적용되어
다중 수준의 정렬을 가능하게 해주는 모듈이라고 한다.
itemgetter()리스트튜플들이 중첩되어 구성된 배열에서 특정 위치의 값들만 가져오는 기능을 수행한다.

위 코드는
1차적으로 정렬한 string을 다시
기준 글자를 key로 재정렬한 것을 알 수 있다.
(확실하게 처리하는 군요....)


0개의 댓글