🧱
기본 자료구조
슬라이싱·문자열 메서드·아스키 활용
04. 배열과 문자열 (Arrays & Strings)
투 포인터·회문 판별·애너그램 등 배열·문자열 응용 패턴의 토대를 만듭니다.
배열문자열투 포인터
소요 시간
⏱ 약 1시간
난이도
📊 초급
선수 조건
🎯 기초 트랙
결과물
투 포인터·회문 판별·애너그램 등 배열·문자열 응용 패턴의 토대를 만듭니다.
이 강의에서 배우는 것
- 1Python `list`(동적 배열)의 슬라이싱 문법과 복잡도를 정확히 이해한다.
- 2문자열 주요 메서드를 활용하고, 불변성으로 인한 성능 이슈를 회피할 수 있다.
- 3투 포인터 기법을 이용해 팰린드롬 검사 등의 배열/문자열 문제를 O(n)에 풀 수 있다.
소개
배열(Array)은 모든 자료구조의 근간이 되는 가장 기본적인 선형 자료구조입니다. Python에서는 `list`가 동적 배열(Dynamic Array) 역할을 하며, 인덱스를 이용해 O(1)에 임의 접근이 가능합니다.
문자열(String)은 Python에서 **불변(Immutable)** 객체입니다. 한 번 생성된 문자열은 변경할 수 없으며, `+=` 연산을 반복하면 매번 새로운 문자열 객체가 생성됩니다. 이 특성은 코딩 테스트에서 **성능 함정**이 되기 쉬우므로 반드시 이해해야 합니다.
text
인덱스: 0 1 2 3 4
+----+----+----+----+----+
값: | 10 | 20 | 30 | 40 | 50 |
+----+----+----+----+----+
^ ^
arr[0] arr[-1]핵심 개념
1. 슬라이싱 (Slicing)
python
arr = [0, 1, 2, 3, 4, 5]
arr[1:4] # [1, 2, 3] -- 인덱스 1 이상 4 미만
arr[:3] # [0, 1, 2] -- 처음부터 3 미만
arr[3:] # [3, 4, 5] -- 3부터 끝까지
arr[::-1] # [5, 4, 3, 2, 1, 0] -- 역순
arr[::2] # [0, 2, 4] -- 2칸 간격
arr[1:5:2] # [1, 3] -- 1부터 5미만 2칸 간격| 연산 | 시간 복잡도 | 설명 |
|---|---|---|
| `arr[i]` | O(1) | 인덱스 접근 |
| `arr[i:j]` | O(j-i) | 슬라이싱 (복사 발생) |
| `arr.append(x)` | O(1) 균상 | 끝에 추가 |
| `arr.insert(i, x)` | O(n) | 중간 삽입 (이동 필요) |
| `arr.pop()` | O(1) | 끝 제거 |
| `arr.pop(i)` | O(n) | 중간 제거 (이동 필요) |
| `x in arr` | O(n) | 선형 탐색 |
| `len(arr)` | O(1) | 길이 조회 |
💡
**주의**: `arr[i:j]` 슬라이싱은 O(j-i)의 **새로운 리스트를 복사**합니다.
2. 문자열 메서드 (String Methods)
| 메서드 | 설명 | 예시 | 반환값 |
|---|---|---|---|
| `split(sep)` | 구분자로 분리 | `"a,b".split(",")` | `["a","b"]` |
| `join(iter)` | 이터러블 연결 | `",".join(["a","b"])` | `"a,b"` |
| `strip()` | 양쪽 공백 제거 | `" ab ".strip()` | `"ab"` |
| `lstrip()` | 왼쪽 공백 제거 | `" ab ".lstrip()` | `"ab "` |
| `rstrip()` | 오른쪽 공백 제거 | `" ab ".rstrip()` | `" ab"` |
| `replace(old,new)` | 문자열 치환 | `"abab".replace("a","x")` | `"xbxb"` |
| `find(sub)` | 부분 문자열 위치 | `"hello".find("ll")` | `2` |
| `upper()` | 대문자 변환 | `"hello".upper()` | `"HELLO"` |
| `lower()` | 소문자 변환 | `"HELLO".lower()` | `"hello"` |
| `count(sub)` | 등장 횟수 | `"abab".count("ab")` | `2` |
| `startswith(s)` | 접두어 확인 | `"hello".startswith("he")` | `True` |
| `endswith(s)` | 접미어 확인 | `"hello".endswith("lo")` | `True` |
3. ASCII 코드 -- ord / chr
python
ord('A') # 65
ord('a') # 97
ord('0') # 48
chr(65) # 'A'
chr(97) # 'a'
# 알파벳 인덱스 (0-based)
idx = ord('c') - ord('a') # 2| 문자 범위 | ASCII 시작 |
|---|---|
| '0' ~ '9' | 48 ~ 57 |
| 'A' ~ 'Z' | 65 ~ 90 |
| 'a' ~ 'z' | 97 ~ 122 |
4. 투 포인터 (Two Pointer) -- 팰린드롬 검사
text
문자열: r a c e c a r
인덱스: 0 1 2 3 4 5 6
^ ^
left right
비교 r==r -> 이동
^ ^
비교 a==a -> 이동
^ ^
비교 c==c -> 이동
^ ^
비교 e==e -> 이동
left > right -> 팰린드롬!투 포인터를 사용하면 O(n) 시간, O(1) 공간으로 팰린드롬을 검사할 수 있습니다.
예제로 보기
| 파일 | 내용 | 핵심 개념 |
|---|---|---|
| `src/01_slicing.py` | 슬라이싱 기초 + 2D 예제 | 인덱싱, 복사, 역순 |
| `src/02_string_methods.py` | 문자열 메서드 실습 | split, join, replace |
| `src/03_palindrome.py` | 팰린드롬 검사 (나이브 + 투포인터) | two-pointer, O(n) |
| `src/04_anagram.py` | 애너그램 검사 | Counter, sorted |
자주 하는 실수
실수 1: 문자열 += 반복 사용 -- O(n^2) 함정
python
# 잘못된 방법 -- O(n^2): 매번 새로운 문자열 객체 생성
result = ""
for c in chars:
result += c # 매번 O(n) 복사!
# 올바른 방법 -- O(n): 리스트에 모아서 join
parts = []
for c in chars:
parts.append(c)
result = "".join(parts) # 한 번만 복사실수 2: `in` 연산자의 복잡도 착각
python
arr = [1, 2, 3, ..., 1000000]
if x in arr: # O(n) 선형 탐색!
...
# 자주 검색한다면 set 또는 dict 사용 -> O(1)
lookup = set(arr)
if x in lookup: # O(1)
...실수 3: 슬라이싱이 복사를 생성함을 잊음
python
arr = [1, 2, 3, 4, 5]
sub = arr[1:4] # 새로운 리스트 복사, O(k) 시간 + O(k) 공간
sub[0] = 99
print(arr) # [1, 2, 3, 4, 5] -- 원본 불변실수 4: `split()` vs `split(' ')`
python
"a b".split() # ['a', 'b'] -- 연속 공백 무시
"a b".split(' ') # ['a', '', 'b'] -- 빈 문자열 포함!실수 5: 문자열과 정수 비교 시 ord() 혼동
python
# 잘못된 예
if 'a' > 'Z': # True -- 아스키값 97 > 90
...
# 의도한 동작을 위해 lower()/upper() 사용
if 'a'.lower() == 'A'.lower(): # True
...정리
| 개념 | 핵심 포인트 |
|---|---|
| 동적 배열 | Python list, 임의 접근 O(1), 삽입/삭제 O(n) |
| 슬라이싱 | O(k) 복사 발생, 원본 불변 |
| 문자열 | 불변 객체, += 반복은 O(n^2) |
| join() | 문자열 조합은 항상 join()으로 O(n) |
| 투 포인터 | 양 끝에서 좁혀오는 기법, O(n) 시간 O(1) 공간 |
| ord/chr | 문자<->아스키 변환, 알파벳 인덱스 계산 |
직접 해 보기
- `src/01_slicing.py` 를 실행하고 각 슬라이싱 결과를 예측해 보세요.
- `src/03_palindrome.py` 에서 투 포인터 과정을 손으로 그려 보세요.
- `src/04_anagram.py` 에서 Counter 없이 직접 딕셔너리로 구현해 보세요.
- `homework/README.md` 의 과제를 풀어 보세요.