디자인을 입히지 않고 오로지 기능만을 구현하는데에 21분이 걸렸다. 지난 번 연습 때 29분이 걸린 걸 생각하면 확실히 시간이 줄었다. 내일 실제 타임어택 때 어디까지 구현해야할지, 어떤 변수가 있을지는 모르겠지만 이 정도면 무난하게 할 수 있을 것 같다.
다음은 구현한 컴포넌트들이다.
// App.jsx
const App = () => {
return (
<>
<TodoContainer />
</>
);
};
// TodoContainer.jsx
const TodoContainer = () => {
const [todos, setTodos] = useState([
{
id: crypto.randomUUID(),
title: "todo 1",
content: "content 1",
isDone: false,
},
{
id: crypto.randomUUID(),
title: "todo 2",
content: "content 2",
isDone: true,
},
]);
const workingTodos = todos.filter((todo) => !todo.isDone);
const doneTodos = todos.filter((todo) => todo.isDone);
const deleteTodoHandler = (id) => {
setTodos(
todos.filter((todo) => {
return todo.id !== id;
})
);
};
const toggleTodoHandler = (id) => {
setTodos(
todos.map((todo) => {
return todo.id !== id ? todo : { ...todo, isDone: !todo.isDone };
})
);
};
return (
<div>
<TodoForm setTodos={setTodos} />
<TodoList
isDone={false}
todos={workingTodos}
deleteTodoHandler={deleteTodoHandler}
toggleTodoHandler={toggleTodoHandler}
/>
<TodoList
isDone={true}
todos={doneTodos}
deleteTodoHandler={deleteTodoHandler}
toggleTodoHandler={toggleTodoHandler}
/>
</div>
);
};
// TodoForm.jsx
const TodoForm = ({ setTodos }) => {
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const addTodoHandler = (e) => {
if (!title.trim() || !content.trim()) {
alert("제목과 내용을 모두 입력해주세요.");
return;
}
e.preventDefault();
const newTodo = {
id: crypto.randomUUID(),
title,
content,
isDone: false,
};
setTodos((prevTodos) => [...prevTodos, newTodo]);
setTitle("");
setContent("");
};
return (
<form onSubmit={addTodoHandler}>
<input
placeholder="제목을 입력하세요."
value={title}
onChange={(e) => {
setTitle(e.target.value);
}}
/>
<input
value={content}
placeholder="내용을 입력하세요."
onChange={(e) => {
setContent(e.target.value);
}}
/>
<button>추가하기</button>
</form>
);
};
// TodoList.jsx
const TodoList = ({ todos, isDone, deleteTodoHandler, toggleTodoHandler }) => {
return (
<>
<p>{isDone ? "Done" : "Working"}</p>
<ul>
{todos.map((todo) => {
return (
<TodoItem
isDone={isDone}
key={todo.id}
todo={todo}
deleteTodoHandler={deleteTodoHandler}
toggleTodoHandler={toggleTodoHandler}
/>
);
})}
</ul>
</>
);
};
// TodoItem.jsx
const TodoItem = ({ todo, deleteTodoHandler, toggleTodoHandler, isDone }) => {
const { id, title, content } = todo;
return (
<li>
<p>{title}</p>
<p>{content}</p>
<button
onClick={() => {
deleteTodoHandler(id);
}}
>
삭제하기
</button>
<button
onClick={() => {
toggleTodoHandler(id);
}}
>
{isDone ? "취소" : "완료"}
</button>
</li>
);
};
휴대폰의 자판은 컴퓨터 키보드 자판과는 다르게 하나의 키에 여러 개의 문자가 할당될 수 있습니다. 키 하나에 여러 문자가 할당된 경우, 동일한 키를 연속해서 빠르게 누르면 할당된 순서대로 문자가 바뀝니다.
예를 들어, 1번 키에 "A", "B", "C" 순서대로 문자가 할당되어 있다면 1번 키를 한 번 누르면 "A", 두 번 누르면 "B", 세 번 누르면 "C"가 되는 식입니다.
같은 규칙을 적용해 아무렇게나 만든 휴대폰 자판이 있습니다. 이 휴대폰 자판은 키의 개수가 1개부터 최대 100개까지 있을 수 있으며, 특정 키를 눌렀을 때 입력되는 문자들도 무작위로 배열되어 있습니다. 또, 같은 문자가 자판 전체에 여러 번 할당된 경우도 있고, 키 하나에 같은 문자가 여러 번 할당된 경우도 있습니다. 심지어 아예 할당되지 않은 경우도 있습니다. 따라서 몇몇 문자열은 작성할 수 없을 수도 있습니다.
이 휴대폰 자판을 이용해 특정 문자열을 작성할 때, 키를 최소 몇 번 눌러야 그 문자열을 작성할 수 있는지 알아보고자 합니다.
1번 키부터 차례대로 할당된 문자들이 순서대로 담긴 문자열배열 keymap과 입력하려는 문자열들이 담긴 문자열 배열 targets가 주어질 때, 각 문자열을 작성하기 위해 키를 최소 몇 번씩 눌러야 하는지 순서대로 배열에 담아 return 하는 solution 함수를 완성해 주세요.
단, 목표 문자열을 작성할 수 없을 때는 -1을 저장합니다.
function solution(keymap, targets) {
let result = targets.map((target) => {
let targetArr = [...target];
let countSum = 0;
for (let i = 0; i < targetArr.length; i++) {
let count = 0;
for (let j = 0; j < keymap.length; j++) {
if (keymap[j].includes(target[i])) {
if (count === 0 || count > keymap[j].indexOf(target[i]) + 1) {
count = keymap[j].indexOf(target[i]) + 1;
}
}
}
if (count === 0) {
return -1;
} else {
countSum += count;
}
}
return countSum;
});
return result;
}
예상 외로 크게 어렵지 않게 풀 수 있었다. map을 사용해 각 target의 요소마다 반복문을 사용해 keymap 중 더 빠르게 타자를 칠 수 있는 count를 더해주고 해당 숫자를 return 해줌으로써 숫자가 담긴 배열을 제작하고 return하는 방식으로 문제를 풀 수 있었다. 무지성으로 이렇게 하면 되겠지 라고 생각하며 풀어서 테스트 케이스에서 틀리거나 시간 초과의 문제가 생기지는 않을까 걱정했는데 다행히 그런 문제가 없었어서 뿌듯했다.
function solution(keymap, targets) {
const answer = [];
const map = {}
for (const items of keymap) {
items.split('').map((item, index) => map[item] = (map[item] < index+1 ? map[item] : index+1))
}
for (const items of targets) {
answer.push(items.split('').reduce((cur, item) => cur += map[item], 0) || -1)
}
return answer;
}