새소식

Career/Coding Test

99클럽 코테 스터디 3/99일차 TIL # 문자열 내 마음대로 정렬하기(미들러)

  • -
반응형

 

 

문제: 문자열 내 마음대로 정렬하기

출처: 프로그래머스

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

1. 문제 설명


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


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

2. 문제 해석

strings: 문자열로 구성된 배열

n: 배열에 구성된 문자열들을 새로운 기준으로 재배열 하는 기준이 되는 index 값

이를 바탕으로 n의 위치에 있는 문자를 기준으로 빠른 문자가 앞으로, 느린 문자가 뒤로 재배열해야한다.

그리고 동일한 순서일 경우 해당 문자열들을 사전순으로 다시 배열해야한다.

1. strings를 돌면서 해당하는 위치(n)에서 문자의 우선순위 값을 얻기

- ord()를 이용해서 유니코드 정수로 변환

ord('a') = 97

ord('b') = 98

2. 해당 우선순위를 key로, 해당 문자열을 value로 구성된 dictionary 만들기

- 이 부분에서 실수를 하여 첫 코드가 점수가 엉망이 나왔다.

3. dictonary를 key 값을 기준으로 오름차순 재배열

- sorted() 함수 이용하여 재배열

- 새로운 list에 재배열된 dict의 key 값에 따라 append

4. 1개가 아닌 여러 값이 있는 경우 재정렬

- 같은 ord() 값이 나왔을 경우 이를 오름차순으로 재정렬

 

3. 문제 풀이

 

풀이 (1) 41.7/100

def solution(strings, n):
    
    dic = dict()
    
    tmp = []
    for string in strings:
        
        
        if ord(string[n]) in tmp:
            
            dic[ord(string[n])] = [dic[ord(string[n])]]
            dic[ord(string[n])].append(string)
            
        else:
            dic[ord(string[n])] = string
        
        tmp.append(ord(string[n]))
            
    print(dic)
    
    sorted_dic = sorted(dic)
    print(sorted_dic)
    
    tmp_ = []
    for i in sorted_dic:
        tmp_.append(dic[i])
    
    answer = []
    for val in tmp_:
        
        if type(val) == list:
            sorted_val = sorted(val)
            for val_ in sorted_val:
                answer.append(val_)
        else:
            answer.append(val)
    
    print(answer)
    
    
    return answer

테스트 1 통과 (0.02ms, 10.2MB)
테스트 2 통과 (0.03ms, 10.2MB)
테스트 3 실패 (런타임 에러)
테스트 4 실패 (런타임 에러)
테스트 5 통과 (0.02ms, 10.2MB)
테스트 6 실패 (런타임 에러)
테스트 7 실패 (런타임 에러)
테스트 8 실패 (런타임 에러)
테스트 9 통과 (0.03ms, 10.3MB)
테스트 10 실패 (런타임 에러)
테스트 11 통과 (0.03ms, 10.3MB)
테스트 12 실패 (런타임 에러)

 

해당 풀이 방식으로 테스트는 통과하였으나 절반 이상의 테스트 케이스에서 런타임 에러가 발생하였다.

가장 큰 코드상의 문제는 2개 중복으로 존재할 경우와 1개만 존재할 경우에 tmp에 넣는 로직을 잘못 설계했다.

tmp 리스트를 이용해서 한번이라도 나온적이 있는지를 판단하는 방식으로 조건문을 설계했다.

하나라도 있을 경우 list를 새로 만들고, 그 리스트에 원래의 값과 새로 나온 값을 추가하는 방식으로 짜려고 했...지만

잘못짠 것을 짚어보면 - dic[ord(string[n])] = [dic[ord(string[n])]] 부분을 아주 댕청하게 짰다.

원래의 값을 저장을 해두고 넣어야 하는데 그냥 현재 값을 넣었던 것이다.

만약에 이전 값을 임시 저장하고 리스트에 넣어서 쓰면 되는데 그렇게 되면 한 개가 있을 경우, 2개가 있을 경우 또 문제가 발생한다.

이렇게 짠 이유를 생각해보면 dictionary에 값을 추가할 경우 key 값이 있는경우와 없는 경우에 추가하는 방식이 다르다.

그리고 원래 있는 경우에도 key에 대한 value가 int 형태 또는 string 형태로 있으면 append가 불가능하다.

dic에 'car'라는 key값에 1이라는 value가 있는 상황에 2 value는 추가 불가능하다. 따라서 여러 values를 다루려면 애초에 list 형태의 value로 설정해야한다.

그러다보니 list 형태 쓰는 것과 안쓰는 것을 분리해서 생각하다보니 저런 이상한? 코드가 나왔던 것 같다.

풀이 (2) 100/100

def solution(strings, n):
    
    dic = dict()
    tmp = []
    
    for string in strings:
        
        if ord(string[n]) not in tmp:
                dic[ord(string[n])] = []
                dic[ord(string[n])].append(string)
              
        else:
            dic[ord(string[n])].append(string)
        tmp.append(ord(string[n]))
            
    sorted_dic = sorted(dic)
    
    tmp_ = []
    
    for i in sorted_dic:
        tmp_.append(dic[i])
    
    answer = []
    
    for val in tmp_:
        
        if type(val) == list:
            sorted_val = sorted(val)
            for val_ in sorted_val:
                answer.append(val_)
        else:
            answer.append(val)
            
    return answer

앞서 (1)의 풀이에서 언급한 부분을 해결하고자 1개건 2개건 1개라도 나오면 value를 리스트 형태로 만들어 해당 값을 append 했다.

이렇게 되니 로직이 생각보다 더 간단해졌고 나중에 중복이 있는 경우는 type으로 확인할 필요 없이 len으로 해당 값이 2개이상일 경우로 확인하면 되었다.

거기에다 해당 list를 sorted만 해주면 추가적인 사전정렬이 마무리 된다.

 

테스트 1 통과 (0.01ms, 10.2MB)
테스트 2 통과 (0.02ms, 10.3MB)
테스트 3 통과 (0.06ms, 10.2MB)
테스트 4 통과 (0.05ms, 10.4MB)
테스트 5 통과 (0.02ms, 10.2MB)
테스트 6 통과 (0.04ms, 10.3MB)
테스트 7 통과 (0.02ms, 10.3MB)
테스트 8 통과 (0.03ms, 10.2MB)
테스트 9 통과 (0.02ms, 10.1MB)
테스트 10 통과 (0.05ms, 10.2MB)
테스트 11 통과 (0.03ms, 10.1MB)
테스트 12 통과 (0.10ms, 10.3MB)

모든 테스트 케이스를 통과하였다.

 

5. 주요 코드 및 정리

 

5.1 ord(): 문자열을 유니코드(숫자) 형태로 변환

ord('a') = 97

5.2 sorted(): 배열 오름차순 정렬

 

5.3 dict 타입 다루기

# dict 생성
dic = dict()

# key, value를 dict에 추가하기
dic.append(key) = value

# 하나의 key에 여러 value를 다루고 싶은 경우
=> value를 list 형태로 사용
dic[ord(string[n])] = []
dic[ord(string[n])].append(string)

 

문제가 단순하게는 보이지만 정작 코드를 짰을때 생각보다 이리 갔다 저리 갔다 해야해서 헷갈리는게 은근 있었다.

test case는 통과했지만 실제 제출 시 반 정도 밖에 맞지 않아 로직을 하나씩 새로 확인하는데 오래 걸렸다.

오랜만에 dict 타입을 다루다보니 까먹은 부분도 있었던 것 같다.

 

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.