To Lower Case
문자열 s가 주어집니다. 모든 영문 대문자 A부터 Z를 해당하는 소문자로 바꾼 새 문자열을 반환하세요. 소문자, 숫자 또는 기호와 같은 다른 모든 문자는 그대로 유지됩니다.
함수
- sstring
- 변환할 텍스트
- 반환값string
- 모든 대문자를 소문자로 바꾼 s
제약 조건
1 ≤ s.length ≤ 104s의 모든 문자는 영문자, 숫자 또는 다음 기호 중 하나입니다:!#$%&()*+-./:;<=>?@[]^_`{|}~.
예제
- 입력
- s = "Hello-World!"
- 출력
- "hello-world!"
- 설명
- 대문자
H와W는h와w가 됩니다.-와!는 문자가 아니므로 그대로 유지됩니다.
- 입력
- s = "coddy_2026"
- 출력
- "coddy_2026"
- 설명
- 변경할 대문자가 없습니다. 소문자,
_, 숫자는 변경되지 않고 그대로 돌아옵니다.
- 입력
- s = "SQL"
- 출력
- "sql"
- 설명
- 세 글자 모두 대문자이므로 각각 소문자로 변환됩니다.
제출 시 숨은 테스트 +15개
후속 질문
같은 루프를 사용해 toUpperCase를 작성하고, 문자 코드에서 한 비트만 다른 이유가 A와 a 사이에 무엇인지 설명할 수 있나요?
힌트
하나씩 열어 보세요. 열 때마다 조금 더 알려 줍니다.
컴퓨터는 각 문자를 숫자로 저장합니다.
A와a에 해당하는 숫자는 어떤 관계가 있을까요?A부터Z까지는 코드 65부터 90까지이고,a부터z까지는 97부터 122까지입니다. 각 대문자는 해당 소문자보다 정확히 32 작습니다.문자를 하나씩 확인하세요. 코드가 65에서 90 사이이면 32를 더하고, 그렇지 않으면 문자를 그대로 둡니다. 결과를 모아 하나로 합쳐 답을 만드세요.
풀이
모든 언어에는 소문자로 변환하는 함수가 제공되며, 실제 운영 코드에서는 이 함수를 호출해야 합니다. 면접관이 이 문제를 묻는 이유는 이 함수의 작동 방식을 알고 있는지 확인하기 위해서입니다. 문자는 숫자이며, ASCII에서 각 대문자는 해당 소문자보다 코드값이 정확히 32만큼 낮습니다. 코드값이 'A'와 'Z' 사이에 있는지 확인하고, 그렇다면 32를 더하세요.
내장 소문자 변환 함수를 호출하세요
핵심 아이디어
Python의 lower(), JavaScript의 toLowerCase(), Ruby의 downcase와 다른 모든 언어의 해당 함수들은 이미 이 작업을 수행합니다. C와 C++는 한 문자에 적용하는 tolower를 제공하므로, 반복문에서 호출하면 됩니다. 각 문자를 한 번씩 살펴보므로 작업에는 O(n)이 걸리고, 새 문자열에는 O(n)의 공간이 필요합니다.
이 함수 중 일부는 컴퓨터의 언어 설정을 따릅니다. 터키어에서는 I의 소문자가 i가 아니라 점이 없는 ı입니다. 그래서 Java와 C# 버전에서는 컴퓨터마다 결과가 달라지지 않도록 Locale.ROOT와 ToLowerInvariant를 사용해 고정된 규칙을 지정합니다.
실무에서는 이것이 올바른 답입니다. 하지만 면접에서는 질문의 핵심인 아이디어를 가려 버리기 때문에 이 답을 인정하지 않는 경우가 많습니다.
알고리즘
s에 해당 언어의 소문자 변환 함수를 호출하거나, C와 C++에서는 각 문자에tolower를 호출하세요.- 함수가 제공하는 경우, 언어에 독립적인 고정 규칙을 요청하세요.
- 결과를 반환하세요.
def toLowerCase(s):
return s.lower()대문자의 문자 코드를 이동합니다
핵심 아이디어
모든 문자는 숫자로 저장됩니다. ASCII에서 A부터 Z까지는 코드 65부터 90까지이고, a부터 z까지는 97부터 122까지입니다. 두 범위는 모두 알파벳 순서이며 시작점이 32만큼 차이가 나므로, 대문자의 소문자 코드는 해당 대문자 코드에 32를 더한 값입니다. H는 72이고 h는 104입니다.
따라서 문자열을 한 번 순회합니다. 코드가 65와 90 사이에 있으면 32를 더하고, 그렇지 않으면 문자를 그대로 복사합니다. 범위 확인이 중요합니다. 기호 [, ^, _는 Z와 a 사이에 있고, @는 A 바로 앞에 있습니다. code < 97만 검사하면 _가 다른 기호로 바뀝니다.
각 문자는 한 번씩 확인하므로 시간 복잡도는 O(n)입니다. 결과는 길이가 같은 새 문자열이므로 공간 복잡도는 O(n)입니다. 32 대신 'a' - 'A'라고 쓰면 같은 의미이며, 그 숫자가 어디서 나오는지도 설명해 줍니다.
알고리즘
s를 문자 또는 코드의 배열로 복사합니다.- 각 위치에서 문자 코드를 읽습니다.
- 코드가
'A'(65)와'Z'(90) 사이에 있으면 32를 더합니다. - 배열을 다시 문자열로 변환하여 반환합니다.
def toLowerCase(s):
# Every capital letter sits 32 codes below its small letter: 'A' is 65, 'a' is 97.
shift = ord("a") - ord("A")
chars = []
for ch in s:
if "A" <= ch <= "Z":
ch = chr(ord(ch) + shift)
chars.append(ch)
return "".join(chars)
함정과 경계 사례
루프는 짧으므로, 오류는 범위 검사와 결과를 만드는 방식에 있습니다.
- 소문자가 아닌 모든 문자에 32를 더합니다. 숫자와 기호도 바뀝니다.
1은Q가 됩니다. - 범위의 한쪽 끝만 확인합니다.
code < 'a'는[,_,@도 잡아내고,code >= 'A'는 모든 소문자도 잡아냅니다. - 범위의 끝에서
<=대신<를 사용하면A또는Z가 대문자로 남습니다. - 불변 문자열에서
result = result + ch로 결과를 만듭니다. 각 단계에서 지금까지의 내용을 모두 복사하므로,n = 10^4일 때 시간 복잡도는 이차가 됩니다. - C에서는 입력에 덮어쓰거나 종료 문자
'\0'를 빠뜨리지 않도록 합니다. 복사본을 위해n + 1바이트를 할당하세요.
자주 묻는 질문4
내장 함수 없이 문자열을 소문자로 어떻게 변환하나요?
문자를 반복하면서 각 문자의 코드를 살펴보세요. 코드가 65(A)와 90(Z) 사이이면 32를 더해 소문자로 바꾸고, 그 외의 모든 문자는 그대로 두세요. 문자들을 다시 하나의 문자열로 결합하세요.
대문자와 소문자의 차이가 왜 32인가요?
ASCII는 대문자를 코드 65~90에, 소문자를 97~122에 배치하고 그 사이에는 기호 6개가 있습니다. 두 알파벳은 같은 순서이므로 각 쌍은 97 - 65 = 32만큼 떨어져 있습니다. 32는 단일 비트이므로 그 비트를 설정하면 대문자가 해당 소문자로 바뀝니다.
비트 연산으로 대소문자를 바꿀 수 있나요?
맞습니다. 대문자의 경우 code | 32는 두 대소문자를 구분하는 비트를 설정해 소문자로 바꾸고, code & ~32는 이 비트를 다시 지웁니다. 같은 비트 트릭을 사용하면 숫자와 기호도 바뀌므로 먼저 범위를 확인해야 합니다.
문자열을 소문자로 변환하는 시간 복잡도는 얼마인가요?
길이가 n인 문자열의 경우 각 문자를 한 번씩 확인하므로 O(n)입니다. 새 문자열은 O(n)의 공간을 차지합니다. 문자 배열을 제자리에서 변경할 수 있다면 추가 공간은 O(1)로 줄어듭니다.
비슷한 문제
같은 아이디어를 쓰는 문제입니다. 두세 개를 풀면 패턴이 몸에 익습니다.
Python
def toLowerCase(s):
# 여기에 코드를 작성하세요케이스 1
케이스 2
케이스 3
입력
s = "Hello-World!"
기대값
"hello-world!"