문제 소개
첫 번째 인수로 문자열을, 두 번째·세 번째 인수로 각각 시작 인덱스(start)와 끝 인덱스(end)를 받는 JavaScript 함수를 작성해야 합니다. 이 함수는 첫 번째 인수로 전달된 문자열이 자기 자신을 끝없이 이어 붙여 무한히 확장된다고 가정할 때, 시작 인덱스부터 끝 인덱스 직전까지에 해당하는 부분 문자열을 반환해야 합니다.
입력 예시
예를 들어 입력이 다음과 같다고 가정해 보겠습니다.
const str = 'helloo'; const start = 12; const end = 15;
'helloo'를 무한히 반복하면 'helloohelloohelloo…' 형태의 문자열이 됩니다. 이 문자열에서 인덱스 12부터 15 직전까지 잘라낸 결과는 다음과 같아야 합니다.
const output = 'hel';
코드 구현
핵심 아이디어는 간단합니다. 문자열이 일정한 패턴으로 반복되므로 모듈로(%) 연산을 활용하면, 확장된 문자열의 임의 위치에 어떤 문자가 오는지 원본 문자열만으로 알아낼 수 있습니다.
const str = 'helloo';
const start = 12;
const end = 15;
const findSubstring = (str = '', start, end) => {
let res = '';
for (let i = start; i < end; i++) {
res += str[i % str.length];
}
return res;
};
console.log(findSubstring(str, start, end));동작 원리
- i % str.length: 무한히 확장된 문자열에서 i번째 문자는 항상 원본 문자열의 (i % 길이)번째 문자와 같습니다.
- 시작 인덱스부터 끝 인덱스 직전까지 한 글자씩 이어 붙이면 원하는 부분 문자열이 완성됩니다.
더 효율적인 방법
추출 범위가 매우 넓다면(예: 수백만 글자) 한 글자씩 반복하는 방식은 비효율적입니다. 이럴 때는 문자열을 통째로 이어 붙이는 방식으로 성능을 크게 개선할 수 있습니다.
const findSubstring = (str = '', start, end) => {
const n = str.length;
const s = start % n; // 시작 위치가 원본 안에서 차지하는 인덱스
const len = end - start; // 추출해야 할 총 문자 수
let res = '';
// 1) 첫 조각: 시작 위치부터 원본 문자열 끝까지
const firstLen = Math.min(len, n - s);
res += str.slice(s, s + firstLen);
let remaining = len - firstLen;
// 2) 중간 조각: 원본 문자열 전체를 반복해서 붙임
while (remaining >= n) {
res += str;
remaining -= n;
}
// 3) 마지막 조각: 남은 길이만큼 원본 앞부분에서 잘라냄
if (remaining > 0) {
res += str.slice(0, remaining);
}
return res;
};이 방식은 반복 횟수가 추출 범위의 길이가 아니라 문자열 길이에 비례하므로, start = 0, end = 1000000처럼 큰 범위에서도 매우 빠르게 동작합니다.
출력 결과
두 구현 모두 콘솔에 다음과 같은 결과를 출력합니다.
hel