Strings - Merge the Tools!

String에 이런저런 작업을 하는 문제인데 문제 번역하는 데에 시간이 걸렸다. Medium 레벨이라 조금 골치아팠지만 새로운 dict.fromkeys() 메서드를 알고 사용해보았다.

문제 풀이

문제 해석

  • 문자열 s는 n의 길이를 가지고 있으며 s = c0c1…cn-1처럼 각 문자로 이루어져있다.
  • 정수 k는 n의 약수이다.
  • s를 n/k 개의 문자열로 나누는데, 각 문자덩어리 ti는 k개의 문자로 이루어져 있다.
  • ti에 속한 문자 중 중복되는 문자를 제거한 ui를 한 줄로 하는, k개 줄을 출력한다.

Input Format

  • 첫번째 줄은 s라는 문자열을 입력한다.
  • 두번째 줄은 각 문자열덩어리의 문자 개수를 지칭하는 k라는 정수를 입력한다.

문제 풀이

이미 주어진 코드 해석

1
2
3
4
5
6
def merge_the_tools(string, k):
# your code goes here

if __name__ == '__main__':
string, k = input(), int(input())
merge_the_tools(string, k)
  • string과 k를 인수로 받는 merge_the_tools라는 함수를 완성시키는 것이 오늘의 미션
  • string과 k는 친절한 해커랭크가 알아서 문자열과 정수형태로 입력받고, 내가 완성할 함수에 인수로 넣어 호출해준다는 것을 알 수 있다.

Pseudocoding

  • 두가지 단계로 작업을 나눠보았다.
  • 먼저 string을 k개의 문자를 가진 n/k개의 문자덩어리 ti로 나누어주자
  • 이제 리스트를 구성하는 각 ti에 대해서, 중복된 문자가 삭제된 ui으로 바꿔주는 작업을 해준다.

코드 작성하기

  • string을 나누어주는 건 인덱스값으로 작업하는 방법 말곤 생각이 안나서 빈 list 하나를 만든 후 for문을 n/k번 돌리면서 k개 단위로 끊은 문자를 append해주었다.
    1
    2
    3
    4
    def merge_the_tools(string, k):
    t_list = []
    for i in range(int(len(string)/k)):
    t_list.append(string[k*i:k*(i+1)])
  • 두번째 단계는 리스트의 각 요소에 대해 작업해주는 거니까 map함수로 해주기로 했다.
    • map에 넣을 콜백함수로 람다를 쓰는데, 각 요소에서 중복된 문자를 제거하기 위해 dict.fromkeys()메서드를 써서 중복문자를 제거하고 빈 문자열로 다시 join하였다.
    • print의 인수로 넘길 땐 asterisk *로 맵 객체 안의 내용을 풀고, 각 요소는 sep='\n'를 통해 개행하며 출력되게 했다.
      1
      print(*map(lambda x: ''.join(dict.fromkeys(x)), t_list), sep='\n')

시행착오

  • 처음엔 아래와 같이 람다함수에 set으로 중복문자를 제거하려고 했는데 그렇게 하니까 정렬이 이상하게 되었다.
    1
    # print(*map(lambda x: ''.join(set(x)), t_list), sep='\n')
  • 예컨대 문자열 ‘CAA’에 대해서는 ‘AC’로, 문자열 ‘ADA’에 대해서는 ‘DA’로 결과물을 내뱉는다. 공식문서에 보면 set은 기존 위치를 기억하거나 삽입한 순서로 정렬하지 않는다고 한다. 원하는 기대값을 안정적으로 얻기 위해 다른 방법을 찾아야만 했다.
  • StackOverflow에서 비슷한 질문의 답변을 참고하여 dict.fromkeys라는 메서드를 알게되었다.
  • 공식문서의 dict.fromkeys() 설명을 찾아보면 다음과 같다.
    • iterable로부터 받은 값을 key로 한 새로운 dict를 리턴한다. 두 번째 인수로 준 값을 각 key의 value로 넣기도 하는데 이건 옵션이며, 두번째 인수를 비워두면 None으로 디폴트값을 준다.
    • 딕셔너리에서 하나의 key값은 한 번만 사용할 수 있으므로 중복이 제거되고, 순서는 유지된다. (왜 유지되는지는 사실 모르겠다…)
  • 이 딕셔너리를 다시 하나하나 조인해주면 중복이 제거되고 순서는 유지된 문자열을 얻을 수 있으므로 set으로 인한 순서 뒤죽박죽 문제를 해결할 수 있다.

느낀 점

  • 새로운 메서드를 알게되는 건 언제나 환영이야.
  • for문의 range를 int로 따로 또 나눠줘야 하는게 지저분해보이는데 다른 방법이 없으려나 싶다.
  • 시간복잡도도 고려하고싶은데 내 역량으론 아직 무리인게 아쉽다.