Recent Posts
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
관리 메뉴

개발자 박가나

[241029 TIL] 본캠프 20일차 ('Medal Tracker 만들기' 프로젝트 1일차) 본문

내일배움캠프

[241029 TIL] 본캠프 20일차 ('Medal Tracker 만들기' 프로젝트 1일차)

gnchoco97 2024. 10. 29. 19:59

  📌 오늘의 TIL
  • 알고리즘 문제 풀이 실패 원인 파악 (해결 완료)
  • [Medal Tracker 만들기] 프로젝트

 

 

 알고리즘 'n^2 배열 자르기' 문제 풀이 

/* 런타임 에러 코드 */
function solution(n, left, right) {
    let answer = [];

    for (let i = 1; i <= n; i++) {
        for (let j = 1; j <= n; j++) {
            answer.push(i > j ? i : j);
        }
    }

    return answer.slice(left, right + 1);
}


단순하게 n * n 크기의 배열을 만든 뒤 원하는 부분을 자르는 로직으로 코드를 작성했는데 런타임 에러가 발생을 했다. 구글링을 해보니 배열의 크기가 너무 커서 메모리적으로 과부화가 발생하는 것이 런타임 에러가 발생하는 대표적인 원인 중 하나였고, 다음과 같이 로직을 변경하였다.

  • n * n 크기의 배열을 만든 후에 필요한 부분만 자르는 것이 아니라, 필요한 부분만을 배열로 만든다.
/* 시간 초과 코드 */
function solution(n, left, right) {
    let answer = [];

    for (let row = 1; row <= n; row++) {
        for (let col = 1; col <= n; col++) {
            const index = (row - 1) * n + col - 1;

            if (index >= left && index <= right) {
                answer.push(row > col ? row : col);
                continue;
            }

            if (index > right) break;
        }
    }

    return answer;
}

 

그 결과, 런타임 에러는 해결되었는데 이번엔 시간 초과가 발생을 했다. 다시 한 번 원인을 파악해보니 1행 1열부터 순회를 하면서 원하는 구간인지를 판별하는 로직이기 때문에 n의 값이 엄청나게 커지고 원하는 구간 또한 뒤쪽에 있으면 시간 초과가 발생할 수 밖에 없었고, 최종적으로 다음과 같이 해결하였다.

  • 1행 1열부터 하나하나 순회를 하는 것이 아니라, 원하는 구간의 시작 좌표를 구한다.
/* 정답 코드 */
function solution(n, left, right) {
    let answer = [];

    let row = parseInt(left / n) + 1;
    let col = (left % n) + 1;
    let index = left;

    while (index <= right) {
        answer.push(row > col ? row : col);

        row = col < n ? row : row + 1;
        col = col < n ? col + 1 : 1;
        index++;
    }

    return answer;
}

 

 

 [Madal Tracker] 프로젝트 

프로젝트 셋업

vite를 사용해서 프로젝트를 셋업해준다.

yarn create vite [폴더명] --template react

 

디자인 및 퍼블리싱

styled-components 라이브러리를 이용해서 스타일을 적용시켜 주었다.

/* styled-components 코드 */
import styled from 'styled-components';

const Container = styled.div`
    max-width: 1000px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 20px;
    border-radius: 8px;
    background-color: #ffffff;
    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
    padding: 20px;
    margin: 40px auto;
`;

const Title = styled.p`
    color: #003580;
    font-size: 32px;
    font-weight: 700;
`;

const Form = styled.form`
    display: flex;
    align-items: end;
    gap: 10px;
`;

const InputContainer = styled.div`
    text-align: center;
`;

const InputTitle = styled.p`
    color: #000000;
    font-size: 16px;
    font-weight: 700;
    margin-bottom: 10px;
`;

const Input = styled.input`
    width: 170px;
    height: 40px;
    border: 1px solid #dddddd;
    border-radius: 4px;
    color: #000000;
    font-size: 14px;
    padding: 10px;

    &:focus {
        outline: none;
    }
`;

const CreateUpdate = styled.input`
    width: 100px;
    height: 40px;
    border: none;
    border-radius: 4px;
    background-color: #ffcc00;
    color: #000000;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
`;

const Message = styled.p`
    color: #000000;
    font-size: 16px;
    text-align: center;
`;

const ListContainer = styled.div`
    width: 100%;
    border-radius: 8px;
    overflow: hidden;
`;

const ListTitleContainer = styled.div`
    display: flex;
    background-color: #003580;
    padding: 15px;
`;

const ListTitle = styled.div`
    width: 20%;
    color: #ffffff;
    font-size: 16px;
    font-weight: 700;
    text-align: center;
`;

const ListValueContainer = styled.div`
    display: flex;
    align-items: center;
    background-color: #f4f4f9;
    padding: 15px;

    &:nth-child(2n) {
        background-color: #e6e6fa;
    }

    &:hover {
        background-color: #dcdcdc;
    }
`;

const ListValue = styled.div`
    width: 20%;
    color: #000000;
    font-size: 14px;
    text-align: center;
`;

const Delete = styled.button`
    border: none;
    border-radius: 4px;
    background-color: #ff0000;
    color: #ffffff;
    font-size: 14px;
    font-weight: 700;
    padding: 5px 10px;
    cursor: pointer;
`;
<!-- JSX 코드 -->
function App() {
    const listItems = [
        { country: '대한민국', gold: 15, silver: 10, bronze: 7 },
        { country: '일본', gold: 7, silver: 12, bronze: 5 },
        { country: '중국', gold: 30, silver: 24, bronze: 14 }
    ];

    return (
        <Container>
            <Title>2024 파리 올림픽</Title>

            <Form>
                <InputContainer>
                    <InputTitle>국가명</InputTitle>
                    <Input type="text" placeholder="국가 입력" />
                </InputContainer>
                <InputContainer>
                    <InputTitle>금메달</InputTitle>
                    <Input type="number" />
                </InputContainer>
                <InputContainer>
                    <InputTitle>은메달</InputTitle>
                    <Input type="number" />
                </InputContainer>
                <InputContainer>
                    <InputTitle>동메달</InputTitle>
                    <Input type="number" />
                </InputContainer>
                <CreateUpdate type="submit" value="국가 추가" />
                <CreateUpdate type="submit" value="업데이트" />
            </Form>

            <Message>아직 추가된 국가가 없습니다. 메달을 추적하세요!</Message>

            <ListContainer>
                <ListTitleContainer>
                    <ListTitle>국가명</ListTitle>
                    <ListTitle>금메달</ListTitle>
                    <ListTitle>은메달</ListTitle>
                    <ListTitle>동메달</ListTitle>
                    <ListTitle>액션</ListTitle>
                </ListTitleContainer>
                {listItems.map((item, index) => {
                    return (
                        <ListValueContainer key={index}>
                            <ListValue>{item.country}</ListValue>
                            <ListValue>{item.gold}</ListValue>
                            <ListValue>{item.silver}</ListValue>
                            <ListValue>{item.bronze}</ListValue>
                            <ListValue>
                                <Delete type="button">삭제</Delete>
                            </ListValue>
                        </ListValueContainer>
                    );
                })}
            </ListContainer>
        </Container>
    );
}

export default App;

 

초기 상태 설정

useState()와 onSubmit() 등을 이용해서 초기 상태를 설정해준다.

/* JSX 코드 */
function App() {
    const [country, setCountry] = useState('');
    const [gold, setGold] = useState(0);
    const [silver, setSilver] = useState(0);
    const [bronze, setBronze] = useState(0);

    /* 국가명 값 변경 */
    const changeCountry = (e) => setCountry(e.target.value);

    /* 금메달 값 변경 */
    const changeGold = (e) => setGold(parseInt(e.target.value) < 0 ? 0 : parseInt(e.target.value));

    /* 은메달 값 변경 */
    const changeSilver = (e) => setSilver(parseInt(e.target.value) < 0 ? 0 : parseInt(e.target.value));

    /* 동메달 값 변경 */
    const changeBronze = (e) => setBronze(parseInt(e.target.value) < 0 ? 0 : parseInt(e.target.value));

    /* 추가 및 업데이트 이벤트 */
    const handleSubmit = (e) => {
        e.preventDefault();

        window.alert('버튼 클릭');

        setCountry('');
        setGold(0);
        setSilver(0);
        setBronze(0);
    };

    /* 삭제 이벤트 */
    const handleDelete = () => {
        window.alert('버튼 클릭');
    };

    return (
        <Container>
			...
            <Form onSubmit={(e) => handleSubmit(e)}>
                <InputContainer>
                    <InputTitle>국가명</InputTitle>
                    <Input type="text" placeholder="국가 입력" value={country} onChange={changeCountry} />
                </InputContainer>
                <InputContainer>
                    <InputTitle>금메달</InputTitle>
                    <Input type="number" value={gold} onChange={changeGold} />
                </InputContainer>
                <InputContainer>
                    <InputTitle>은메달</InputTitle>
                    <Input type="number" value={silver} onChange={changeSilver} />
                </InputContainer>
                <InputContainer>
                    <InputTitle>동메달</InputTitle>
                    <Input type="number" value={bronze} onChange={changeBronze} />
                </InputContainer>
                <CreateUpdate type="submit" value="국가 추가" />
                <CreateUpdate type="submit" value="업데이트" />
            </Form>
			...
        </Container>
    );
}

export default App;