본문 바로가기
AI/Coding_Test

Day 9) 프로그래머스 문자열 문제: 리스트 컴프리헨션, zip, 슬라이싱, 접미사 풀이 정리

by 거대웅 TitanBear 2026. 7. 14.

Day 9 코딩테스트 공부 기록

프로그래머스 문자열 문제: 리스트 컴프리헨션, zip, 슬라이싱, 접미사 풀이 정리

이번 글은 Google 문서에 정리해 둔 문자열 문제 풀이 흐름을 블로그 글로 다시 다듬은 기록입니다. 핵심은 문자열을 자르고, 필요한 부분만 이어 붙이고, 접미사를 만들고, 조건에 맞게 판별하는 것입니다.

처음에는 반복문으로 차근차근 풀고, 그다음 리스트 컴프리헨션, zip(), join(), 음수 슬라이싱, sorted(), endswith()로 더 간단하게 줄이는 흐름까지 정리했습니다.

핵심 1 문자열 슬라이싱
핵심 2 컴프리헨션과 join
핵심 3 접미사와 사전순 정렬
문자열 문제는 “어디서부터 어디까지 자르는가”와 “자른 조각을 언제 합치는가”를 정확히 잡는 것이 핵심이었습니다.

이 글에 빠짐없이 반영한 내용

  1. 배열 만들기 5: s:s+l, int(), 리스트 컴프리헨션, 중복 연산 줄이기
  2. 부분 문자열 이어 붙이기: 잘못된 이중 반복문, zip(), s:e+1, join()
  3. 문자열의 뒤의 n글자: 음수 슬라이싱 [-n:]
  4. 접미사 배열: 접미사 만들기, 리스트 컴프리헨션, 사전순 정렬
  5. 접미사인지 확인하기: in의 한계, 하드코딩 제거, 오타 수정, endswith()

1. 문제 및 프로그래머스 공식 링크

이번 글에서 정리한 문제는 모두 프로그래머스 코딩 기초 트레이닝의 문자열 관련 문제입니다.

프로그래머스 문자열 문제 링크와 핵심 개념
문제 공식 링크 핵심 개념
배열 만들기 5 문제 보기 슬라이싱, 정수 변환, 리스트 컴프리헨션
부분 문자열 이어 붙여 문자열 만들기 문제 보기 zip, 언패킹, join
문자열의 뒤의 n글자 문제 보기 음수 인덱싱, 슬라이싱
접미사 배열 문제 보기 접미사, sorted
접미사인지 확인하기 문제 보기 endswith, 반례, boolean 변환

2. 배열 만들기 5: 자른 문자열을 정수로 바꿔 비교하기

문제 요약

intStrs의 각 문자열에서 s번 인덱스부터 길이 l만큼 잘라냅니다. 잘라낸 부분 문자열을 정수로 바꾼 값이 k보다 크면 결과 배열에 담습니다.

내가 작성한 리스트 컴프리헨션 풀이

def solution(intStrs, k, s, l):
    return [int(intstr[s:s+l]) for intstr in intStrs if int(intstr[s:s+l]) > k]

좋았던 점과 보완할 점

  • intstr[s:s+l]s부터 길이 l만큼 자르는 핵심을 정확히 사용했습니다.
  • 잘라낸 값은 문자열이므로 int()로 정수 변환한 뒤 k와 비교해야 합니다.
  • 다만 int(intstr[s:s+l])가 조건문에서 한 번, 결과 리스트에 넣을 때 한 번, 총 두 번 계산됩니다.

중복 계산을 줄인 기본 풀이

def solution(intStrs, k, s, l):
    answer = []

    for intstr in intStrs:
        num = int(intstr[s:s+l])
        if num > k:
            answer.append(num)

    return answer

처음 공부할 때는 이 풀이가 가장 읽기 쉽습니다. num이라는 변수에 잘라낸 값을 한 번만 저장하고, 조건을 만족하면 answer에 추가합니다.

대입 표현식을 활용한 한 줄 풀이

def solution(intStrs, k, s, l):
    return [val for intstr in intStrs if (val := int(intstr[s:s+l])) > k]

:=는 계산한 값을 변수에 저장하면서 조건식에도 사용할 수 있는 문법입니다. 여기서는 부분 문자열을 정수로 바꾼 값을 val에 저장하고, 그 값이 k보다 큰지 확인합니다. 다만 처음 보는 사람에게는 낯설 수 있으므로, 블로그 글에서는 기본 풀이도 함께 보여주는 편이 좋습니다.

3. 부분 문자열 이어 붙여 문자열 만들기: 두 배열을 1:1로 묶기

문제 요약

my_stringsparts가 같은 길이로 주어집니다. parts[i][s, e] 형태이고, my_strings[i]에서 s부터 e까지 자른 문자열을 순서대로 이어 붙이면 됩니다.

처음 헷갈린 코드

def solution(my_strings, parts):
    answer = ''

    for s, e in parts:
        for i in answer += my_strings[i][s:e]

    return answer

잘못된 점

  • for i in 뒤에 반복할 대상이 비어 있어 문법 오류가 납니다.
  • 이 문제는 모든 문자열에 모든 구간을 적용하는 문제가 아닙니다. 같은 위치의 my_strings[i]parts[i]를 1:1로 매칭해야 합니다.
  • 문제는 e 인덱스까지 포함해서 자르라고 하므로 s:e가 아니라 s:e+1을 써야 합니다.

인덱스를 활용한 정석 풀이 1

def solution(my_strings, parts):
    answer = ''

    for i in range(len(parts)):
        l, r = parts[i]
        answer += my_strings[i][l:r+1]

    return answer

l, r = parts[i]는 언패킹입니다. 예를 들어 parts[i][2, 4]라면 l에는 2, r에는 4가 들어갑니다. 변수 이름을 따로 두면 슬라이싱 범위가 훨씬 잘 보입니다.

인덱스를 직접 쓰는 풀이 2

def solution(my_strings, parts):
    answer = ""

    for i in range(len(parts)):
        answer += my_strings[i][parts[i][0]:parts[i][1] + 1]

    return answer

이 풀이도 정답입니다. parts[i][0]은 시작점, parts[i][1]은 끝점입니다. 다만 대괄호가 많이 겹쳐서 첫 번째 풀이보다 읽기가 조금 어렵습니다.

zip을 활용한 기본 풀이

def solution(my_strings, parts):
    answer = ''

    for string, (s, e) in zip(my_strings, parts):
        answer += string[s:e+1]

    return answer

zip(my_strings, parts)는 문자열 하나와 구간 하나를 동시에 꺼내 줍니다. 그래서 인덱스 i를 직접 만들지 않아도 string[s, e]를 1:1로 다룰 수 있습니다.

join까지 활용한 한 줄 풀이

def solution(my_strings, parts):
    return ''.join(string[s:e+1] for string, (s, e) in zip(my_strings, parts))

문자열을 +=로 계속 더하면 매번 새 문자열을 만드는 흐름이 됩니다. 입력이 크다면 조각들을 모아 join()으로 한 번에 합치는 방식이 더 깔끔합니다.

부분 문자열 풀이 방식 비교
풀이 방식 특징 추천 상황
l, r = parts[i] 시작점과 끝점을 변수로 분리해서 읽기 쉽습니다. 처음 풀이를 설명할 때 좋습니다.
parts[i][0], parts[i][1] 변수를 줄일 수 있지만 대괄호가 많아집니다. 짧게 쓸 때 가능하지만 가독성은 낮습니다.
zip()join() 두 배열을 1:1로 묶고 문자열을 한 번에 합칩니다. 실전에서 가장 깔끔하게 쓰기 좋습니다.

4. 문자열의 뒤의 n글자: 음수 슬라이싱으로 끝에서 자르기

문제 요약

my_string의 뒤에서 n글자만 잘라 반환하면 됩니다.

내 풀이

def solution(my_string, n):
    return my_string[-n:]

[-n:]은 뒤에서 n번째 위치부터 문자열 끝까지 자르겠다는 뜻입니다. 예를 들어 "He110W0r1d"에서 n = 5라면 뒤의 5글자인 "W0r1d"가 반환됩니다.

len(my_string) - n을 안 써도 될까?

파이썬은 음수 인덱스를 지원합니다. -1은 마지막 글자, -2는 뒤에서 두 번째 글자를 의미합니다. 그래서 뒤에서부터 자르는 문제에서는 my_string[len(my_string)-n:]보다 my_string[-n:]이 훨씬 간단합니다.

5. 접미사 배열: 모든 접미사를 만들고 사전순으로 정렬하기

문제 요약

접미사는 어떤 인덱스부터 문자열 끝까지 이어지는 문자열입니다. 예를 들어 "banana"의 접미사는 "banana", "anana", "nana", "ana", "na", "a"입니다. 이 접미사들을 사전순으로 정렬해서 반환해야 합니다.

처음 작성한 코드

def solution(my_string):
    answer = []

    for i in range(len(my_string)):
        answer.append(my_string[i:])

    return answer

접미사를 만드는 로직 자체는 맞습니다. my_string[i:]i번째 인덱스부터 끝까지 자르므로, 모든 접미사를 만들 수 있습니다. 다만 문제에서 요구한 것은 “사전순으로 정렬한 배열”이기 때문에 마지막에 정렬이 필요합니다.

리스트 컴프리헨션으로 줄이기

def solution(my_string):
    return [my_string[i:] for i in range(len(my_string))]

이 코드는 모든 접미사를 만드는 데까지는 깔끔합니다. 하지만 접미사 배열 문제에서는 사전순 정렬 조건이 있으므로 여기서 한 단계 더 가야 합니다.

최종 풀이

def solution(my_string):
    return sorted(my_string[i:] for i in range(len(my_string)))
사전순은 정렬이다

문제에서 “사전순”이라고 나오면 문자열을 오름차순으로 정렬하라는 뜻으로 받아들이면 됩니다. 파이썬에서는 sorted()가 문자열 리스트를 자동으로 사전순 정렬해 줍니다. 예를 들어 ["banana", "apple", "cherry"]를 정렬하면 ["apple", "banana", "cherry"]가 됩니다.

6. 접미사인지 확인하기: 포함 여부가 아니라 끝나는지 확인하기

문제 요약

is_suffixmy_string의 접미사라면 1, 아니면 0을 반환합니다. 접미사는 문자열의 중간에 포함된 단어가 아니라, 문자열의 끝부분과 정확히 일치하는 문자열입니다.

처음 작성한 코드

def solution(my_string, is_suffix):
    answer = 0

    if is_suffix in my_string:
        answer = 1
    elif "nan" in is_suffix:
        answer = 0
    else:
        ansewr = 0

    return answer

잘못된 점

  • is_suffix in my_string은 문자열 어디에든 포함되어 있으면 True입니다. 접미사인지 확인하는 조건으로는 부족합니다.
  • "nan" 같은 특정 테스트 케이스를 직접 넣는 하드코딩은 피해야 합니다. 다른 반례가 나오면 바로 틀립니다.
  • ansewranswer 오타입니다. 파이썬은 새로운 변수로 인식할 수 있어 디버깅이 어려워집니다.

중간 보완 코드와 반례

def solution(my_string, is_suffix):
    answer = 0

    if is_suffix in my_string and is_suffix[-1] == my_string[-1]:
        answer = 1
    else:
        answer = 0

    return answer

처음 코드보다 좋아졌지만 아직 완벽하지 않습니다. 예를 들어 my_string = "abcbac", is_suffix = "bc"라면 "bc"는 문자열 안에 있고 마지막 글자도 "c"로 같습니다. 하지만 "abcbac"의 끝은 "bc"가 아니므로 접미사가 아닙니다.

음수 슬라이싱으로 해결하기

def solution(my_string, is_suffix):
    if my_string[-len(is_suffix):] == is_suffix:
        return 1

    return 0

my_string[-len(is_suffix):]is_suffix의 길이만큼 뒤에서 잘라낸 문자열입니다. 이 조각이 is_suffix와 같으면 접미사입니다.

boolean을 int로 바꾸는 한 줄 풀이

def solution(my_string, is_suffix):
    return int(my_string[-len(is_suffix):] == is_suffix)

파이썬에서 True는 1, False는 0으로 바꿀 수 있습니다. 그래서 비교 결과를 int()로 감싸면 바로 문제의 반환 형태와 맞습니다.

가장 간단한 풀이: endswith

def solution(my_string, is_suffix):
    return int(my_string.endswith(is_suffix))

endswith()는 문자열이 특정 문자열로 끝나는지 확인하는 메서드입니다. 접미사 문제의 의도와 정확히 맞는 도구라서 가장 짧고 안전합니다. 반대로 시작 문자열을 확인할 때는 startswith()를 사용할 수 있습니다.

7. 입출력 예로 빠르게 검산하기

문자열 문제별 빠른 검산 예시
문제 예시 입력 기대 결과
배열 만들기 5 ["0123456789","9876543210","9999999999999"], k=50000, s=5, l=5 [56789, 99999]
부분 문자열 이어 붙이기 ["progressive","hamburger","hammer","ahocorasick"], [[0,4],[1,2],[3,5],[7,7]] "programmers"
문자열의 뒤의 n글자 "He110W0r1d", n=5 "W0r1d"
접미사 배열 "banana" ["a", "ana", "anana", "banana", "na", "nana"]
접미사인지 확인하기 "banana", "nan" 0

8. 실수 방지 체크리스트

  • 길이 l만큼 자를 때는 s:s+l을 사용한다.
  • 끝 인덱스 e를 포함해야 하면 s:e+1을 사용한다.
  • 문자열로 된 숫자는 비교 전에 int()로 바꾼다.
  • 같은 계산을 두 번 한다면 변수에 저장해서 재사용할 수 있는지 확인한다.
  • 두 배열을 같은 인덱스로 묶어야 할 때는 zip()을 떠올린다.
  • 문자열을 여러 조각 이어 붙일 때는 +=보다 join()이 더 깔끔할 수 있다.
  • 뒤에서 n글자를 자를 때는 [-n:]을 사용한다.
  • “사전순”은 문자열 정렬이므로 sorted()를 떠올린다.
  • 접미사는 포함 여부가 아니라 끝부분 일치 여부다. in보다 endswith()가 정확하다.
  • 특정 테스트 케이스만 막는 하드코딩은 피한다.
  • answer처럼 자주 쓰는 변수명은 오타가 나도 에러 없이 새 변수로 생길 수 있으니 철자를 확인한다.

9. 같이 보면 좋은 글

  • 파이썬 문자열 슬라이싱 정리: s:s+l, s:e+1, [-n:], [::-1]을 함께 복습하기 좋습니다.
  • 리스트 컴프리헨션 기초: 반복문과 조건문을 한 줄로 줄이는 연습에 도움이 됩니다.
  • zip과 언패킹: 여러 배열을 동시에 순회하는 문제에서 자주 나옵니다.
  • 문자열 메서드 endswith, startswith: 접두사와 접미사 문제를 빠르게 풀 수 있습니다.

마무리

이번 문서에서 다룬 문제들은 모두 문자열을 다루는 기본기가 중심이었습니다. 처음에는 반복문으로 직접 풀고, 이후에는 리스트 컴프리헨션이나 zip(), join(), sorted(), endswith() 같은 파이썬 도구로 코드를 줄여나가는 흐름이 좋았습니다.

특히 기억해야 할 점은 두 가지입니다. 첫째, 슬라이싱은 끝 인덱스를 포함하지 않으므로 문제에서 “끝까지 포함”이라고 하면 +1을 확인해야 합니다. 둘째, 접미사는 단순히 문자열 안에 포함되어 있는지가 아니라 끝부분과 정확히 일치하는지를 확인해야 합니다.