소프트웨어 엔지니어나 웹 개발자를 꿈꾸는 초보 개발자들이 처음으로 마주하는 알고리즘 챌린지 중 하나가 바로 문자열 뒤집기입니다. 문자열이란 단순히 문자와 공백의 모음일 뿐입니다. 우리가 해야 할 일은 예를 들어 "Hello World!"라는 문자열을 받아 "!dlroW olleH"처럼 거꾸로 변환해 반환하는 것입니다. 이 문제를 해결하는 방법은 여러 가지가 있으며, 이 글에서는 대표적인 몇 가지 방법을 소개합니다.
문제 정의
문자열을 뒤집어 반환하는 함수 reverseString을 작성하세요. 뒤집을 문자열은 함수의 인수로 전달됩니다.
해결 방법 1: for 반복문 활용
가장 직관적이고 널리 쓰이는 해결책은 for 반복문을 사용해 문자열을 뒤에서부터 앞으로 순회하는 것입니다. 이때 뒤집힌 문자열을 담아둘 새 변수를 하나 생성하고, 문자열의 각 문자를 순서대로 추가해 나갑니다.
function reverseString(str) {
let newStr = '';
for(let i = str.length - 1; i >= 0; i--) {
newStr += str[i];
}
return newStr;
}for 반복문의 구조를 살펴보겠습니다. 먼저 변수 i를 문자열의 마지막 인덱스(문자열 길이에서 1을 뺀 값)로 설정합니다 ⇒ 이것이 초기화(initialization) 부분으로, 반복이 시작되는 첫 번째 인덱스가 됩니다. 두 번째 부분은 조건(condition)으로, 반복문이 언제 멈춰야 하는지를 결정합니다. 마지막 세 번째 부분은 증감식(increment)으로, 각 반복이 끝난 후 조건이 여전히 참인 동안 i가 얼마나 변할지를 지정합니다. 여기서 i--는 i에 i - 1을 다시 할당하는 것과 같습니다.
각 반복마다 str[i] 위치의 문자를 가져와 newStr에 이어 붙입니다. 모든 반복이 끝나면 for 반복문 밖에서 newStr을 반환하고 함수를 종료합니다.
아래 코드 에디터에서 직접 실행해 보세요:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="" />
<script>
function reverseString(str) {
let newStr = '';
for(let i = str.length - 1; i >= 0; i--) {
newStr += str[i];
}
return newStr;
}
function showInput(e) {
e.preventDefault();
const inputStr = document.getElementById('user_input').value;
if(inputStr.length < 1) {
alert("Must enter a string to reverse. Try again.")
}
let reversed = reverseString(inputStr);
document.getElementById(
'display'
).innerHTML = reversed;
document.getElementById('user_input').value = '';
}
</script>
<style>
* {
box-sizing: border-box;;
}
body {
width: 100%;
max-width: 500px;
height: 100vh;
background: lightblue;
margin: 0 auto;
display: flex;
flex-flow: column wrap;
align-items: center;
justify-content: center;
}
div {
display: flex;
flex-flow: column wrap;
align-items: flex-start;
width: 100%;
}
form {
display: flex;
flex-flow: column wrap;
width: 100%;
background: lightgray;
padding: 20px;
border: 5px double slategray;
}
#user_input {
width: 100%;
}
#submit_button {
width: 25%;
align-self: flex-end;
margin-top: 10px;
}
#display {
font-size: 1.4rem;
height: 50px;
}
</style>
</head>
<body>
<div>
<form onsubmit="showInput(event);">
<label id="label">Enter a String to Reverse:</label>
<input type="text" name="message" id="user_input"/>
<input type="submit" onclick="showInput(event);" id="submit_button"/><br />
<label>Your input: </label>
<p><span id="display"></span></p>
</form>
</div>
</body>
</html>해결 방법 2: ES6 map 메서드 활용
JavaScript에는 ES6에서 새롭게 도입된 내장 배열 메서드인 map이 있습니다. map은 지정된 값들로 구성된 새로운 배열을 반환하며, 세 가지 매개변수를 받습니다: 현재 항목(item), 해당 항목의 인덱스(index), 그리고 원본 배열(array). 이 해결책에서는 후자의 두 매개변수를 활용합니다.
먼저 split() 메서드를 사용해 문자열을 배열로 분리해야 합니다. 빈 문자열('')을 기준으로 split하면 각각의 문자가 개별 요소로 담긴 배열을 얻을 수 있습니다. 그다음 이 새로운 배열을 대상으로 map을 실행합니다.
function reverseString(str) {
let newArr = str.split('');
let rev = newArr.map((letter, index, array) => {
let swapIndex = array.length - index - 1;
return array[swapIndex];
});
return rev.join('')
}핵심은 인덱스를 서로 맞바꾸는 것이므로, 현재 인덱스 자리에 놓일 문자의 인덱스를 계산해야 합니다. 그 문자가 바로 우리가 반환할 값입니다.
계산 방법은 다음과 같습니다. 배열의 전체 길이에서 1을 빼고(배열은 0부터 시작하므로), 현재 인덱스의 위치를 다시 빼면 됩니다. 반환되는 array[swapIndex]는 사실상 현재 인덱스의 자리를 대신하게 되며, 그 결과 뒤집힌 문자들을 담은 배열이 완성됩니다.
마지막으로 join() 메서드로 배열을 하나의 문자열로 합쳐 반환하면 됩니다.
아래 에디터에서 해결책을 직접 테스트해 보세요!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="" />
<script>
function reverseString(str) {
let newArr = str.split('');
let rev = newArr.map((letter, index, array) => {
let newIndex = array.length - index - 1;
return array[newIndex];
});
return rev.join('')
}
function showInput(e) {
e.preventDefault();
const inputStr = document.getElementById('user_input').value;
if(inputStr.length < 1) {
alert("Must enter a string to reverse. Try again.")
}
let reversed = reverseString(inputStr);
document.getElementById(
'display'
).innerHTML = reversed;
document.getElementById('user_input').value = '';
}
</script>
<style>
* {
box-sizing: border-box;;
}
body {
width: 100%;
max-width: 500px;
height: 100vh;
background: lightblue;
margin: 0 auto;
display: flex;
flex-flow: column wrap;
align-items: center;
justify-content: center;
}
div {
display: flex;
flex-flow: column wrap;
align-items: flex-start;
width: 100%;
}
form {
display: flex;
flex-flow: column wrap;
width: 100%;
background: lightgray;
padding: 20px;
border: 5px double slategray;
}
#user_input {
width: 100%;
}
#submit_button {
width: 25%;
align-self: flex-end;
margin-top: 10px;
}
#display {
font-size: 1.4rem;
height: 50px;
}
</style>
</head>
<body>
<div>
<form onsubmit="showInput(event);">
<label id="label">Enter a String to Reverse:</label>
<input type="text" name="message" id="user_input"/>
<input type="submit" onclick="showInput(event);" id="submit_button"/><br />
<label>Your input: </label>
<p><span id="display"></span></p>
</form>
</div>
</body>
</html>기억해야 할 핵심은 map이 새로운 배열을 반환한다는 점입니다. 즉, 함수에 전달된 원본 문자열이나 배열은 수정되지 않습니다.
해결 방법 3: JavaScript 내장 메서드 조합
세 번째 방법은 내장 메서드인 split(), reverse(), join()을 메서드 체이닝으로 연결해 한 줄로 문제를 해결하는 것입니다.
function reverseString(str) {
return str.split('').reverse().join('');
}아래 코드를 실행해 직접 확인해 보세요!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="" />
<script>
function reverseString(str) {
return str.split('').reverse().join('');
}
function showInput(e) {
e.preventDefault();
const inputStr = document.getElementById('user_input').value;
if(inputStr.length < 1) {
alert("Must enter a string to reverse. Try again.")
}
let reversed = reverseString(inputStr);
document.getElementById(
'display'
).innerHTML = reversed;
document.getElementById('user_input').value = '';
}
</script>
<style>
* {
box-sizing: border-box;;
}
body {
width: 100%;
max-width: 500px;
height: 100vh;
background: lightblue;
margin: 0 auto;
display: flex;
flex-flow: column wrap;
align-items: center;
justify-content: center;
}
div {
display: flex;
flex-flow: column wrap;
align-items: flex-start;
width: 100%;
}
form {
display: flex;
flex-flow: column wrap;
width: 100%;
background: lightgray;
padding: 20px;
border: 5px double slategray;
}
#user_input {
width: 100%;
}
#submit_button {
width: 25%;
align-self: flex-end;
margin-top: 10px;
}
#display {
font-size: 1.4rem;
height: 50px;
}
</style>
</head>
<body>
<div>
<form onsubmit="showInput(event);">
<label id="label">Enter a String to Reverse:</label>
<input type="text" name="message" id="user_input"/>
<input type="submit" onclick="showInput(event);" id="submit_button"/><br />
<label>Your input: </label>
<p><span id="display"></span></p>
</form>
</div>
</body>
</html>내장 reverse() 메서드가 하는 일은 본질적으로 앞선 해결책에서 소개한 map() 방식과 같습니다. 다만, reverse()는 새 배열을 반환하는 대신 원본 배열 자체를 제자리에서(in place) 뒤집는다는 중요한 차이가 있습니다. 따라서 더 큰 문제를 풀 때는 필요할 경우 원본 배열에 다시 접근할 수 있도록 미리 복사본을 만들어 두는 것이 좋습니다.
물론 이것이 이 문제의 유일한 정답은 아닙니다. 여기서 소개한 것들은 가장 널리 쓰이는 몇 가지 방법일 뿐입니다. 위 코드 에디터에서 다른 해결책을 직접 실험해 보세요. 화면에 결과를 표시하고 싶다면 reverseString() 함수만 수정하면 됩니다.