<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sky-pey.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 15 Feb 2024 05:06:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sky-pey.log</title>
            <url>https://velog.velcdn.com/images/sky-pey/profile/416dd4d3-9b48-4ae5-b75d-dc10a918a032/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sky-pey.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sky-pey" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[🌊🚢 파이널프로젝트: 여행일정 앱 TRIPVOTE 후기]]></title>
            <link>https://velog.io/@sky-pey/%ED%8C%8C%EC%9D%B4%EB%84%90%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%97%AC%ED%96%89%EC%9D%BC%EC%A0%95-%EC%95%B1-TRIPVOTE-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@sky-pey/%ED%8C%8C%EC%9D%B4%EB%84%90%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%97%AC%ED%96%89%EC%9D%BC%EC%A0%95-%EC%95%B1-TRIPVOTE-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Thu, 15 Feb 2024 05:06:19 GMT</pubDate>
            <description><![CDATA[<p>2023-12-04 ~ 2024-01-29
파이널프로젝트 : <strong>여행일정 앱 TRIPVOTE</strong></p>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/af1f06b9-978c-43b4-8151-4f8696aeeb9f/image.png" alt=""><img src="https://velog.velcdn.com/images/sky-pey/post/15752582-ee6d-4749-83bf-032b3748d232/image.png" alt=""></p>
<h3 id="프로젝트-기간">프로젝트 기간</h3>
<ul>
<li>전체 기간 : 2023-12-04 ~ 2024-01-29</li>
<li>기획 / UI : 2023-12-04 ~ 2024-01-05</li>
<li>기능 구현 : 2024-01-05 ~ 2024-01-29</li>
<li>리팩토링 : 2024-02-14 ~ 2024-02-29</li>
</ul>
<ul>
<li><strong>Github</strong> : <a href="https://github.com/Strong-Potato/TripVote-FE">https://github.com/Strong-Potato/TripVote-FE</a></li>
<li><strong>배포 링크</strong> : <a href="https://tripvote.site/">https://tripvote.site/</a><pre><code>Test ID : test@test.com
Test PW : 1q2w3e4r!Q</code></pre></li>
</ul>
<hr>
<h3 id="담당-파트----여행지-투표">담당 파트 -  여행지 투표</h3>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/583b2934-6873-4098-b7ec-8b2ab497620c/image.png" alt=""></p>
<blockquote>
</blockquote>
<p>** 기능 요약 **
(1) 투표하기 - 투표 CRUD, 투표하기, 투표 순위 정렬
(2) 여행지 후보 - 여행지 후보 추가&amp;삭제, 메모 남기기, 메모 임시 저장
(3) 여행지 후보 지도 - 카카오맵으로 후보 보기</p>
<blockquote>
</blockquote>
<p>추가 페이지<img src="https://velog.velcdn.com/images/sky-pey/post/76e304a2-48e2-4fae-9ea3-db50b09113b0/image.png" alt=""></p>
<h3 id="1-🤔-고민한-기능">1. 🤔 고민한 기능</h3>
<p><strong>(1)‘메모 작성 페이지’의 실시간 저장 기능</strong></p>
<ul>
<li><p>커스텀 훅 <strong>useGetSelectedArray</strong>을 이용하여 유저가 선택한 여행지 목록과 여행지에 작성한 메모를 실시간으로 <strong>로컬스토리지</strong>에 저장. 이는, 메모 작성 도중 <strong>유저가 페이지를 이탈했다 돌아와도 처음부터 작성할 필요가 없도록</strong> 하기 위함이다.</p>
<ul>
<li><p><strong>useGetSelectedArray</strong></p>
<pre><code class="language-tsx">  import {RecoilState, useSetRecoilState} from &#39;recoil&#39;;
  import {SearchItemType} from &#39;@/types/home&#39;;
  import {TaglineType} from &#39;@/types/vote&#39;;

  // 다른 컴포넌트에서도 사용할 수 있도록 두 가지 타입 제시
  const useGetSelectedArray = &lt;T extends SearchItemType | TaglineType&gt;(selectedState: RecoilState&lt;T[]&gt;) =&gt; {
    const setSelectedState = useSetRecoilState(selectedState);

  // 체크박스 토글로 배열에 아이템 아이디 담기
    const toggleItemInNewArray = (data: T) =&gt; {
      setSelectedState((currentArray) =&gt; {
        const index = currentArray.findIndex((item) =&gt; item.id === data.id);

        if (index !== -1) {
          const newArray = [...currentArray.slice(0, index), ...currentArray.slice(index + 1)];
          return newArray;
        } else {
          const newArray = [...currentArray, data];
          return newArray;
        }
      });
    };

  // 메모 작성 시 기존 배열에 담기
    const setMemoArray = (data: T) =&gt; {
      setSelectedState((currentArray: T[]) =&gt; {
        const index = currentArray.findIndex((item) =&gt; item.id === data.id);
        if (index !== -1) {
          const newArray = [...currentArray];
          newArray[index] = data;
          return newArray;
        }
        return currentArray;
      });
    };

    return {toggleItemInNewArray, setMemoArray};
  };
</code></pre>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>또한, 글 작성 시 <strong>useDebounce</strong>를 이용하여 <strong>불필요하게 지속 저장되는 것을 방지</strong></p>
<ul>
<li><p><strong>useDebounce</strong></p>
<pre><code class="language-tsx">  const useDebounce = (value: string, delay: number) =&gt; {
    const [debouncedValue, setDebouncedValue] = useState(value);

    useEffect(() =&gt; {
      const timer = setTimeout(() =&gt; {
        setDebouncedValue(value);
      }, delay);

      return () =&gt; {
        clearTimeout(timer);
      };
    }, [value, delay]);

    return debouncedValue;
  };</code></pre>
</li>
</ul>
</li>
</ul>
<p><strong>(2) 재 사용 가능한 공용 컴포넌트</strong></p>
<ul>
<li>전체적으로 동일하게 사용되는 모달을 공용으로 만들어 pr을 통해 공유<ul>
<li>모달<img src="https://velog.velcdn.com/images/sky-pey/post/140115d1-8049-410f-a7e2-092950771fe1/image.png" alt=""> <img src="https://velog.velcdn.com/images/sky-pey/post/aac7e415-573d-4dbe-a9c3-9e2242385d27/image.png" alt=""></li>
</ul>
</li>
<li>공용 컴포넌트 이외에도 checkbox, avatar, button 등 chakra UI를 이용한 공용 스타일 테마도 적용 <img src="https://velog.velcdn.com/images/sky-pey/post/d2f4f7f3-8802-45b6-a5e6-8174423a26f1/image.png" alt=""></li>
</ul>
<h3 id="2-✍--리팩토링-할-내용-정리하기">2. <strong>✍</strong>  리팩토링 할 내용 정리하기</h3>
<p><strong>(1) <span style="background-color:#fff5b1">실시간 저장 기능 수정</span></strong>
 실시간 저장 기능을 만들 때는 ‘실시간 저장’에 초점을 두어 구현했으나, 기능 완성 후에는 언마운트를 기준으로 저장해도 무관할 것 같다는 생각이 들었다. 이 부분은 추후 <strong>실시간 저장에서 언마운트 시 저장하도록 수정</strong>할 예정.
그리고 저장을 로컬스토리지 말고 다른 방법으로 할 수 있는지 더 고민해봐야겠다.</p>
<p><strong>(2) <span style="background-color:#fff5b1">투표하기에서 투표의 상태 관리</span></strong>
 투표의 상태는 여러가지로 나뉜다.
** &#39;진행 중&#39;, &#39;결정완료&#39;** 로 투표 결정 완료 여부를 따지고,
또 <strong>&#39;투표 전&#39;, &#39;투표완료&#39;, &#39;투표 결과 보기&#39;</strong> 로 투표를 3가지 상태로 나눌 수 있다.
&#39;투표 결과 보기&#39; 상태는 결정 여부와 관계 없이 가질 수 있고, 각 투표마다 가지고 있다.
문제는 이 결과보기 상태 값을 백에서 각 투표마다 가지고 있는게 아니라 전체 투표 리스트에서 배열로 주고 있기 때문에 프론트에서의 처리 과정이 조금 번잡하게 되어있다.
현재는 배열에 담긴 id와 투표id를 비교해서 boolean값을 recoil에 지정해 주었더니 이 부분에서 버그가 나고 있다.
특히 지도에서도 결과보기 값이 필요해서 url에 쿼리스트링을 넣는 방식으로 할까 싶은데 이게 맞는지는 아직 확신이 들지 않는다.</p>
<p><strong>(3) <span style="background-color:#fff5b1">여행지 후보 지도</span></strong>
아마 2번이 해결되면 3번도 자연스럽게 해결 될 것 같지만 현재의 가장 큰 문제다.
카카오맵과 swiper를 연결해서, 하단의 슬라이드가 움직이면 센터 좌표도 바뀌도록 로직을 짰는데 결과보기 상태를 추가하고 나니 슬라이드 정렬에 문제가 생겼다.<img src="https://velog.velcdn.com/images/sky-pey/post/210e7334-2c67-489e-be83-67fe90be4748/image.png" alt=""> 이미지에서는 보이지 않지만 슬라이드를 넘길때마다 슬라이드가 복제되어 중복으로 보이고 있다.
좀 이상한건 모바일에서는 정상적으로 보이고 있다는 것.
우선, 결과보기 상태부터 해결하고 이 부분도 새로 코드를 작성해 봐야 할 것 같다.</p>
<p><strong>(4) <span style="background-color:#fff5b1">react 성능 최적화</span></strong>
항상 바로바로 해야하는 걸 알지만 어쩌다보니 항상 후순위로 밀려나 있다.
이번에는 위의 1-3 문제를 해결한 다음에 성능 최적화까지 해 볼 생각이다.</p>
<p><strong>(5) <span style="background-color:#fff5b1">타입 정리</span></strong>
시간이 촉박해질 수록 타입을 지저분하게 작성한 부분이 있다. 아마 이부분 때문에 버그가 발생한 것도 있는 것 같아 같이 수정해야 한다.</p>
<hr>
<h3 id="리팩토링-이전-간단한-후기">리팩토링 이전 간단한 후기</h3>
<p>PM부터 디자이너, BE까지 총 16명이서 진행한 2달의 프로젝트였다.
부트캠프에서 안내한 대략적인 기간은 12월에 기획과 디자인, 12월 26일부터 개발이었지만 개발 기간은 한 주 가량 밀리고 마감 직전 주까지도 기획과 자잘한 디자인이 바뀌었으며, API 스키마도 마감 직전 주에 확정되어서 마감 전날까지 계속해서 버그 수정을 했었다.</p>
<p>사실 같은 기능을 담당한 BE분의 작업이 점점 늦어 졌었는데, 알고보니 해당 팀원이 취업에 성공해서 작업 시간이 부족했던 거였다. 이 내용을 모두가 마감 3,4일 전에 알게 되었고, 그로 인해 다른 BE 분들이 남은 작업을 나눠 진행하게 되어 시간이 더 촉박했다. </p>
<p>개발 기간이 점차 밀리고 프론트엔드가 중간에서 정신 없을 거란 건 어느정도 예상하긴 했지만 막상 그 상황에 놓이게 되니 조급해지는 건 어쩔 수가 없었던 것 같다.
넉넉할거라 생각했던 기간은 다 같이 밤을 새며 작업을 해도 턱없이 많이 부족했고, 버그들이 남겨진 채로 마무리 된 게 아쉬웠다.
모두가 쉬는 사람 없이 다 같이 잠도 안자고 노력했던 터라 더 아쉬웠던 것 같다.
 현업에서도 기획, 디자인 등 계속해서 변경된다는 이야기는 많이 들었는데 다들 어떻게 잘 해나가시는 건지 정말 궁금해졌다.</p>
<p>그리고 이전에도 느꼈지만 이번 프로젝트를 통해 다양한 팀과 협업하면서 더 확실히 느낀게 있다. 코드를 작성 하다 막혔을 때 최대한 짧은 시간 안에 처리하는 게 개발에 있어서 가장 중요하다는 것.
리팩토링을 하면서 다음에는 시간 분배를 어떻게 할지 같이 고민해 봐야겠다.</p>
<p><strong>+</strong>
난 recoil이랑 react-query(tanstack-query)가 너무 좋은 것 같다. 사용 방법도 간단하고 작성된 코드도 깔끔했다.
다만 프로젝트 3개를 두 조합으로 했더니 react만 쓰는 걸 잊은 것 같아 걱정이다.
리팩토링이 끝나면 react만 썼을 때는 어떻게 작성이 되는지 거꾸로 바꿔볼 예정이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[패스트캠퍼스X야놀자 프론트엔드 개발 부트캠프 미니프로젝트: 숙박 예약 API 서비스 리팩토링 후기]]></title>
            <link>https://velog.io/@sky-pey/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4X%EC%95%BC%EB%86%80%EC%9E%90-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%88%99%EB%B0%95-%EC%98%88%EC%95%BD-API-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@sky-pey/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4X%EC%95%BC%EB%86%80%EC%9E%90-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%88%99%EB%B0%95-%EC%98%88%EC%95%BD-API-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Thu, 21 Dec 2023 13:17:35 GMT</pubDate>
            <description><![CDATA[<p>20~21주차
미니프로젝트: 숙박 예약 API 서비스
<br></p>
<h2 id="✍-소개">✍ 소개</h2>
<hr>
<p> <strong>React</strong>를 기반으로 개발된 숙박 예약 서비스입니다.
FE 5명, BE 3명이 참여했으며 약 2주간 개발했습니다.</p>
<p>공개용 Github : <a href="https://github.com/Yanolja-MiniProject-10/Yanolja-clone-fe">https://github.com/Yanolja-MiniProject-10/Yanolja-clone-fe</a>
배포 링크 : <a href="https://yanolja.vercel.app/">https://yanolja.vercel.app/</a></p>
<pre><code>Test ID : test@yanolja.com
Test PW : 00000</code></pre><p><img src="https://velog.velcdn.com/images/sky-pey/post/3da70f2e-9701-40c0-b150-33b8cbad0a05/image.png" alt=""></p>
<h3 id="전체-시연-영상">전체 시연 영상</h3>
<hr>
<p>!youtube[xnGrdf6tPFQ]</p>
<br>

<h2 id="skills">Skills</h2>
<hr>
<p> React, JavaScript, TypeScript, Recoil, Axios, React-Query, Vite, Github, Vercel, Styled Components</p>
<br>

<h2 id="🧑🏻💻-담당-개발-내용">🧑🏻‍💻 담당 개발 내용</h2>
<hr>
<h3 id="담당---첫-메인-페이지">담당 - <strong>첫 메인 페이지</strong></h3>
<ul>
<li>상세 내용<ul>
<li>이벤트 캐러셀</li>
<li>카테고리</li>
<li>모든 숙소 둘러보기</li>
<li>최근 본 상품의 연관 상품</li>
<li>지역 별 상품 추천</li>
<li>예약 숙소 랭킹</li>
<li>푸터, 메인 내비바, 메인 헤더, 공통 헤더</li>
</ul>
</li>
</ul>
<p><strong>주요 내용 요약</strong></p>
<ol>
<li>컴포넌트 재 사용</li>
<li>recoil을 이용하여 연관된 상품 추천 기능 구현</li>
<li>react-query를 통해 api 호출 함수 컴포넌트 별 조건부 재 사용</li>
<li>디자인 - 스켈레톤 UI 도입으로 UX 측면 고도화</li>
</ol>
<h3 id="1-재사용-컴포넌트">1. <strong>재사용 컴포넌트</strong></h3>
<ul>
<li><p>Common Header - 페이지 별 제목과 필요한 아이콘을 보여줍니다.</p>
<ul>
<li><p>영상
!youtube[BZPleJXjfsA]</p>
</li>
<li><p>예시 이미지
<img src="https://velog.velcdn.com/images/sky-pey/post/7c7d5ee1-4c58-480b-a265-cb92a34d5a87/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>AllAndRelatedSwiper - [모든 숙소 둘러보기], [최근 본 상품의 연관 상품]</p>
<ul>
<li><p>영상</p>
<p>!youtube[rTmzz2n5jIU]</p>
</li>
</ul>
</li>
</ul>
<pre><code> - 예시 이미지</code></pre><p><img src="https://velog.velcdn.com/images/sky-pey/post/75d0ad79-2a18-470c-8346-ac4211a48b44/image.png" alt=""></p>
<h3 id="2-상품-추천-기능-구현---최근-본-상품의-연관-상품">2. <strong>상품 추천 기능 구현</strong> - [최근 본 상품의 연관 상품]</h3>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/f63ea8c4-19ef-46e7-95c8-20eba18525fe/image.gif" alt=""></p>
<ul>
<li>고객이 클릭해서 본 숙소에서 정보를 recoil에 저장하고 불러와 메인에 보여줍니다.</li>
<li>로그인을 하지 않거나, 클릭한 상품이 없을 경우 보여주지 않습니다.</li>
</ul>
<h3 id="3--react-query를-통한-api-호출-함수의-컴포넌트-별-조건부-재-사용">3.  react-query를 통한 api 호출 함수의 컴포넌트 별 조건부 재 사용</h3>
<p><code>enabled</code>을 사용하면 비동기 함수인 useQuery를 동기적으로 사용 가능하다.</p>
<pre><code class="language-jsx">const useFetchCarts = () =&gt;
  useQuery({
    queryKey: [&quot;fetchCarts&quot;],
    queryFn: () =&gt; fetchCarts(),
  });

//api 호출 함수를 더 만들지 않고 useQuery를 추가하여 enable 사용
// 동일한 쿼리키를 사용하여, mutate를 동일하게 적용받도록 함

const useFetchCartCount = (user: UserToken) =&gt;
  useQuery({
    queryKey: [&quot;fetchCarts&quot;],
    queryFn: () =&gt; fetchCarts(),
    enabled: !!user.accessToken,  // accessToken 유무로 user 로그인 상태일 때 실행
  });</code></pre>
<h3 id="4-디자인">4. <strong>디자인</strong></h3>
<ul>
<li>스켈레톤 UI
<img src="https://velog.velcdn.com/images/sky-pey/post/13df8d8b-b3fa-4e33-b4d0-1c2168879081/image.png" alt=""></li>
</ul>
<ul>
<li>반응형
<img src="https://velog.velcdn.com/images/sky-pey/post/9851176c-9c3b-4679-a876-6efc69e3cf8d/image.gif" alt=""></li>
</ul>
<br>


<h2 id="🧑🏻💻-github">🧑🏻‍💻 Github</h2>
<hr>
<ul>
<li><strong>Project</strong>를 이용한 진행 상황 처리
<img src="https://velog.velcdn.com/images/sky-pey/post/f379ba64-1643-492f-9133-bff006f39334/image.png" alt=""></li>
</ul>
<ul>
<li><strong>Actions</strong>를 활용하여 CI/CD 경험</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/de609e21-78af-45fe-bcb9-28adf4ffdbc1/image.png" alt=""></p>
<br>

<h2 id="에러-및-고민한-점">에러 및 고민한 점</h2>
<hr>
<p>위에서 기재했던 <code>react-query를 통한 api 호출 함수의 컴포넌트 별 조건부 재 사용</code> 부분이 오래 고민했던 곳이다.
api 호출을 비동기로 사용했는데, api 호출을 조건에 따라 동기적으로 사용이 필요했기 때문이다.
유저가 로그인 상태일 때만 함수를 실행해야 하는 조건이었는데
custom hook의 경우 useEffect나 조건문에 넣지 못해서, 처음에는 api호출 함수에서 조건을 넣어봤지만 번번히 실패했다.</p>
<p>그러다 react-query의 <code>enabled</code>를 알게 되고 손쉽게 조건부 처리를 할 수 있었다.</p>
<pre><code class="language-ts">const useFetchCartCount = (user: UserToken) =&gt;
  useQuery({
    queryKey: [&quot;fetchCarts&quot;],
    queryFn: () =&gt; fetchCarts(),
    enabled: !!user.accessToken,  // accessToken 유무로 user 로그인 상태일 때 실행
  });</code></pre>
<br>
<br>

<p><span style="font-size:10px; color:gray;">해당 게시글은 부트캠프 과정 중 수료 점수에 반영되어, 제목과 해시태그를 포함한 지정된 양식으로 작성되었습니다.</span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Redux Toolkit] todos-app에서의 Slice 231023]]></title>
            <link>https://velog.io/@sky-pey/React-Redux-todos-app%EC%97%90%EC%84%9C%EC%9D%98-Slice-231023</link>
            <guid>https://velog.io/@sky-pey/React-Redux-todos-app%EC%97%90%EC%84%9C%EC%9D%98-Slice-231023</guid>
            <pubDate>Mon, 23 Oct 2023 10:52:56 GMT</pubDate>
            <description><![CDATA[<p><del>106일차</del></p>
<p>todos 앱을 배우며 모르는 부분이 있어 질의응답으로 이해한 부분을 기재한다.</p>
<pre><code class="language-ts">//타입과 initialState
interface NoteState {
  mainNotes: Note[];
  archiveNotes: Note[];
  trashNotes: Note[];
  editNote: null | Note;
}
const initialState: NoteState = {
  mainNotes: [...notes],
  archiveNotes: [],
  trashNotes: [],
  editNote: null,
};
enum noteType {
  archiveNotes = &quot;archiveNotes&quot;,
  trashNotes = &quot;trashNotes&quot;,
  mainNotes = &quot;mainNotes&quot;,
}


// Slice
const noteListSlice = createSlice({
  name: &quot;noteList&quot;,
  initialState,
  reducers: {
    //중략

     readNote: (state, { payload }) =&gt; {
       //1. payload
      const { type, id } = payload;

      const setRead = (notes: noteType) =&gt; {
        //2. state
        state[notes] = state[notes].map((note: Note) =&gt;
          note.id === id ? { ...note, isRead: !note.isRead } : note
        );
      };
          // noteType은 enum이다
      if (type === &quot;archive&quot;) {
        setRead(noteType.archiveNotes); //&quot;archiveNotes&quot;
      } else if (type === &quot;trash&quot;) {
        setRead(noteType.trashNotes); //&quot;trashNotes&quot;
      } else {
        setRead(noteType.mainNotes); //&quot;mainNotes&quot;
      }
    },
  },
});

// 사용하는 곳
&lt;DeleteBox
   onClick={() =&gt; dispatch(readNote({ type, id: note.id }))}
   className=&quot;readNote__close-btn&quot;
        &gt;</code></pre>
<h3 id="1-payload">1. payload</h3>
<p>type, id를 객체로 받으며 payload에 할당</p>
<h3 id="2-state">2. state</h3>
<p>notes가 버라이어티한 string값이기 때문에
<code>state.mainNotes = state.mainNotes.map</code> 처럼
state.notes로 사용할 수 없다.</p>
<p>예를 들어 설명한다.
notes = “archiveNotes” 이며,
<code>state.notes</code> - <strong>state.“archiveNotes”</strong> 형태는 되지 않는다. 
<code>state[notes]</code> - <strong>state[“archiveNotes”]</strong> 로 작성해야,
결국 <strong>state.archiveNotes</strong>과 같아진다.</p>
<blockquote>
</blockquote>
<p>*<em>간단 정리 *</em></p>
<blockquote>
</blockquote>
<p>setRead(noteType.archiveNotes)
=&gt; setRead(“archiveNotes”)</p>
<blockquote>
</blockquote>
<p>state[notes] = state[“archiveNotes”] = state.archiveNotes</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 백트래킹 알고리즘 문제풀이 4 (BackTracking Algorithm) 231019]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-4-BackTracking-Algorithm-231019</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-4-BackTracking-Algorithm-231019</guid>
            <pubDate>Thu, 19 Oct 2023 08:17:44 GMT</pubDate>
            <description><![CDATA[<h2 id="1-n-queen">1. N-Queen</h2>
<p><a href="https://www.acmicpc.net/problem/9663">https://www.acmicpc.net/problem/9663</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>1부터 N까지 자연수 중에서 중복 없이 M개를 고른 모든 수열을 계산</li>
<li>모든 순열의 수를 고려하기 위해 재귀 함수(백트래킹)를 사용할 수 있다.</li>
<li>하나의 순열을 트리(tree)에서 리프 노드까지의 경로로 생각할 수 있다.
-&gt; 이때, M개의 원소를 뽑는 순열을 고려하는 것이므로, 깊이(depth)는 M과 같다. -원소를 중복하여 선택하지 않으므로, 방문처리(visited) 배열을 사용한다.
-&gt; 한 번 선택된 원소는 다음 재귀 함수에서 다시 선택되지 않는다.</li>
</ul>
<h3 id="제출-답안">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]); // 전체 map의 크기
let queens = []; // 현재 체스판에 놓인 퀸(queen)의 위치 정보들

function possible(x, y) {
  // (x, y) 위치에 퀸을 놓을 수 있는지 확인
  for (let [a, b] of queens) {
    // 현재까지 놓았던 모든 queen의 위치를 하나씩 확인하며
    if (a == x || b == y) return false; // 행이나 열이 같다면 X
    if (Math.abs(a - x) == Math.abs(b - y)) return false; // 대각선 위치한 경우 X
  }
  return true;
}

let cnt = 0;
function dfs(row) {
  if (row == n) cnt += 1; // queen을 N개 배치할 수 있는 경우 카운트
  for (let i = 0; i &lt; n; i++) {
    // 현재 행(row)에 존재하는 열을 하나씩 확인하며
    if (!possible(row, i)) continue; // 현재 위치에 놓을 수 없다면 무시
    queens.push([row, i]); // 현재 위치에 퀸 놓기
    dfs(row + 1); // 재귀함수 호출
    queens.pop(); // 현재 위치에서 퀸 제거
  }
}
dfs(0);
console.log(cnt);</code></pre>
<h3 id="정답-예시">정답 예시</h3>
<p>제출 답안과 동일</p>
<br>

<h2 id="2-알파벳">2. 알파벳</h2>
<p><a href="https://www.acmicpc.net/problem/1987">https://www.acmicpc.net/problem/1987</a></p>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let [r, c] = input[0].split(&quot; &quot;).map(Number);
let arr = []; // 순열을 계산하고자 하는 원소가 담긴 배열
for (let i = 1; i &lt;= r; i++) arr.push(input[i]);

let dx = [-1, 1, 0, 0]; // 상하좌우 방향
let dy = [0, 0, -1, 1];

let visited = new Set(); // 방문한 적 있는 알파벳 집합
let maxDepth = 0; // 최대 깊이

function dfs(depth, x, y) {
  maxDepth = Math.max(maxDepth, depth); //최대 깊이 계산
  for (let i = 0; i &lt; 4; i++) {
    let nx = x + dx[i];
    let ny = y + dy[i];
    if (nx &lt; 0 || nx &gt;= r || ny &lt; 0 || ny &gt;= c) continue; // 맵을 벗어나면 무시
    if (visited.has(arr[nx][ny])) continue;
    visited.add(arr[nx][ny]); // 방문 처리
    dfs(arr, depth + 1); // 재귀 함수 호출
    visited.delete(arr[nx][ny]); // 방문처리 해제
  }
}
visited.add(arr[0][0]); // 왼쪽 위에서 출발
dfc(1, 0, 0);
console.log(maxDepth);</code></pre>
<br>

<h2 id="3-부등호">3. 부등호</h2>
<p><a href="https://www.acmicpc.net/problem/2529">https://www.acmicpc.net/problem/2529</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>총 10개의 숫자 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 중에서 <strong>중복 없이 모든 순열을 선택</strong> 한다.</li>
<li>선택한 뒤에 K 개의 부등호에 대한 순서를 만족하는지 확인한다.</li>
<li>K는 최대 9까지 입력될 수 있다.</li>
</ul>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let k = Number(input[0]);
let arr = input[1].split(&#39; &#39;);
let visited = new Array(10).fill(false);
let result = [];
let current = &quot;&quot;;
let first = &quot;&quot;;

dfs(0);
console.log(current + &quot;\n&quot; + first) // 마지막에 남은 current 값은 [가장 큰 문자열]


function dfs(depth) {
  if (depth == k+1) { //각 순열에 대한 처리
   let check = true; // 부등식을 만족하는지 확인
    for (let i = 0; i &lt; k; i++) {
      if (arr[i] ==&quot;&lt;&quot;) {
        if(result[i] &gt; result[i+1]) check = false; // 부등식을 만족하지 않음
      }
      else if (arr[i] == &#39;&gt;&#39;) {
        if(result[i] &lt; result[i+1]) check = false; // 부등식을 만족하지 않음
      }
    }
    if (check) { // 부등식을 만족하는 경우에
      current = &quot;&quot;;
      for (let x of result) current += x + &quot;&quot;;
      if ( first == &quot;&quot;) first = current; // 첫째 문자열은 [가장 작은 수]
    }
    return;
     }
     for (let i = 0; i &lt; 10; i++;) { // 0부터 9까지의 숫자를 하나씩 고르는 순열(백트래킹)
   if (visited[i]) continue; // 이미 고른 숫자라면 무시하도록
    visited[i] = true; // 현재 선택한 숫자 방문 처리
    result.push(i);
    dfs(depth + 1); // 재귀 함수 호출
    visited[i] = false; //현재 선택한 숫자 방문 처리 취소
    result.pop();
  }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 백트래킹 알고리즘 문제풀이 3 (BackTracking Algorithm) 231019]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-3-BackTracking-Algorithm-231019</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-3-BackTracking-Algorithm-231019</guid>
            <pubDate>Thu, 19 Oct 2023 08:16:53 GMT</pubDate>
            <description><![CDATA[<h2 id="1-외판원-순회-2">1. 외판원 순회 2</h2>
<p><a href="https://www.acmicpc.net/problem/10971">https://www.acmicpc.net/problem/10971</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>외판원 순회(traveling salesman problem. TSP) 문제이다.</li>
<li>어느 한 도시에서 출발해 N개의 도시를 모두 거쳐 다시 원래의 도시로 돌아와야 한다.
-&gt; 어떤 노드에서 출발해도 무관</li>
</ul>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]);
let graph = []; // 전체 그래프(graph) 정보 입력
for (let i = 0; i &lt;= n; i++) graph.push([0]);
for (let i = 1; i &lt;= n; i++) {
  line = input[i].split(&quot; &quot;).map(Number);
  for (let j = 0; j &lt; n; j++) graph[i].push(line[j]);
}
let visited = new Array(11).fill(false); // 방문처리 배열
let result = []; // 순열 정보 배열
let minValue = 1e9;

dfc(arr, 0);
console.log(minValue);

// 2부터 N까지의 수를 하나씩 골라 나열하는 모든 순열을 계산
function dfs(arr, depth) {
  if (depth == n - 1) {
    //현재 순열에 대한 처리
    let totalCost = 0; // 1번 노드에서 출발
    let cur = 1; // 1번 노드에서 출발

    for (let i = 0; i &lt; n - 1; i++) {
      // 현재 순열에 따라서 노드 이동
      let nextNode = result[i]; // 다음 이동 노드까지의 비용 계산
      let cost = graph[cur][nextNode];
      if (cost == 0) return; // 이동 불가능하면 무시
      totalCost += cost; // 이동 가능 -&gt; 비용 더하고 노드 이동
      cur = nextNode;
    }
    // 마지막 노드에서 1로 돌아오는 것이 필수
    let cost = graph[cur][1];
    if (cost == 0) return; // 이동 불가능하면 무시
    totalCost += cost; // 이동 가능 -&gt; 비용 더하고 노드 이동
    minValue = Math.min(minValue, totalCost); // 경로의 최소 비용 저장
  }
  for (let i = 2; i &lt;= n; i++) {
    if (visited[i]) continue;
    result.push(i); // 방문 처리
    visited[i] = true;
    dfs(depth + 1); // 재귀 함수 호출
    result.pop(); // 방문 처리 해제
    visited[i] = false;
  }
}</code></pre>
<br>

<h2 id="2-조합---도영이가-만든-맛있는-음식">2. 조합 - 도영이가 만든 맛있는 음식</h2>
<p><a href="https://www.acmicpc.net/problem/2961">https://www.acmicpc.net/problem/2961</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>모든 길이에 대한 가능한 모든 조합을 구하는 것</li>
</ul>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]);
let arr = [];
for (let i = 1; i &lt;= n; i++) {
  let [x, y] = input[i].split(&quot; &quot;).map(Number);
  arr.push([x, y]);
}
let visited = new Array(n).fill(false); // 각 원소 인덱스별 방문 여부
let result = []; // 현재 순열에 포함된 원소
let answer = 1e9;

function dfs(depth, start) {
  if (depth &gt;= 1) {
    // 현재 조합에 대하여 결과 계산
    let totalX = 1;
    let totalY = 0;
    for (let i of result) {
      // 인덱스를 하나씩 확인하며
      let [x, y] = arr[i];
      totalX *= x;
      totalY += y;
    }
    answer = Math.min(answer, Math.abs(totalX - totalY));
  }
  for (let i = start; i &lt; n; i++) {
    // 모든 조합 계산
    if (visited[i]) continue;
    visited[i] = true; // 방문 처리
    result.push(i);
    dfs(depth + 1, i + 1); // 재귀 함수 호출
    visited[i] = false; //방문 처리 해제
    result.pop();
  }
}
dfs(0, 0);
console.log(answer);</code></pre>
<br>

<h2 id="3-로또">3. 로또</h2>
<p><a href="https://www.acmicpc.net/problem/6603">https://www.acmicpc.net/problem/6603</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>모든 조합을 고려해서 모든 조합을 출력하는 정도로 이해해도 무관</li>
</ul>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

for (let i =0; i &lt; input.length; i++) {
  let data = input[i].split(&quot; &quot;).map(Number);
  if (data[0] == 0) break; // 테스트 케이스 종료 조건
  else {
    n = data[0];
    arr = data.slice(1);
    visited = new Array(n).fill(false); // 각 원소 인덱스별 방문 여부
    selected = []; // 현재 조합에 포함된 원소
    answer = &quot;&quot;;
    dfs(arr, 0,0);
    console.log(answer);
      }
}

function dfs(result, depth) {
  if (depth == 6) { // 모든 조합을 확인하는 부분(로또는 6개의 자연수로 구성)
    let result= []; // 조합 결과 저장 테이블
    for (let i of selected) result.push(arr[i]);
    for (let x of result) answer += x + &quot; &quot;; // 계산된 조합을 실질적으로 처리하는 부분
    answer += &quot;\n&quot;;
    return;
  }
  // start 지점부터 하나씩 원소 인덱스를 확인하며
  for (let i = start; i &lt; arr.length; i++) {

    if (visited[i]) continue; // [중복x] 이미 처리 된 원소라면 무시
    selected.push(i); // 현재 원소 선택
    visited[i] = true; // 방문 처리
    dfs(arr, depth + 1, i + 1); // 조합이므로, 재귀 함수 호출 시 다음 인덱스 넣기
    selected.pop(); // 현재 원소 선택 취소
    visited[i] = false; //방문 처리 취소
  }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 백트래킹 알고리즘 문제풀이 2 (BackTracking Algorithm) 231019]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-2-BackTracking-Algorithm-231019</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-2-BackTracking-Algorithm-231019</guid>
            <pubDate>Thu, 19 Oct 2023 08:16:10 GMT</pubDate>
            <description><![CDATA[<h2 id="1-조합---n과-m-2">1. 조합 - N과 M (2)</h2>
<p><a href="https://www.acmicpc.net/problem/15650">https://www.acmicpc.net/problem/15650</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li><p>5개의 수 [1, 2, 3, 4, 5]에서 3개를 고르는 모든 조합을 고려해보자.</p>
</li>
<li><p>깊이가 3인 경우를 고려한다.</p>
</li>
<li><p>경우의 수 : 10개</p>
</li>
<li><p>모든 조합의 수를 고려하기 위해 재귀 함수(백트래킹)을 사용할 수 있다.</p>
</li>
<li><p>하나의 조합을 트리(tree)에서 리프 노드까지의 경로로 생각할 수 있다.
-&gt; 이때, M개의 원소를 뽑는 순열을 고려하는 것이므로, 깊이(depth)는 M과 같다.</p>
</li>
<li><p>원소를 중복하여 선택하지 않으므로, 방문처리(visited) 배열을 사용한다.
-&gt; 한 번 선택된 원소는 다음 재귀 함수에서 다시 선택되지 않는다.
[조합] 재귀 함수를 호출할 때마다 (자식 노드로 갈수록) 선택되는 값이 커지도록 하는 것이 핵심
-&gt; 순열 코드와 다른 점은 start 변수가 사용된다는 점 뿐이다.</p>
</li>
</ul>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let [n, m] = input[0].split(&quot; &quot;).map(Number);
let arr = []; // 조합을 계산하고자 하는 원소가 담긴 배열
for (let i = 1; i &lt;= n; i++) arr.push(i); //
let visited = new Array(n).fill(false); //각 원소 인덱스별 방문 여부(중복 확인용)
let selected = []; // 현재 조합에 포함된 원소

let answer = &quot;&quot;;
function dfs(arr, depth, start) {
  if (depth == m) {
    //모든 조합을 확인하는 부분
    let result = []; // 조합 결과 저장 테이블
    for (let i of selected) result.push(arr[i]);
    for (let x of result) answer += x + &quot; &quot;; // 계산된 조합을 실질적으로 처리하는 부분
    answer += &quot;\n&quot;;
    return;
  }
  for (let i = start; i &lt; arr.length; i++) {
    // start 지점부터 하나씩 원소 인덱스를 확인하며
    if (visited[i]) continue; //[중복X] 이미 처리된 원소라면 무시
    selected.push(i); // 현재 원소 선택
    visited[i] = true; // 현재 원소 방문 처리
    dfs(arr, depth + 1, i + 1); // 조합이므로, 재귀 함수 호출 시 다음 인덱스 넣기
    selected.pop(); // 현재원소 선택 취소
    visited[i] = false; // 현재 원소 방문 처리 취소
  }
}
dfc(arr, 0, 0);
console.log(answer);</code></pre>
<br>

<h2 id="2-중복-순열---n과-m-3">2. 중복 순열 - N과 M (3)</h2>
<p><a href="https://www.acmicpc.net/problem/15651">https://www.acmicpc.net/problem/15651</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li><p>1부터 N까지 자연수 중에서 M개를 고른 모든 수열을 계산.
[중복 수열] 이때, 같은 수를 여러번 골라도 된다.</p>
</li>
<li><p>모든 조합의 수를 고려하기 위해 재귀 함수(백트래킹)을 사용할 수 있다.</p>
</li>
<li><p>하나의 조합을 트리(tree)에서 리프 노드까지의 경로로 생각할 수 있다.
  -&gt; 이때, M개의 원소를 뽑는 순열을 고려하는 것이므로, 깊이(depth)는 M과 같다.</p>
</li>
<li><p>원소를 중복하여 선택하므로, 방문처리(visited) 배열을 사용하지 않는다.
  -&gt; 한 번 방문한(방문 처리된) 원소도 중복해서 또 방문할 수 있다.</p>
</li>
<li><p>따라서 기본 순열 코드에서 단순히 visited 변수를 제거한다.</p>
</li>
</ul>
<h3 id="제출-답안">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let [n, m] = input[0].split(&quot; &quot;).map(Number);
let arr = []; // 순열을 계산하고자 하는 원소가 담긴 배열
for (let i = 1; i &lt;= n; i++) arr.push(i);
let selected = []; // 현재 순열에 포함된 원소

let answer = &quot;&quot;;
function dfs(arr, depth) {
  if (depth == m) {
    //모든 순열을 확인하는 부분
    let result = []; // 순열 결과 저장 테이블
    for (let i of selected) result.push(arr[i]);
    for (let x of result) answer += x + &quot; &quot;; // 계산된 순열을 실질적으로 처리하는 부분
    answer += &quot;\n&quot;;
    return;
  }
  for (let i = 0; i &lt; arr.length; i++) {
    // 하나씩 원소 인덱스를 확인하며
    if (visited[i]) continue; //[중복X] 이미 처리된 원소라면 무시
    selected.push(i); // 현재 원소 선택
    dfs(arr, depth + 1); // 재귀 함수 호출
    selected.pop(); // 현재원소 선택 취소
  }
}
dfc(arr, 0);
console.log(answer);</code></pre>
<h3 id="정답-예시-1">정답 예시</h3>
<p>제출답안과 동일</p>
<br>

<h2 id="3-중복-조합---n과-m-4">3. 중복 조합 - N과 M (4)</h2>
<p><a href="https://www.acmicpc.net/problem/15652">https://www.acmicpc.net/problem/15652</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li><p>1부터 N까지 자연수 중에서 M개를 고른 모든 조합을 계산한다.</p>
</li>
<li><p>오름차순이라는 점 (순서가 하나만 있다는 점)에서 조합으로 이해할 수 있다.
[중복 조합] 이때, 같은 수를 여러 번 골라도 된다.</p>
</li>
<li><p>모든 조합의 수를 고려하기 위해 재귀 함수(백트래킹)을 사용할 수 있다.</p>
</li>
<li><p>하나의 조합을 트리(tree)에서 리프 노드까지의 경로로 생각할 수 있다.
-&gt; 이때, M개의 원소를 뽑는 순열을 고려하는 것이므로, 깊이(depth)는 M과 같다.</p>
</li>
<li><p>원소를 중복하여 선택하므로, 방문처리(visited) 배열을 사용하지 않는다.
-&gt; 한 번 방문한(방문 처리된) 원소도 중복해서 또 방문할 수 있다.</p>
</li>
<li><p>따라서 기본 순열 코드에서 단순히 visited 변수를 제거한다.
[조합] 재귀 함수를 호출할 때마다(자식 노드로 갈수록) 선택되는 값이 커지도록 하는것이 핵심이다.
-&gt; 순열 코드와 달리 start 변수가 사용된다.</p>
</li>
</ul>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let [n, m] = input[0].split(&quot; &quot;).map(Number);
let arr = []; // 조합을 계산하고자 하는 원소가 담긴 배열
for (let i = 1; i &lt;= n; i++) arr.push(i); //
let selected = []; // 현재 조합에 포함된 원소

let answer = &quot;&quot;;
function dfs(arr, depth, start) {
  if (depth == m) {
    //모든 조합을 확인하는 부분
    let result = []; // 조합 결과 저장 테이블
    for (let i of selected) result.push(arr[i]);
    for (let x of result) answer += x + &quot; &quot;; // 계산된 조합을 실질적으로 처리하는 부분
    answer += &quot;\n&quot;;
    return;
  }
  for (let i = start; i &lt; arr.length; i++) {
    // start 지점부터 하나씩 원소 인덱스를 확인하며
    selected.push(i); // 현재 원소 선택
    dfs(arr, depth + 1, i); // 조합이므로, 재귀 함수 호출 시 다음 인덱스 넣기
    selected.pop(); // 현재원소 선택 취소
  }
}
dfc(arr, 0, 0);
console.log(answer);</code></pre>
<h3 id="정답-예시-2">정답 예시</h3>
<p>제출답안과 동일</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 백트래킹 알고리즘 문제풀이 1 (BackTracking Algorithm) 231019]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-1-BackTracking-Algorithm-231019</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-1-BackTracking-Algorithm-231019</guid>
            <pubDate>Thu, 19 Oct 2023 08:15:04 GMT</pubDate>
            <description><![CDATA[<h2 id="1-n과-m-1">1. N과 M (1)</h2>
<p><a href="https://www.acmicpc.net/problem/15649">https://www.acmicpc.net/problem/15649</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>1부터 N까지 자연수 중에서 중복 없이 M개를 고른 모든 수열을 계산</li>
<li>모든 순열의 수를 고려하기 위해 재귀 함수(백트래킹)를 사용할 수 있다.</li>
<li>하나의 순열을 트리(tree)에서 리프 노드까지의 경로로 생각할 수 있다.
-&gt; 이때, M개의 원소를 뽑는 순열을 고려하는 것이므로, 깊이(depth)는 M과 같다.</li>
<li>원소를 중복하여 선택하지 않으므로, 방문처리(visited) 배열을 사용한다.
-&gt; 한 번 선택된 원소는 다음 재귀 함수에서 다시 선택되지 않는다.</li>
</ul>
<h3 id="제출-답안">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let [n, m] = input[0].split(&quot; &quot;).map(Number);

let arr = [];

function possible(x, y) {
  for (let [a, b] of arr) {
    if (a == x || b == y) return false; // 행이나 열이 같다면 X
    if (Math.abs(a - x) == Math.abs(b - y)) return false; // 대각선 위치한 경우 X
  }
  return true;
}

function dfs(row) {
  for (let i = 1; i &lt; n; i++) {
    if (!possible(row, i)) continue;
    arr.push([row, i]);
    dfs(row + 1);
  }
}
dfs(1);
console.log(arr);</code></pre>
<p>-오답 !</p>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let [n, m] = input[0].split(&quot; &quot;).map(Number);
let arr = []; // 순열을 계산하고자 하는 원소가 담긴 배열
for (let i = 1; i &lt;= n; i++) arr.push(i); // [ 1, 2, 3, 4 ]
let visited = new Array(n).fill(false); // [ false, false, false, false ] 각 원소 인덱스별 방문 여부
let selected = []; // 현재 순열에 포함된 원소

let answer = &quot;&quot;;
function dfs(arr, depth) {
  if (depth == m) {
    //모든 순열을 확인하는 부분
    let result = []; // 순열 결과 저장 테이블
    for (let i of selected) result.push(arr[i]);
    for (let x of result) answer += x + &quot; &quot;; // 계산된 순열을 실질적으로 처리하는 부분
    answer += &quot;\n&quot;;
    return;
  }
  for (let i = 0; i &lt; arr.length; i++) {
    // 하나씩 원소 인덱스를 확인하며
    if (visited[i]) continue; //[중복X] 이미 처리된 원소라면 무시
    selected.push(i); // 현재 원소 선택
    visited[i] = true; // 현재 원소 방문 처리
    dfs(arr, depth + 1); // 재귀 함수 호출
    selected.pop(); // 현재원소 선택 취소
    visited[i] = false; // 현재 원소 방문 처리 취소
  }
}
dfc(arr, 0);
console.log(answer);</code></pre>
<br>

<h2 id="2-모든-순열">2. 모든 순열</h2>
<p><a href="https://www.acmicpc.net/problem/10974">https://www.acmicpc.net/problem/10974</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>N이 주어졌을 때, 1부터 N까지의 수로 이루어진 순열을 사전 순으로 출력</li>
<li>N의 값은 최대 8이다.
-&gt; 이때 모든 순열을 출력하므로 최대 경우의 수는 8!개이다.</li>
</ul>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]);
let arr = []; // 순열을 계산하고자 하는 원소가 담긴 배열
for (let i = 1; i &lt;= n; i++) arr.push(i);
let visited = new Array(n).fill(false); // 각 원소 인덱스별 방문 여부
let selected = []; // 현재 순열에 포함된 원소

let answer = &quot;&quot;;
function dfs(arr, depth) {
  if (depth == n) {
    //모든 순열을 확인하는 부분
    let result = []; // 순열 결과 저장 테이블
    for (let i of selected) result.push(arr[i]);
    for (let x of result) answer += x + &quot; &quot;; // 계산된 순열을 실질적으로 처리하는 부분
    answer += &quot;\n&quot;;
    return;
  }
  for (let i = 0; i &lt; arr.length; i++) {
    // 하나씩 원소 인덱스를 확인하며
    if (visited[i]) continue; //[중복X] 이미 처리된 원소라면 무시
    selected.push(i); // 현재 원소 선택
    visited[i] = true; // 현재 원소 방문 처리
    dfs(arr, depth + 1); // 재귀 함수 호출
    selected.pop(); // 현재원소 선택 취소
    visited[i] = false; // 현재 원소 방문 처리 취소
  }
}
dfc(arr, 0);
console.log(answer);</code></pre>
<h3 id="정답-예시-1">정답 예시</h3>
<p>제출답안과 동일</p>
<br>

<h2 id="3-0-만들기">3. 0 만들기</h2>
<p><a href="https://www.acmicpc.net/problem/7490">https://www.acmicpc.net/problem/7490</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>1부터 N까지의 수를 오름차순으로 쓴 수열 [1,2,3, ...N]이 있다고 할때</li>
<li>이때 각 수 사이에 사용할 수 있는 연산으로는 다음의 세가지 연산이 있다.</li>
</ul>
<ol>
<li>(-)</li>
<li>(+)</li>
<li>숫자 이어붙이기 (공백)</li>
</ol>
<ul>
<li>결과적으로 N이 주어졌을때, 수식의 결과가 0이 되는 모든 수식을 찾아야 한다.</li>
<li>테스트 케이스 및 자연수 N의 최댓값은 9이다.</li>
<li>3개의 연산 중에서 연속적으로 N번 선택하는 중복 순열 문제로 이해할 수 있다.</li>
<li>따라서 가능한 전체 경우의 수는 3의 8제곱이다.</li>
</ul>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let testCase = Number(input[0]);
let n = 0;
let arr = [];

for (let tc =1; tc &lt;= testCase; tc++) { // 각 테스트 케이스 처리
n = Number(input[tc]); // 자연수(N) 입력 받기
arr = [];
for (let i = 1; i &lt;= n; i++) arr.push(i) // 1부터 N까지의 수 삽입
dfs([],0);
console.log()
}

function dfs(result, depth) {
  if (depth == n-1) { //현재 순열 처리(중복 순열)
    let str = &#39;&#39;; // 현재 수식 문자열
    for (let i = 0; i &lt; n-1; i++) str += arr[i] +result[i];
    str += arr[n-1] +&#39;&#39;;
    current = eval(str.split(&#39; &#39;).join(&#39;&#39;)); // 공백을 제거한 뒤에 수식 계산
    if (current == 0) console.(str); // 수식의 결과가 0이 되는 경우 출력
    return;
  }
  for (let x of [&#39; &#39;, &#39;+&#39;, &#39;-&#39;]) { // +,-,혹은 이어붙이기( )
    result.push(x);
    dfs(result, depth + 1); // 재귀 함수 호출
    result.pop();
  }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 백트래킹 알고리즘 (BackTracking Algorithm) 231019]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-BackTracking-Algorithm-231019</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-BackTracking-Algorithm-231019</guid>
            <pubDate>Thu, 19 Oct 2023 08:12:54 GMT</pubDate>
            <description><![CDATA[<p><del>102일차</del></p>
<h2 id="1-백트래킹-backtracking">1. 백트래킹 (BackTracking)</h2>
<ul>
<li>일반적으로 그래프/트리의 모든 원소를 완전 탐색하기 위한 목적으로 사용</li>
<li>추후에 공부할 DFS와의 차이점<ol>
<li>DFS보다 백트래킹이 더 많이 출제</li>
<li>DFS는 일반적으로 완전 탐색 목적, 재귀 함수를 이용해 구현</li>
<li>백트래킹도 재귀 함수를 이용하는 것이 일반적이지만, 단순히 완전 탐색하는 것이 아니라 조건에 따라서 <strong>유망한 노드</strong>로 이동</li>
</ol>
</li>
</ul>
<h3 id="1-그래프-표현-방식">1) 그래프 표현 방식</h3>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/c37bfab1-ad37-4a73-befb-d3c65708f636/image.png" alt=""></p>
<h2 id="2-n-queen-문제">2. N-Queen 문제</h2>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/891a7d99-7ef2-4555-9fa6-95007f2d9327/image.png" alt=""></p>
<ul>
<li>예를들어 N = 8이라고 할 때</li>
<li>64개의 위치에 8개의 퀸을 설치하는 모든 조합의 수 = Combination(64,8)</li>
<li>따라서 단순히 모든 경우의 수를 전부 고려한다면?
-&gt; 각 퀸이 서로 공격이 가능한지 검사하는 방식을 사용한다면 <strong>경우의 수가 매우 커질 수 있다.</strong></li>
</ul>
<h3 id="1-문제해결-아이디어">1) 문제해결 아이디어</h3>
<ul>
<li>완전 탐색을 하더라도 유망한 경우에 대해서만 탐색을 진행한다면?</li>
<li>그러한 백트래킹 방식을 사용하여 훨씬 경우의 수를 줄일 수 있다.</li>
</ul>
<h3 id="2-문제-이해하기">2) 문제 이해하기</h3>
<ul>
<li>N개의 퀸을 놓기 위해서는 각 행마다 1개씩 퀸을 놓아야 한다.</li>
<li>하나의 A가 이미 존재하는 상태에서, 다른 퀸 B를 놓으려면 어떻게 해야 할까?
<img src="https://velog.velcdn.com/images/sky-pey/post/43a40b19-26d6-4923-ade4-ff6101c9ce09/image.png" alt=""></li>
</ul>
<h3 id="3-문제-해결-방법">3) 문제 해결 방법</h3>
<ul>
<li>백트래킹 진행 시 경우의 수를 최대한 줄이는 방법
방법 : 이전까지 놓았던 퀸들과 상충되지 않는 조건을 만족하는 위치에 대해서만 재귀 함수를 호출
1) 재귀 함수를 통해 모든 경우의 수를 다 찾은 뒤, 각 경우마다 가능한지 검사하는 방법
2) <strong>유망한 경우</strong>에 대해서만 재귀 함수를 호출하는 방법
-&gt; 위 경우에서는 2) 방법이 더 효율적</li>
</ul>
<h2 id="3-백트래킹의-기본-형태">3. 백트래킹의 기본 형태</h2>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/58600ce5-88bf-4dd3-b21e-9082a8007238/image.png" alt=""></p>
<h2 id="4-n-queen-문제-해결-아이디어">4. N-Queen 문제 해결 아이디어</h2>
<ul>
<li><p>가능한 모든 조합의 수를 구하는 것</p>
</li>
<li><p>매 재귀함수마다 실제로 N x N 모든 위치를 볼 필요가 없다.
<strong>[ 핵심 ]</strong> 맨 처음 행(row)부터 차례대로 퀸을 놓는다고 생각하면 가짓수를 훨씬 줄일 수 있다.</p>
</li>
<li><p>N-Queen 문제는 가능한 조합을 계산하는 것, 현재 행의 이전 행으로 돌아갈 필요가 없다.</p>
</li>
<li><p>백트래킹은 기본적으로 <strong>가능한 노드</strong>에 대하여 계속해서 재귀적으로 함수 호출</p>
</li>
<li><p>백트래킹은 모든 경우의 수를 탐색하기에 적합하다.</p>
</li>
<li><p>N-Queen 문제를 해결하기 위해서는 <strong>특정 위치(노드)의 가능 여부</strong>를 판단할 필요가 있다.</p>
</li>
<li><p>가능한 노드 여부는 다음의 두가지를 확인
<img src="https://velog.velcdn.com/images/sky-pey/post/06901799-3257-4ea5-92fc-95fc65c18148/image.png" alt=""></p>
</li>
</ul>
<h2 id="5-n-queen-정답-코드-예시">5. N-Queen 정답 코드 예시</h2>
<pre><code class="language-js">let n = 8; // 전체 map의 크기
let queens = []; // 현재 체스판에 놓인 퀸(queen)의 위치 정보들

function possible(x, y) {
  // (x, y) 위치에 퀸을 놓을 수 있는지 확인
  for (let [a, b] of queens) {
    // 현재까지 놓았던 모든 queen의 위치를 하나씩 확인하며
    if (a == x || b == y) return false; // 행이나 열이 같다면 X
    if (Math.abs(a - x) == Math.abs(b - y)) return false; // 대각선 위치한 경우 X
  }
  return true;
}

let cnt = 0;
function dfs(row) {
  if (row == n) cnt += 1; // queen을 N개 배치할 수 있는 경우 카운트
  for (let i = 0; i &lt; n; i++) {
    // 현재 행(row)에 존재하는 열을 하나씩 확인하며
    if (!possible(row, i)) continue; // 현재 위치에 놓을 수 없다면 무시
    queens.push([row, i]); // 현재 위치에 퀸 놓기
    dfs(row + 1); // 재귀함수 호출
    queens.pop(); // 현재 위치에서 퀸 제거
  }
}
dfs(0);
console.log(cnt);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 이진 탐색 알고리즘 문제풀이 2 231011]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-2-231011</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-2-231011</guid>
            <pubDate>Wed, 11 Oct 2023 13:13:12 GMT</pubDate>
            <description><![CDATA[<h2 id="1-숫자-카드-2">1. 숫자 카드 2</h2>
<p><a href="https://www.acmicpc.net/problem/10816">https://www.acmicpc.net/problem/10816</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>이진 탐색을 위해 데이터를 오름차순 정렬</li>
<li>lowerBound()와 upperBound() 이해</li>
<li>countByRange()를 사용</li>
</ul>
<h3 id="제출-답안">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]); //가지고 있는 개수
let numberArray = input[1].split(&quot; &quot;).map(Number); // 카드에 적힌 숫자 배열
let m = Number(input[2]); //쿼리 수
let queryArray = input[3].split(&quot; &quot;).map(Number); // 갯수 구해야할 배열

numberArray.sort((a, b) =&gt; a - b);

result = &quot;&quot;;
for (x of queryArray) {
  let cnt = countByRange(numberArray, x, x);
  result += cnt + &quot; &quot;;
}

console.log(result);

//함수들
function lowerBound(arr, target, start, end) {
  while (start &lt; end) {
    let mid = parseInt((start + end) / 2);
    if (arr[mid] &gt;= target) end = mid;
    else start = mid + 1;
  }
  return end;
}
function upperBound(arr, target, start, end) {
  while (start &lt; end) {
    let mid = parseInt((start + end) / 2);
    if (arr[mid] &gt; target) end = mid;
    else start = mid + 1;
  }
  return end;
}
function countByRange(arr, leftValue, rightValue) {
  let rightIndex = upperBound(arr, rightValue, 0, arr.length);
  let leftIndex = lowerBound(arr, leftValue, 0, arr.length);
  return rightIndex - leftIndex;
}</code></pre>
<ul>
<li>정답!
정답 예시와 다른 점은 <code>for of</code>를 사용한 것</li>
</ul>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]);
let arr = input[1].split(&quot; &quot;).map(Number);
let m = Number(input[2]);
let query = input[3].split(&quot; &quot;).map(Number);

arr.sort((a, b) =&gt; a - b);

answer = &quot;&quot;;
for (let i = 0; i &lt; m; i++) {
  let cnt = countByRange(arr, query[i], query[i]);
  answer += cnt + &quot; &quot;;
}
console.log(answer);

//함수 생략</code></pre>
<br>

<h2 id="2-병사-배치하기">2. 병사 배치하기</h2>
<p><a href="https://www.acmicpc.net/problem/18353">https://www.acmicpc.net/problem/18353</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>요구사항 : 전투력이 높은 병사가 앞쪽에 오도록 내림차순 정렬<ol>
<li>배치과정에서는 특정 위치의 병사를 열외시키는 방법 사용</li>
<li>남은 병사의 수가 최대가 되도록 하는 것이 목표</li>
</ol>
</li>
</ul>
<p>✨ 특정한 수열에서 <strong>&quot;가장 긴 증가하는 부분 수열&quot;</strong>을 찾는 문제</p>
<ul>
<li>Long Increasing Subsequence(LIS) 알고리즘</li>
<li>부분 수열 : 주어진 수열의 일부 항을 원래 순서대로 나열하여 얻을 수 있는 수열
<img src="https://velog.velcdn.com/images/sky-pey/post/82fa3f25-6ef3-4712-8a6f-9a992966f55b/image.png" alt=""></li>
</ul>
<ul>
<li>아이디어 : 현재 원소가 가장 크다면 뒤에 삽입하고, 그렇지 않다면 최대한 왼쪽의 원소와 교체
<img src="https://velog.velcdn.com/images/sky-pey/post/9374025f-cdc1-4b13-9ecb-8bc970ed04f5/image.png" alt=""></li>
</ul>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]); //병사 수
let arr = input[1].split(&quot; &quot;).map(Number); // 병사 별 전투력

let cnt = [];
for (let i = 0; i &lt; n; i++) {
  let a = arr[i];
  let b = arr[i + 1];
  if (a &lt; b) cnt.push(b);
}

console.log(cnt.length);</code></pre>
<p>-오답 : 출력된 숫자는 동일하지만 강의에서 제시한 형식을 사용하지 않았다.</p>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]); //병사 수
let arr = input[1].split(&quot; &quot;).map(Number); // 병사 별 전투력

arr.reverse(); // 순서를 뒤집어 최장 증가 부분 수열(LIS)문제로 변환

let d = [0]; // LIS배열
// 이진 탐색을 활용한 LIS 알고리즘 수행
for (x of arr) {
  if (d[d.length - 1] &lt; x) {
    //마지막 원소보다 현재 원소 x가 크다면 가장 뒤에 넣기
    d.push(x);
  } else {
    //  x 이하인 원소가 있다면 가능한 왼쪽에 있는 원소와 x를 교체
    let index = lowerBound(d, x, 0, d.length);
    d[index] = x;
  }
}
console.log(n - (d.length - 1));</code></pre>
<br>

<h2 id="3-k번째-수">3. K번째 수</h2>
<p><a href="https://www.acmicpc.net/problem/1300">https://www.acmicpc.net/problem/1300</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>&quot;현재 mid보다 작거나 같은 데이터의 수가 K개 이상이 되는 조건&quot;을 만족하는 mid중에서 가장 작을 값을 구하기</li>
<li>파라메트릭 서치 문제로 볼 수 있음</li>
</ul>
<h3 id="제출-답안-2">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]);
let k = Number(input[1]);

let arr = [];
for (let i = 1; i &lt;= n; i++) {
  for (let j = 1; j &lt;= n; j++) arr.push(i * j);
}

let start = 1;
let end = n ** n;

let result = 0;
while (start &lt;= end) {
  let mid = parseInt((start + end) / 2);
  let total = 0;
  for (x of arr)
    if (mid &lt;= x) {
    }
}</code></pre>
<p>-오답 : 미제출 - for문으로 arr부터 만들고 정렬하려 했는데 잘못된 방법인 걸 깨달았다. 시간초과.</p>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0]); // 배열의 크기
let k = Number(input[1]); // 인덱스 k

let start = 1; // 배열에 존재할 수있는 가장 작은 값
let end = 10 ** 10; // 배열에 존재할 수 있는 가장 큰 값

let result = 0;
while (start &lt;= end) {
  //이진 탐색 수행(반복적)
  let mid = parseInt((start + end) / 2); //현재의 중간점
  let total = 0; // mid보다 작거나 같은 데이터의 개수
  for (let i = 1; i &lt;= n; i++) {
    total += Math.min(parseInt(mid / i), n);
  }
  if (total &gt;= k) {
    //mid보다 작거나 같은 데이터의 개수 &gt;= k
    result = mid; // result에 기록
    end = mid - 1; //탐색범위 왼쪽으로 이동
  }
  // mid보다 작거나 같은 데이터의 개수 &lt; k
  else start = mid + 1;
}
console.log(result);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 이진 탐색 알고리즘 문제풀이 1 231011]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-1-231011</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-1-231011</guid>
            <pubDate>Wed, 11 Oct 2023 13:11:32 GMT</pubDate>
            <description><![CDATA[<h2 id="1-예산">1. 예산</h2>
<p><a href="https://www.acmicpc.net/problem/2512">https://www.acmicpc.net/problem/2512</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>문제 요구사항 : 적절한 상한 금액을 찾는 것이 문제의 목표</li>
<li>전체 국가 예산이 485이고, 4개의 지방 예산 요청이 120, 110, 140,150이라고 하자
-&gt; 상한 금액이 127인 경우, 배정 금액의 합이 120 + 110 + 127 + 127 = 484 이다.
<img src="image-5.png" alt="Alt text"></li>
</ul>
<ol>
<li>배정된 총 예산이 조건을 만족 -&gt; 상한금액을 증가(최대화가 목표)</li>
<li>배정된 총 예산이 조건을 만족 X -&gt; 상한 금액을 감소</li>
</ol>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0].split(&quot; &quot;)[0]); //지방의 갯수
let arr = input[1].split(&quot; &quot;).map(Number); // 지방의 예산요청
let m = Number(input[2]); // 총 예산

// 이진 탐색을 위한 시작점(start)과 끝점(end) 설정
let start = 1;
let end = arr.reduce((a, b) =&gt; Math.max(a, b));

let result = 0;
// 이진 탐색 수행(반복문)
while (start &lt;= end) {
  let mid = parseInt((start + end) / 2);
  let total = 0; // 배정된 예산의 총액 계산
  for (x of arr) {
    // 각 지방에서 요청한 예산을 하나씩 확인하며
    total += Math.min(mid, x); // 예산 배정
  }
  if (total &lt;= m) {
    // 조건 만족 -&gt; 상한액 증가
    result = mid;
    start = mid + 1;
  } else {
    // 조건 만족 X -&gt; 상한액 감소
    end = mid - 1;
  }
}
console.log(result);</code></pre>
<br>

<h2 id="2-나무-자르기">2. 나무 자르기</h2>
<p><a href="https://www.acmicpc.net/problem/2805">https://www.acmicpc.net/problem/2805</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>문제의 목표 : 적절한 높이(height) 값 찾기</li>
<li>높이를 15로 설정한 경우 총 7만큼의 나무를 얻을 수 있다
<img src="https://velog.velcdn.com/images/sky-pey/post/f7f28315-4657-450a-bf6d-3a90124bb586/image.png" alt=""></li>
</ul>
<ol>
<li>절단기의 높이가 올라가는 경우 : 얻을 수 있는 나무의 양 감소</li>
<li>절단기의 높이가 내려가는 경우 : 나무의 양 증가</li>
</ol>
<h3 id="제출-답안">제출 답안</h3>
<p>x -오답 : 코드는 1번과 거의 유사했는데 1번에서 변형을 어떻게 해야할지 몰랐다.</p>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

// 나무의 수(n), 가져갈 나무 길이(m)
let [n, m] = input[0].split(&quot; &quot;).map(Number);
let arr = input[1].split(&quot; &quot;).map(Number); // 각 나무 높이

// 이진 탐색을 위한 시작점(start)과 끝점(end) 설정
let start = 0;
let end = arr.reduce((a, b) =&gt; Math.max(a, b));

let result = 0;
// 이진 탐색 수행(반복문)
while (start &lt;= end) {
  let mid = parseInt((start + end) / 2);
  let total = 0; // mid로 잘랐을 때 얻을 수 있는 나무의 양 계산
  for (x of arr) if (x &gt; mid) total += x - mid;
  if (total &lt; m)
    end = mid - 1; // 나무의 양이 부족한 경우 더 많이 자르기 (높이 내리기)
  else {
    // 나무의 양이 충분한 경우 덜 자르기(높이 올리기)
    result = mid; // 최대한 덜 잘랐을 때가 정답이므로 result에 기록
    start = mid + 1;
  }
}
console.log(result);</code></pre>
<br>

<h2 id="3-랜선-자르기">3. 랜선 자르기</h2>
<p><a href="https://www.acmicpc.net/problem/1654">https://www.acmicpc.net/problem/1654</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>요구사항 : 랜선의 개수 N개 이상을 얻을 수 있는 길이의 최댓값</li>
</ul>
<ol>
<li>길이를 키우면, 얻을 수 있는 랜선의 수 감소</li>
<li>길이를 줄이면, 얻을 수 있는 랜선의 수 증가</li>
</ol>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

// 가지고 있는 개수(k), 필요한 개수(n)
let [k, n] = input[0].split(&quot; &quot;).map(Number);
let arr = [];
for (let i = 1; i &lt;= k; i++) arr.push(Number(input[i]));

let start = 1;
let end = arr.reduce((a, b) =&gt; Math.max(a, b));

let result = 0;
while (start &lt;= end) {
  let mid = parseInt((start + end) / 2);
  let total = 0; // 총 잘린 갯수
  for (x of arr) if (x &gt; mid) total += parseInt(x / mid); //자른 갯수 확인
  if (total &lt; n) end = mid - 1; // 갯수 부족하면 mid 줄이기
  else {
    result = mid;
    start = mid + 1;
  }
}
console.log(result);</code></pre>
<p>-오답 : 결과값은 200으로 나오지만 오답
for 문 이후 <code>if (x &gt; mid)</code> 불필요</p>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

// 가지고 있는 개수(k), 필요한 개수(n)
let k = Number(input[0].split(&quot; &quot;)[0]);
let n = Number(input[0].split(&quot; &quot;)[1]);
let arr = [];
for (let i = 1; i &lt;= k; i++) arr.push(Number(input[i]));

let start = 1;
let end = arr.reduce((a, b) =&gt; Math.max(a, b));

let result = 0;
while (start &lt;= end) {
  let mid = parseInt((start + end) / 2);
  let total = 0;
  for (x of arr) total += parseInt(x / mid);
  if (total &lt; n) end = mid - 1;
  else {
    result = mid;
    start = mid + 1;
  }
}
console.log(result);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 파라메트릭 서치(Parametric Search) 231011]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%ED%8C%8C%EB%9D%BC%EB%A9%94%ED%8A%B8%EB%A6%AD-%EC%84%9C%EC%B9%98Parametric-Search-231011</link>
            <guid>https://velog.io/@sky-pey/STUDY-%ED%8C%8C%EB%9D%BC%EB%A9%94%ED%8A%B8%EB%A6%AD-%EC%84%9C%EC%B9%98Parametric-Search-231011</guid>
            <pubDate>Wed, 11 Oct 2023 13:10:02 GMT</pubDate>
            <description><![CDATA[<h1 id="파라메트릭-서치parametric-search">파라메트릭 서치(Parametric Search)</h1>
<hr>
<br>

<h2 id="1-이진-탐색-조건">1. 이진 탐색 조건</h2>
<p>변경할(최적화 할) 값 x에 대하여 f(x)가 단조 증가 혹은 단조 감소</p>
<ul>
<li>단조 증가 함수 : x ≤ y 이면 f(x) ≤ f(y)인 경우
일반적으로 조건(constraint)은 f(x)에 대하여 정의된다.
<img src="image-3.png" alt="Alt text"></li>
</ul>
<h2 id="2-파라메트릭-서치parametric-search">2. 파라메트릭 서치(Parametric Search)</h2>
<ul>
<li>최적화 문제를 결정 문제(&#39;예&#39; 혹은 &#39;아니오&#39;)로 바꾸어 해결하는 기법이다.
예시 : 특정한 조건을 만족하는 가장 알맞은 값을 빠르게 찾는 최적화 문제</li>
<li>일반적으로 코딩 테스트에서 파라메트릭 서치 문제는 이진 탐색을 이용하여 해결할 수 있다.
파라메트릭 서치 문제의 목적 함수 예시 :
<img src="https://velog.velcdn.com/images/sky-pey/post/6fbbc6d9-a490-44e6-8f14-376c335f7745/image.png" alt=""></li>
</ul>
<h2 id="3-예산-문제">3. 예산 문제</h2>
<p><a href="https://www.acmicpc.net/problem/2512">https://www.acmicpc.net/problem/2512</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>문제 요구사항 : 적절한 상한 금액을 찾는 것이 문제의 목표</li>
<li>전체 국가 예산이 485이고, 4개의 지방 예산 요청이 120, 110, 140,150이라고 하자
-&gt; 상한 금액이 127인 경우, 배정 금액의 합이 120 + 110 + 127 + 127 = 484 이다.
<img src="https://velog.velcdn.com/images/sky-pey/post/36547cac-d996-4523-8016-2d7aa6e0bdce/image.png" alt=""></li>
</ul>
<ol>
<li>배정된 총 예산이 조건을 만족 -&gt; 상한금액을 증가(최대화가 목표)</li>
<li>배정된 총 예산이 조건을 만족 X -&gt; 상한 금액을 감소</li>
</ol>
<h3 id="정답-예시-파라메트릭-서치의-전형적인-코드-예시">정답 예시 (파라메트릭 서치의 전형적인 코드 예시)</h3>
<pre><code class="language-js">let fs = require(&quot;fs&quot;);
let input = fs.readFileSync(&quot;dev/stdin&quot;).toString().split(&quot;\n&quot;);

let n = Number(input[0].split(&quot; &quot;)[0]); //지방의 갯수
let arr = input[1].split(&quot; &quot;).map(Number); // 지방의 예산요청
let m = Number(input[2]); // 총 예산

// 이진 탐색을 위한 시작점(start)과 끝점(end) 설정
let start = 1;
let end = arr.reduce((a, b) =&gt; Math.max(a, b));

let result = 0;
// 이진 탐색 수행(반복문)
while (start &lt;= end) {
  let mid = parseInt((start + end) / 2);
  let total = 0; // 배정된 예산의 총액 계산
  for (x of arr) {
    // 각 지방에서 요청한 예산을 하나씩 확인하며
    total += Math.min(mid, x); // 예산 배정
  }
  if (total &lt;= m) {
    // 조건 만족 -&gt; 상한액 증가
    result = mid;
    start = mid + 1;
  } else {
    // 조건 만족 X -&gt; 상한액 감소
    end = mid - 1;
  }
}
console.log(result);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 이진 탐색 알고리즘 (Binary Search Algorithm) 2 231011]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Binary-Search-Algorithm-2-231011</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Binary-Search-Algorithm-2-231011</guid>
            <pubDate>Wed, 11 Oct 2023 13:08:30 GMT</pubDate>
            <description><![CDATA[<h1 id="lowerbound--upperbound">lowerBound() &amp; upperBound()</h1>
<hr>
<br>

<h2 id="1-정렬된-배열에서-특정-원소의-개수-구하기">1. 정렬된 배열에서 특정 원소의 개수 구하기</h2>
<ul>
<li>코딩 테스트에서는 정렬된 배열에서 값이 특정 범위에 해당하는 원소의 개수를 계산하는 것을 종종 요구</li>
<li>이러한 문제를 해결하기 위해 <code>lowerBound()</code>함수와 <code>upperBound()</code> 함수를 사용할 수 있다.</li>
</ul>
<h2 id="2-하한선과-상한선-함수">2. 하한선과 상한선 함수</h2>
<ul>
<li>lowerBound(arr, x) : 정렬된 순서를 유지하면서 배열 arr에 x를 넣을 가장 왼쪽 인덱스를 반환</li>
<li>upperBound(arr, x) : 정렬된 순서를 유지하면서 배열 arr에 x를 넣을 가장 오른쪽 인덱스를 반환
<img src="https://velog.velcdn.com/images/sky-pey/post/d12f04be-aa86-453e-aeb0-536a85beb0a6/image.png" alt=""></li>
</ul>
<h2 id="3-lowerbound-코드-예시">3. <code>lowerBound()</code> 코드 예시</h2>
<pre><code class="language-js">// 정렬된 순서를 유지하면서 배열에 삽일 할 가장 왼쪽 인덱스를 반환
function lowerBound(arr, target, start, end) {
  while (start &lt; end) {
    let mid = parseInt((start + end) / 2);
    if (arr[mid] &gt;= target) end = mid; //최대한 왼쪽으로 이동하기
    else start = mid + 1;
  }
  return end;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/d7ca6cd4-c8a4-4ac1-ad35-099217888891/image.png" alt=""></p>
<h2 id="4-upperbound-코드-예시">4. <code>upperBound()</code> 코드 예시</h2>
<pre><code class="language-js">// 정렬된 순서를 유지하면서 배열에 삽일 할 가장 오른쪽 인덱스를 반환
function upperBound(arr, target, start, end) {
  while (start &lt; end) {
    let mid = parseInt((start + end) / 2);
    if (arr[mid] &gt; target) end = mid;
    else start = mid + 1; //최대한 오른쪽으로 이동하기
  }
  return end;
}</code></pre>
<h2 id="5-countbyrange">5. countByRange()</h2>
<ul>
<li>정렬된 배열에서 값이 특정 범위에 속하는 원소의 개수를 계산</li>
<li>앞서 정의한 lowerBound() 함수와 upperBound() 함수를 이용해 구현할 수 있다.</li>
</ul>
<pre><code class="language-js">// 값이 [leftValue, rightValue]인 데이터의 개수를 반환하는 함수
function countByRange(arr, leftValue, rightValue) {
  // 유의 : lowerBound와 upperBound는 end의 변수의 값을 배열의 길이로 설정
  let rightIndex = upperBound(arr, rightValue, 0, arr.length);
  let leftIndex = lowerBound(arr, leftValue, 0, arr.length);
  return rightIndex - leftIndex;
}

// 배열 선언
let arr = [1, 2, 3, 3, 3, 3, 4, 4, 8, 9];
//값이 4인 데이터 개수 출력
console.log(countByRange(arr, 4, 4));
// 값이 [-1, 3] 범위에 있는 데이터 개수 출력
console.log(countByRange(arr, -1, 3));</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 이진 탐색 알고리즘 (Binary Search Algorithm) 231011]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Binary-Search-Algorithm-231011</link>
            <guid>https://velog.io/@sky-pey/STUDY-%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Binary-Search-Algorithm-231011</guid>
            <pubDate>Wed, 11 Oct 2023 13:06:04 GMT</pubDate>
            <description><![CDATA[<p><del>94일차</del></p>
<h1 id="이진-탐색-알고리즘-binary-search-algorithm">이진 탐색 알고리즘 (Binary Search Algorithm)</h1>
<hr>
<br>

<h2 id="1-동작-방식">1. 동작 방식</h2>
<ul>
<li>시작점(left)와 끝점(end)을 기준으로 탐색 범위를 명시
<img src="https://velog.velcdn.com/images/sky-pey/post/51c3dde1-09d1-420d-97e1-2cd45719d484/image.png" alt=""></li>
</ul>
<h2 id="2-시간-복잡도">2. 시간 복잡도</h2>
<ul>
<li>각 단계마다 탐색 범위를 2로 나누는 것으로 이해할 수 있다.</li>
<li>이상적인 경우 매 단계마다 범위가 반으로 감소, 로그(log) 복잡도를 가진다.</li>
</ul>
<h2 id="3-대표적인-사용법">3. 대표적인 사용법</h2>
<ul>
<li>매우 넓은 범위(억 단위 이상)에서 최적의 해를 찾아야 하는 경우</li>
<li>데이터를 정렬한 뒤에 다수의 쿼리를 날려야 하는 경우</li>
</ul>
<h2 id="4-코드-예시-재귀-함수">4. 코드 예시 (재귀 함수)</h2>
<pre><code class="language-js">// 재귀함수 소스코드 구현
function binarySearch(arr, target, start, end) {
  if (start &gt; end) return -1; //없음
  let mid = parseInt((start + end) / 2);
  // 찾은 경우 중간점 인덱스 반환
  if (arr[mid] == target) return mid;
  //중간 점 &gt; 찾는 값  일 때 왼쪽 확인
  else if (arr[mid] &gt; target) return binarySearch(arr, target, start, mid - 1);
  // 중간 점 &lt; 찾는 값  일 때 오른쪽 확인
  else return binarySearch(arr, target, mid + 1, end);
}

//n(원소의 개수)와 target(찾는 값)
let n = 10;
let target = 7;
arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];

// 이진 탐색 수행 결과 출력
let result = binarySearch(arr, target, 0, n - 1); //결과는 찾은 값의 인덱스
if (result == -1) console.log(&quot;원소가 존재하지 않습니다.&quot;);
else console.log(`${result + 1}번째 원소입니다.`);</code></pre>
<h2 id="5-코드-예시-반복문">5. 코드 예시 (반복문)</h2>
<pre><code class="language-js">// 반복문 소스코드 구현
function binarySearch(arr, target, start, end) {
  while (start &lt;= end) {
    let mid = parseInt((start + end) / 2);
    // 찾은 경우 중간점 인덱스 반환
    if (arr[mid] == target) return mid;
    //중간 점 &gt; 찾는 값  일 때 왼쪽 확인
    else if (arr[mid] &gt; target) end = mid - 1;
    // 중간 점 &lt; 찾는 값  일 때 오른쪽 확인
    else start = mid + 1;
  }
  return -1;
}

//n(원소의 개수)와 target(찾는 값)
let n = 10;
let target = 7;
arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];

// 이진 탐색 수행 결과 출력
let result = binarySearch(arr, target, 0, n - 1); //결과는 찾은 값의 인덱스
if (result == -1) console.log(&quot;원소가 존재하지 않습니다.&quot;);
else console.log(`${result + 1}번째 원소입니다.`);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useRef 231004]]></title>
            <link>https://velog.io/@sky-pey/React-useRef-231004</link>
            <guid>https://velog.io/@sky-pey/React-useRef-231004</guid>
            <pubDate>Thu, 05 Oct 2023 03:58:25 GMT</pubDate>
            <description><![CDATA[<p><del>87일차</del></p>
<h2 id="useref">useRef</h2>
<ul>
<li>렌더링에 필요하지 않은 값을 참조할 수 있는 React Hook</li>
<li>변수 관리, 특정 DOM을 선택 할 때 사용</li>
</ul>
<br>

<h3 id="1-사용">1. 사용</h3>
<h4 id="1-변수관리">1) 변수관리</h4>
<ul>
<li><p>state를 사용 시 state가 변하면 컴포넌트가 다시 렌더링되지만, ref를 사용하면 렌더링 되지 않는다. (생명주기 동안 ref값은 유지)</p>
<h4 id="2-특정-dom-선택하기">2) 특정 DOM 선택하기</h4>
</li>
<li><p>js에서는 getElementId등을 사용하지만 react에서는 ref사용</p>
</li>
<li><p>엘리먼트에 포커스를 설정하거나 스크롤바 위치를 가져오는 등에서 사용</p>
</li>
</ul>
<br>

<hr>
<br>

<h3 id="2-useref-사용-방법">2. useRef 사용 방법</h3>
<ul>
<li>useRef로 Ref 객체 생성 후 특정 DOM에 ref값으로 설정
-&gt; Ref의 .current 값이 특정 DOM을 가리킴</li>
</ul>
<pre><code class="language-js">const Test2 = () =&gt; {
  //Ref 생성
  const inputRef = useRef(null);

  const handleClick = () =&gt; {
    inputRef.current.focus();
  };
  return (
    &lt;div&gt;
        // 특정DOM에 ref 값으로 설정
      &lt;ChildComponent ref={inputRef} /&gt;
      &lt;button onClick={handleClick}&gt;클릭&lt;/button&gt;
    &lt;/div&gt;
  );
};</code></pre>
<br>

<hr>
<br>

<h3 id="3-useref로-custom-hook-만들기">3. useRef로 Custom Hook 만들기</h3>
<h4 id="1-만들-hook-설명">1) 만들 Hook 설명</h4>
<ul>
<li>모달창이 있을 때 외부를 클릭해서 모달창 닫기</li>
</ul>
<h4 id="2-useonclickoutside-hook-생성">2) useOnClickOutside Hook 생성</h4>
<pre><code class="language-js">import { useEffect } from &quot;react&quot;;

export default function useOnClickOutside(ref, handler) {
  useEffect(() =&gt; {
    const listener = event =&gt; {
      // 클릭 시 ref.current가 없거나, 모달창 안이면 그냥 return
      if (!ref.current || ref.current.contains(event.target)) {
        return;
      }
      // 그 외(모달창 외부)에는 hadler(=모달창닫기)실행
      handler(event);
    };

    document.addEventListener(&quot;mousedown&quot;, listener);
    document.addEventListener(&quot;touchstart&quot;, listener);

    //useEffect에서 return은 언마운트될때 호출
    return () =&gt; {
      document.removeEventListener(&quot;mousedown&quot;, listener);
      document.removeEventListener(&quot;touchstart&quot;, listener);
    };
  }, [ref, handler]);
}</code></pre>
<h4 id="3-hook-사용">3) Hook 사용</h4>
<ul>
<li>사용할 컴포넌트에서 적용하기<pre><code class="language-js">const ref = useRef(null);
</code></pre>
</li>
</ul>
<p>//hadler로 모달 닫는 콜백함수
  useOnClickOutside(ref, () =&gt; {
    setIsModalOpen(false);
  });</p>
<p>return (
//중략
  <div className="modal" ref={ref}>
//후략</p>
<p>```</p>
<h4 id="4-전체적인-흐름-요약">4) 전체적인 흐름 요약</h4>
<p> ① useRef로 ref 생성한 다음 사용할 모달에 ref 설정
 ② <code>&quot;mousedown&quot;</code>의 이벤트 발생 시 <code>listener</code>가 모달창 외부인지 인식
 ③ 모달창 외부가 맞으면 handler인<code>setIsModalOpen(false)</code>(모달창 닫기) 실행</p>
<br>

<hr>
<br>

<h3 id="4-usestate-vs-useref-vs-let">4. useState vs useRef vs let</h3>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/167ad36c-f4cf-4b80-94d0-fcc9c47871f6/image.png" alt=""></p>
<ul>
<li><strong>useState</strong> : state 변경마다 렌더링</li>
<li><strong>useRef</strong> : 렌더링X, 렌더링 시 초기화X (컴포넌트 생명주기동안 값이 유지)</li>
<li><strong>let 변수</strong> : 렌더링X, 렌더링 시 초기화O</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Styled Component 230926]]></title>
            <link>https://velog.io/@sky-pey/React-Styled-Component-230926</link>
            <guid>https://velog.io/@sky-pey/React-Styled-Component-230926</guid>
            <pubDate>Tue, 26 Sep 2023 10:33:43 GMT</pubDate>
            <description><![CDATA[<p><del>79일차</del></p>
<h2 id="styled-component">Styled Component</h2>
<ul>
<li>Css-in-JS라고 하는 JavaScript 파일 안에서 CSS를 처리할 수 있게 해주는 대표적인 라이브러리</li>
<li><a href="https://styled-components.com/docs/basics">https://styled-components.com/docs/basics</a></li>
</ul>
<h3 id="1-설치-방법">1. 설치 방법</h3>
<pre><code>npm install styled-components@latest</code></pre><ul>
<li>@latest 없이도 설치가 가능하지만 간혹,
<code>npm ERR! Cannot read properties of null(reading &#39;edgesOut&#39;)</code>
라는 에러가 나올 수 있어서 붙이는 게 좋다.</li>
</ul>
<h3 id="2-작성-방법">2. 작성 방법</h3>
<pre><code class="language-js">import styled from &quot;styled-components&quot;;

const Banner = () =&gt; {
  //생략
  return (
      &lt;&gt;
        &lt;Container&gt;
             &lt;HomeContainer&gt;
             &lt;/HomeContainer&gt;
        &lt;/Container&gt;
       &lt;&gt;
  ) 
};

const Container = styled.div`
display: flex;
justify-content: center;
align-item: center;
flex-direction: column;
width: 100%
height: 100vh;
`;

export default Banner;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TS/React] 직원들을 위한 위키 사이트 프로젝트 230925]]></title>
            <link>https://velog.io/@sky-pey/TSReact-%EC%A7%81%EC%9B%90%EB%93%A4%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%9C%84%ED%82%A4-%EC%82%AC%EC%9D%B4%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-230925</link>
            <guid>https://velog.io/@sky-pey/TSReact-%EC%A7%81%EC%9B%90%EB%93%A4%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%9C%84%ED%82%A4-%EC%82%AC%EC%9D%B4%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-230925</guid>
            <pubDate>Mon, 25 Sep 2023 16:07:12 GMT</pubDate>
            <description><![CDATA[<p><del>77일차</del></p>
<p>9/11 ~ 9/22 총 2주에 걸쳐 팀으로 짜여진 토이프로젝트가 진행되었다.</p>
<p>개발버전 : <a href="https://heartfelt-mandazi-9dce7c.netlify.app/">https://heartfelt-mandazi-9dce7c.netlify.app/</a>
깃 레포지토리 : <a href="https://github.com/noSPkeepgoing/Wikipage-team12">https://github.com/noSPkeepgoing/Wikipage-team12</a>
노션 : <a href="https://www.notion.so/7a5c2df8aaf7413982f8895d96d4db07">https://www.notion.so/7a5c2df8aaf7413982f8895d96d4db07</a></p>
<p>우리 조는 타이머를 포함한 스터디 사이트를 만들었고,
내가 맡은 파트는 갤러리 페이지 구현이었다.</p>
<br>

<hr>
<br>

<h2 id="gallery">Gallery</h2>
<ul>
<li>firebase를 사용하여 이미지 및 댓글을 저장 및 가져오기, 삭제를 구현.</li>
<li>gsap을 이용한 슬라이드를 구현.</li>
<li>session storage의 현재 로그인 유저의 정보를 가져와 사용.</li>
</ul>
<h3 id="1-갤러리-메인-페이지">1. 갤러리 메인 페이지</h3>
<p>  <img src="https://user-images.githubusercontent.com/125979833/269976953-44de4a4e-041c-4ead-8ef6-c0c880d65ad6.gif" alt="갤러리"></p>
<h4 id="1-내비-바">1) 내비 바</h4>
<ul>
<li>내비바에서 카테고리명 클릭 시 해당 슬라이드로 이동</li>
</ul>
<h4 id="2-이미지-추가-버튼">2) 이미지 추가 버튼</h4>
<ul>
<li><strong>비로그인 시</strong> 로그인하라는 문구(클릭하면 로그인 페이지로 이동)가 보이고,</li>
<li><strong>로그인 시</strong>에만 이미지 추가가 가능한 버튼이 보임</li>
</ul>
<h4 id="3-이미지-양방향-슬라이드">3) 이미지 양방향 슬라이드</h4>
<ul>
<li>사진에 그림자를 주어 밋밋하지 않게 만들고 슬라이드 방향도 왼쪽,오른쪽,왼쪽으로 나누어 양방향 슬라이드 구현</li>
<li>마우스 hover 시 해당 이미지 scale커지는 효과</li>
<li>이미지 클릭 시 댓글을 쓸 수 있는 모달창 팝업</li>
</ul>
<br>

<hr>
<br>

<h3 id="2-이미지-추가-모달창">2. 이미지 추가 모달창</h3>
<p> <img src="https://user-images.githubusercontent.com/125979833/269977429-cd2a9a75-59ae-4354-8c2e-8d324986429a.gif" alt="이미지모달"></p>
<ul>
<li>추가 버튼 누르면 모달창이 팝업되고, 사진을 올릴 카테고리를 선택
→ 선택된 카테고리 값을 받아 해당 카테고리 Collection에 저장 </li>
<li>사진은 Drag&amp;Drop으로 추가 가능</li>
<li>사진 추가되면 업로드 버튼이 보임</li>
<li>추가로 올리고 싶으면 다시 이미지 Drag&amp;Drop으로 업로드</li>
</ul>
<br>

<hr>
<br>

<h3 id="3-댓글리스트-모달창">3. 댓글리스트 모달창</h3>
<p><img src="https://user-images.githubusercontent.com/125979833/269977557-324ce65d-d76f-44d8-b25b-5f6ddfaec671.gif" alt="갤러리 댓글.gif"></p>
<h4 id="1-왼쪽-상단의-작성자명">1) 왼쪽 상단의 작성자명</h4>
<ul>
<li>firebase에 이미지 저장 시 작성자의 정보를 같이 저장해서, 사진 위에 업로드했던 사람의 닉네임을 보여줌</li>
</ul>
<h4 id="2-like">2) Like</h4>
<ul>
<li>마음에 들면 좋아요를 마음껏 누를 수 있음</li>
</ul>
<h4 id="3-댓글-작성-및-리스트">3) 댓글 작성 및 리스트</h4>
<ul>
<li>작성칸 위에는 본인의 닉네임이 보임</li>
<li>댓글 창에 내용이 없을 경우 내용이 비었다는 안내창이 뜸</li>
<li>버튼 또는 Enter로 제출하면 오른쪽의 댓글 리스트에 올라가며, <strong>실시간</strong>으로 업로드되도록 firebase의 onSnapshot을 사용</li>
<li>댓글 작성자 본인에게만 <strong>삭제 버튼</strong> 사용 가능 권한 부여</li>
</ul>
<h4 id="4-이미지-게시글-삭제">4) 이미지 게시글 삭제</h4>
<ul>
<li><p>이미지를 업로드한 작성자 본인에게만 버튼이 보이도록 부여
<img src="https://file.notion.so/f/f/3ef8dbd9-414c-4cf5-813d-32ecb943cc67/cdc7409f-c8ef-44e6-ac6b-bfdc8d7225e5/Untitled.png?id=21f588db-bdbd-40ce-b604-7ce3f7a934db&table=block&spaceId=3ef8dbd9-414c-4cf5-813d-32ecb943cc67&expirationTimestamp=1695744000000&signature=fK83pjByTJm16zY8euKf8-WP4m9LCeMmjd5bRqnzMWA&downloadName=Untitled.png" alt="Untitled"></p>
<br>

</li>
</ul>
<hr>
<br>

<h2 id="회고">회고</h2>
<p>프로젝트를 진행하기 직전 주에 TS와 React 강의 2차가 예정되어 있었는데 강사님의 사정으로 인해 그 주의 강의가 모두 취소 되었었다.
프로젝트를 위해 그 주에 온라인 강의나 다른 강의를 듣기는 했지만 역시 강의를 듣는 것과 직접 하는 것은 달랐다.
초반에는 공부를 다시하며 시작해서 속도가 붙지 않았지만 갈수록 익숙해지는 것이 느껴졌고, 확실히 코딩은 직접 부딪히는 게 답이라는 걸 몸소 체험하게 되었다.</p>
<p>이번에 부딪힌 문제와 에러메세지는 사실 기초적인 것이라 할 수도 있겠지만, 그래도 프로젝트 중간중간 마주친 문제들을 나열하며 복기해보려 한다.</p>
<h2 id="1-문제-복기">1. 문제 복기</h2>
<h3 id="1-prop을-내리는-과정에서의-실수">1) prop을 내리는 과정에서의 실수</h3>
<p>댓글을 쓰고 읽는 데 전혀 작동을 하지 않았고, 나중에 처음부터 다시 뜯어보니 prop을 내리는 중 실수가 있었다.
<code>userImage={userImage}</code>라고 적어야 했는데 <code>userImage</code>만 적었던 것.</p>
<h3 id="2-useeffect-미사용">2) useEffect 미사용</h3>
<p><img src="https://velog.velcdn.com/images/sky-pey/post/87ea03bf-f7e1-4cd0-90a9-07006f750d47/image.PNG" alt="">
처음에는 useEffect를 막연히 어렵게만 생각해서, useState만 사용해서 DB에 저장을 하려 했다.
그러니, 댓글을 적을 때 한템포씩 느리게 저장되었고 useEffect를 사용해 이부분이 쉽게 해결되었다.</p>
<h3 id="3-error-message-1">3) Error Message 1</h3>
<p>: <code>.map is not a function</code>
comment 및 유저정보로 이루어진 객체가 여러개 들어있는 <code>commentList</code>가 있다.
여기에 map을 사용하여 뿌려줘야 했는데,
<code>commentList.map ...</code> 이 부분에서 계속 작동을 하지 못했고, 아주 오래 붙잡다 다시 살펴보니... useState의 초기값을 []으로 하지 않아서 commentList 가 객체로 인식된 상태였다.</p>
<h3 id="4-onsnapshot을-이용한-실시간-댓글리스트-구현">4) onSnapshot을 이용한 실시간 댓글리스트 구현</h3>
<p>처음에는 useEffect로 충분히 구현할 수 있을 거라 생각했는데 그러지 못했고, firebase에서 제공하는 onSnapshot을 이용해 새로고침 없이도 댓글을 제출하면 firebase가 실시간으로 변경을 인식해 주는 로직을 사용했다.</p>
<pre><code class="language-tsx">  function realtime() {
    const fetchList = (categoryId: any, imgId: any) =&gt; {
      // 유저가 선택한 카테고리와 이미지를 doc,과 field 명으로 받음
      const userRef = doc(db, categoryId, imgId);
      //onSnapshot으로 데이터를 받아 set
      const unsub = onSnapshot(userRef, (doc: any) =&gt; {
        setCommentList(doc.data().comments);
      });
      return unsub;
    };
    return fetchList(categoryId, imgId);
  }

  useEffect((): any =&gt; {
    if (comment !== &#39;&#39;) {
      uploadCommentList(imgId, categoryId, comment);
      realtime();
    }
    setComment(&#39;&#39;);
  }, [isChange, doc, onSnapshot]);</code></pre>
<h3 id="5-실시간-댓글-삭제-에러---trim">5) 실시간 댓글 삭제 에러 - trim()</h3>
<p>현재 filter는 댓글 당 id값을 주어 해당 내용이 많이 달라졌지만 처음의 코드 구현은 이러했다.
지울 댓글의 내용과 작성자 아이디를 비교해서 불일치하는 것만 남기는 filter를 사용하려 했다.
<img src="https://velog.velcdn.com/images/sky-pey/post/965b4a1c-6273-4d2f-9231-74a2a6258566/image.png" alt="">
(이미지 상에서는 에러로 인해 댓글의 내용으로만 먼저 테스트 중)
하지만 댓글이 전혀 지워지지 않았고,
분명 콘솔을 찍어봐도 지워야 할 내용과 지울 내용이 겹치는 부분이 있었다.
comment.text와 getDelText가 같다면 true값이 나오도록 했는데, 보기에 값은 값이 있어도 false만 나오고 있는 상황이었다.
<img src="https://velog.velcdn.com/images/sky-pey/post/27a3cdcb-a3f3-4d42-870c-62401757ca67/image.png" alt=""></p>
<p>그러다 문득 생각난 게 trim()이었고... trim을 사용하니 너무 가뿐히도 해결되는게 어이없기도 하고 속편하기도 했다.
<img src="https://velog.velcdn.com/images/sky-pey/post/d87f1c6f-3ca4-45e7-adca-7527719cae83/image.png" alt=""></p>
<p>innerHTML를 사용한다면 trim()을 잊지말자.</p>
<h3 id="6-error-message-2">6) Error MeSSage 2</h3>
<p><code>Cannot read properties of null (reading &#39;useContext&#39;) TypeError: Cannot read properties of null (reading &#39;useContext&#39;)</code></p>
<p>구글링했을때 주로 꼽는 원인은 다음과 같다.</p>
<ol>
<li>설치를 다 했는지</li>
<li>import를 제대로 했는지</li>
<li>hook 사용 할 때 function안에서 썼는지</li>
</ol>
<p>나 같은 경우 3번이었다. 수정하니 바로 잘 되었다.
thanks to <a href="https://forum.moralis.io/t/solved-cannot-read-properties-of-null-reading-usecontext/21126/5">https://forum.moralis.io/t/solved-cannot-read-properties-of-null-reading-usecontext/21126/5</a></p>
<h2 id="아쉬운-점">아쉬운 점</h2>
<p>TS에서 제대로 타입을 사용하지 못한 것과, React에서 useState 나 더 다양한 Hook들을 활용하지 못한게 아쉬웠다.
곧 한 달간 TS, React를 배운 다음 토이프로젝트2, 미니프로젝트, 파이널프로젝트가 쭉 이어지게 될텐데 한달 간 정진해서 다음 토이프로젝트부터는 지금보다 더 수월하게 진행하고 싶다.</p>
<h2 id="프로젝트를-통해-얻어가는-점">프로젝트를 통해 얻어가는 점</h2>
<p>우선, 팀으로 프로젝트를 진행하는 것에 걱정이 많았는데 다들 너무 좋은 분들이라 배워가는 부분이 정말 많아 좋았다.
조원 분들께 누가 되고 싶지 않아 잠도 줄이고 주말도 없이 불태웠는데 힘든지도 모르고 꽤 재밌게 했던 것 같다.
그리고 이번 프로젝트를 통해 부트스트랩이나 SCSS도 사용하게 되었는데 생각보다 더 쉬워서 너무 좋았던 기억이 난다.
난 뭐든 완벽히 하고싶다는 생각에 무언가를 시작하는 것에 괜히 큰 마음을 먹고 시작해야 하는 좋지않은 버릇이 있었는데, 이번 프로젝트를 통해 그런 습관을 고치게 된 것 같았다.
코드는 되돌리기가 가능하니 겁먹지 말고 뭐든 시도해보자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 탐욕 알고리즘 문제풀이 4 230905]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-4-230905</link>
            <guid>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-4-230905</guid>
            <pubDate>Tue, 05 Sep 2023 13:45:55 GMT</pubDate>
            <description><![CDATA[<p><del>58일차</del></p>
<h2 id="1-박-터트리기">1. 박 터트리기</h2>
<p><a href="https://www.acmicpc.net/problem/19939">https://www.acmicpc.net/problem/19939</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>가장 많이 담긴 바구니와 가장 적게 담긴 바구니의 공의 개수 차이가 최소가 되려면?</li>
<li><blockquote>
<p>공의 개수가 최대한 연속적이게</p>
</blockquote>
</li>
<li>항상 정답은 K-1 혹은 K</li>
</ul>
<h3 id="제출-답안">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

//n개의 공, k개의 바구니
let [n, k] = input[0].split(&#39; &#39;).map(Number);

let sum = [];
for (let i = 1; i &lt; k+1; i++) { //연속적으로 수를 더하고 배열에 넣기
  sum.push(i);
}

// 연속적인 합의 값 더하기
let newSum = [...sum].reduce((prev, curr) =&gt; prev + curr);

//공의 개수와 비교
newSum==n
? console.log(sum[sum.length - 1]-1)
: console.log(-1)</code></pre>
<p>-오답 - vs는 정상 출력되었는데 이번에도 백준은 오답.
아마 올바른 그리디로 하지 않아서가 문제인 것 같다. </p>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

let n = Number(input[0].split(&#39; &#39;)[0]);
let k = Number(input[0].split(&#39; &#39;)[1]);

let summary = 0; // 1부터 k까지의 합
for (let i = 1; i &lt; k+1; i++) { 
  summary += i;
}
if (summary &gt; n) { // 공의 개수 부족
  console.log(-1);
}
else { // 공의 개수 충분
  n -= summary;
  if(n % k == 0) console.log(k-1); //k개에 각각 1씩 더하기
  else console.log(k);
}
</code></pre>
<br>

<h2 id="2-회문">2. 회문</h2>
<p><a href="https://www.acmicpc.net/problem/17609">https://www.acmicpc.net/problem/17609</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>유사회문 : 한 문자를 삭제하여 회문으로 만들 수 있는 문자열</li>
<li>문자열의 앞에서부터 한 문자씩 확인하면서 회문이 성립하는지 확인</li>
<li>성립하지 않는 위치를 찾는다면 다음의 과정으로 유사회문이 가능한지 여부 판별<ol>
<li>해당 문자를 지웠을 때 가능한지</li>
<li>대칭된 위치에 있는 문자를 지웠을 때 가능한지</li>
</ol>
</li>
</ul>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

//문자열 개수
let t = Number(input[0]);
//문자열
let arr = [];
for(let i = 1; i &lt;=n; i++) arr.push(input[i]);

//1. 회문인지 0
//2. 유사회문 1
//3. 둘다 아닌지 2

for (let text of arr) {
  // 문자열 비교
  for (let j = 1; j &lt;parseInt(text.length/2); j++)
  if (text[j-1] == text[text.length-1-j]) console.log(0) //회문일 때 0
  else if (text[j-1] !== text[text.length-1-j]) {
    // 해당원소 제거 or 반대편 원소 제거
  }
}
</code></pre>
<p>-오답 : 미제출
원소 제거 코드 구현을 하지 못했다.</p>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

function palindrome(x) {
  return x == x.split(&#39;&#39;).reverse().join(&#39;&#39;);
}

let testCases = Number(input[0]);
for (let tc = 1; tc &lt;=testCases; tc++) { //문자열 입력받기
  let data = input[tc];
  if (palindrome(data)) console.log(0); // 회문인 경우
 else {
  let found = false;
  let n = data.length; // 문자열 길이
  for (let i = 0; i &lt; parseInt(n / 2); i++) {
    if (data[i] != data[n - i - 1]) { //대칭 아닌 인덱스 찾은 경우
    //앞쪽의 해당 원소 제거 후 회문 검사
    if(palindrome(data.slice(0, i) + data.slice(i+1,n))) found = true; //해당원소 기준으로 앞뒤문자만 붙임
    //앞쪽의 해당 원소 제거 후 회문 검사
    if(palindrome(data.slice(0, n - i - 1) + data.slice(n - i, n))) found = true;
    break;
    }
  }
  if(found) console.log(1); //유사 회문
  else console.log(2); //둘다 아님
  }
}</code></pre>
<p>-&gt; 정답 예시도 런타임 에러가 나서 다시 수정해볼 예정</p>
<br>

<h2 id="3-박스-채우기">3. 박스 채우기</h2>
<p><a href="https://www.acmicpc.net/problem/1493">https://www.acmicpc.net/problem/1493</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>큐브의 길이, 너비, 높이는 항상 2의 제곱 형태를 보임</li>
<li>큰 큐브는 항상 자기보다 작은 큐브로 채울 수 있다.</li>
<li><blockquote>
<p>큰 큐브부터 채워나가면 해결 할 수 있다.</p>
</blockquote>
</li>
</ul>
<h3 id="제출-답안-2">제출 답안</h3>
<p>-오답 : 미제출</p>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);


//x보다 작거나 같으면서 가장 가까운 2^i를 찾는 함수
function nearestSquare(x) {
  let i = 1;
  while (( 2 ** i) &lt;= x) i += 1;
  return i - 1;
}


let length = Number(input[0].split(&#39; &#39;)[0]);
let width = Number(input[0].split(&#39; &#39;)[1]);
let height = Number(input[0].split(&#39; &#39;)[2]);
let cubes = Array(20).fill(0);

let n = Number(input[1]);
for(let i = 2; i &lt;=n +1; i++) {
  let a = Number(input[i].split(&#39; &#39;)[0]);
  let b = Number(input[i].split(&#39; &#39;)[1]);
  cubes[a] = b;
}

let size = 19;
size = nearestSquare(length);
size = Math.min(size, nearestSquare(width));
size = Math.min(size, nearestSquare(height));

let res = 0;
let used = 0;

for (let i = size; i &gt;= 0; i--) {
  used *= 8; // 채널, 너비, 높이가 2씩 줄었으므로 큐브의 개수는 8배 증가
  cur = (2 ** i); //현재의 정육면체 큐브의 길이
  //채워넣어야 할 큐브의 개수 계산
  let required = parseInt(length /cur)
    * parseInt(width /cur)
    * parseInt(height /cur)
    - used;

  let usage = Math.min(required, cubes[i]); // 이번 단계에서 넣을 수 있는 큐브의 개수
  res += usage;
  used += usage; 
}

if (used == length * width * height) console.log(res); //박스를 가득 채운 경우
else console.log(-1) // 박스를 가득 채우지 못한 경우</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 탐욕 알고리즘 문제풀이 3 230905]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-3-230905</link>
            <guid>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-3-230905</guid>
            <pubDate>Tue, 05 Sep 2023 13:44:15 GMT</pubDate>
            <description><![CDATA[<p><del>58일차</del></p>
<h2 id="1-주유소">1. 주유소</h2>
<p><a href="https://www.acmicpc.net/problem/13305">https://www.acmicpc.net/problem/13305</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>주유 비용을 비오름차순으로 변경</li>
<li>자기보다 뒤에 있는 비싼 주유소에 대해서 미리 결제</li>
</ul>
<h3 id="제출-답안">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;/dev/stdin&#39;).toString().split(&#39;\n&#39;);

let city = Number(input[0]);
let dArray = input[1].split(&#39; &#39;).map(Number); //거리
let pArray = input[2].split(&#39; &#39;).map(Number); //비용

let lowest = pArray[0]; //최저가

let total = pArray[0] * dArray[0]; //초기값 설정

for (let i = 1; i&lt;dArray.length -1; i++) {
  if (lowest &gt;= pArray[i]) { //최저가 비교
      lowest = pArray[i];
      for (let j = 1; j&lt;dArray.length; j++) {
        //최저가를 거리에 곱해서 총 가격(total)에 더하기
        total += lowest * dArray[j]
      }
  }
}

console.log(total);</code></pre>
<p>-오답 !
vs에서는 예시 3개가 모두 정상출력되었는데 백준에서는 틀렸다고 나온다.</p>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;/dev/stdin&#39;).toString().split(&#39;\n&#39;);

let n = Number(input[0]);
let dist = input[1].split(&#39; &#39;).map(Number);
let cost = input[2].split(&#39; &#39;).map(Number);

//주유비용(cost) 배열의 값을 비오름차순이 되도록 변환
// [5, 2, 4, 1] =&gt; [ 5, 2, 2, 1]
let minCost = cost[0];
for (let i = 0; i &lt; n; i++) {
  minCost = Math.min(minCost, cost[i]);
  cost[i] = minCost;
}

//도로당 이동 비용의 합 계산
let answer = BigInt(0);
for (let i = 0; i &lt; n-1; i++) {
  //JS에서 큰 정수 처리할때 BigInt 사용
  answer += BigInt(dist[i]) * BigInt(cost[i]);
}
console.log(String(answer)); // 뒤에 붙는 &#39;n&#39;제거
</code></pre>
<br>

<h2 id="2-회의실-배정">2. 회의실 배정</h2>
<p><a href="https://www.acmicpc.net/problem/1931">https://www.acmicpc.net/problem/1931</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>모든 회의에 대하여 오름차순 정렬</li>
<li>정렬 시 1. 종료시점 2. 시작 시점을 우선순위로 함</li>
<li>종료 시점이 이른 회의부터 확인</li>
</ul>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

//회의의 수
let n = Number(input[0]);
//회의정보
let arr = [];
for(let i = 1; i &lt;=n; i++) {
  let start = Number(input[i].split(&#39; &#39;)[0]);
  let end = Number(input[i].split(&#39; &#39;)[1]);
  arr.push([start, end]);
}

// 시작시간 오름차순 정렬
arr.sort((a,b) =&gt; a[0] - b[0]);

let cnt= 0;
let first = arr[0][0];
for (let i = 1; i&lt;n; i++) {
  if(first = arr[i][0]){  // 시작시간이 같은 회의 수대로 count 시도
    first = arr[i][0];
    cnt += 1;
  }
}

console.log(cnt);</code></pre>
<p>-오답 : <code>first = arr[i][0]</code> 이부분에 대해 판별이 되지 않고 모든 수를 count 했다.</p>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

//회의의 수
let n = Number(input[0]);
//회의정보
let arr = [];
for(let i = 1; i &lt;=n; i++) arr.push(input[i].split(&#39; &#39;).map(Number));

// 1.종료시점, 시작시점을 우선순위로 오름차순 정렬
arr.sort(function(a,b) {
  if(a[1] != b[1]) return a[1] - b[1];
  else return  a[0] - b[0]; //종료시점 같으면 시작순으로 정렬
});
let cnt= 1, cur = 0;
for (let i = 1; i&lt;n; i++) {
  if(arr[cur][1] &lt;= arr[i][0]){  //현재 회의 종료 후 시작되는 경우 카운트
    cur = i;
    cnt += 1;
  }
}
console.log(cnt);
</code></pre>
<br>

<h2 id="3-풍선-맞추기">3. 풍선 맞추기</h2>
<p><a href="https://www.acmicpc.net/problem/11509">https://www.acmicpc.net/problem/11509</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<h3 id="제출-답안-2">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

//풍선 개수
let n = Number(input[0]);
//풍선 높이
let arr = input[1].split(&#39; &#39;).map(Number);

let cnt= 1;
let height = arr[0];
for (let i = 1; i&lt;n; i++) {
  if((height - arr[i]) &lt; 1) {
    height = arr[i];
    cnt += 1;
  }
  else height = arr[i];
}

console.log(cnt); </code></pre>
<p>-오답 : vs에서 출력값은 똑같이 나왔지만, 백준에서 오답
그리고, 문제의 이해부터가 잘못되었다.
왼쪽에서부터 순서대로 시작해서 낮은 높이면 맞추고 아니면 화살을 추가한다고 생각했다.</p>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">
const rl = require(&#39;readline&#39;).createInterface({
  input: process.stdin,
  output: process.stdout
});

let input = [];
rl.on(&#39;line&#39;, function(line) {
  input.push(line);// 콘솔 입력창에서 줄바꿈 입력마다 호출
}).on(&#39;close&#39;, function() {
  let data = input[1].split(&#39; &#39;).map(Number); // 모든 풍선의 위치 정보
  let result = 0;
  let arrow = new Array(1000001).fill(0); // 각 높이에 화실이 몇 개 있는지
  for (let x of data) {
    if (arrow[x] &gt; 0) { // 해당 높이에 화살이 있다면
        arrow[x] -= 1;
        arrow[x-1] += 1;
      } else { // 해당 높이에 화살이 없다면
        arrow[x-1] += 1;
        result += 1; // 화살 쏘기
      }
    }
    console.log(result);
    process.exit();
});</code></pre>
<br>

<h2 id="4-피보나치">4. 피보나치</h2>
<p><a href="https://www.acmicpc.net/problem/9009">https://www.acmicpc.net/problem/9009</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-3">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>가능한 가장 큰 피보나치 수부터 빼 나갈 때 최소 개수 만족</li>
</ul>
<h3 id="제출-답안-3">제출 답안</h3>
<p>-오답 : 미제출</p>
<h3 id="정답-예시-3">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

// 피보나치 계산
pibo = [];
pibo.push(0);
pibo.push(1);
while (pibo[pibo.length - 1] &lt; 1e9) pibo.push(pibo[pibo.length - 2] + pibo[pibo.length - 1]);



//총 개수
let testCases = Number(input[0]);
//데이터
for(let tc = 1; tc &lt;= testCases; tc++) {
  let n = Number(input[tc]);
  let result = [];
  let i = pibo.length -1 // 가장 큰 피보나치 수의 인덱스
  while (n&gt;0) { // n이 0이 될때까지
    if (n &gt;= pibo[i]) {// 가능한 큰 피보나치 수 부터 빼기
    n -= pibo[i];
    result.push(pibo[i]);
    }
    i--;
  }
   let answer = &quot;&quot;;
for (let i = result.length - 1; i &gt;= 0; i--) 
  answer += result[i] + &quot; &quot;; //오름차순 출력
console.log(answer); 
}
</code></pre>
<br>
강의가 진행될 수록 문제 이해 자체가 어려워지면서 시간이 많이 소요되거나 방향성을 잡기가 어려워졌다.
코테 강의 한바퀴 돌고 난 후에 다시 복습을 하려 한다.
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 탐욕 알고리즘 문제풀이 2 230904]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-2</link>
            <guid>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-2</guid>
            <pubDate>Mon, 04 Sep 2023 13:02:34 GMT</pubDate>
            <description><![CDATA[<p><del>57일차</del></p>
<h2 id="1-설탕-배달">1. 설탕 배달</h2>
<p><a href="https://www.acmicpc.net/problem/2839">https://www.acmicpc.net/problem/2839</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<p>1) 현재 값이 5로 나누어 떨어지는 경우, 5로 나누면 될 것이다.
2) 그렇지 않다면, 기존의 값이 5로 나누어 떨어지는 값이 될 때까지 3을 빼준 뒤 1)을 수행한다.</p>
<h3 id="제출-답안">제출 답안</h3>
<p>미제출</p>
<p>-오답 !</p>
<ul>
<li>총 kg인 n을 5로 나누고 그 다음 3을 나누는 식으로 하려 했지만 코드를 제대로 짜지 못했다.</li>
</ul>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;./dev/stdin&#39;).toString().split(&#39;\n&#39;);

let n = Number(input[0]);
let cnt = 0;
let flag = false;

while (n &gt;= 0) {
  //n이 0이 되었거나, n로 나누어 떨어지는 값인 경우
  if ( n== 0 || n% 5 == 0) {
    cnt += parseInt(n/5);
    console.log(cnt);
    flag = true;
    break;
  }
  n -= 3;
  cnt += 1;
}
if (!flag) {
console.log(-1);
}
</code></pre>
<br>

<h2 id="2-a---b">2. A -&gt; B</h2>
<p><a href="https://www.acmicpc.net/problem/16953">https://www.acmicpc.net/problem/16953</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>값이 2로 나눠지는 경우 -&gt; 2로 나누는 연산</li>
<li>그렇지 않고, 일의 자릿수가 1인 경우 -&gt; 10으로 나누는 연산</li>
<li>위 모두 해당 X -&gt; 이동 불가능, 종료</li>
</ul>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

// 
let a = Number(input[0].split(&#39; &#39;)[0]);
let b = Number(input[0].split(&#39; &#39;)[1]);

let cnt = 0;

function count(b) {
  while (a = b) {
    if ( b% 2 == 0) {
      b /= 2;
      cnt++;
    } else {
    b = (b - 1)/10;
    cnt++;
    }
  }
  return a = b ? cnt : -1;
}

console.log(count(b));
</code></pre>
<p>-오답 : 시간초과
vs에서 예시 2개를 돌렸을 때는 정상적으로 나왔지만
나머지 예시 1개는 무한로딩, 백준에서는 시간초과가 나왔다.</p>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

let [a, b] = input[0].split(&#39; &#39;).map(Number);
let flag = false;
let result = 1;

while (a &lt;= b) {
  if (a == b) {  //  a와 b가 같아질 때 탈출
    flag = true;
    break;
  }
  if (b%2 == 0) b = parseInt(b / 2); // 2로 나누어 떨어지는 경우
  else if (b % 10 == 1) b = parseInt(b/10); // 그렇지 않고, 일의 자리수가 1인 경우
  else break; // 위의 경우가 모두 해당되지 않는 경우
  result++;
}

if (flag) console.log(result);
else console.log(-1);
</code></pre>
<br>

<h2 id="3-수들의-합">3. 수들의 합</h2>
<p><a href="https://www.acmicpc.net/problem/1789">https://www.acmicpc.net/problem/1789</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>가장 작은 수부터 더하기
1부터 시작하여, 차례대로 더하면서, 합이 S를 넘지않도록한다.</li>
</ul>
<h3 id="제출-답안-2">제출 답안</h3>
<pre><code class="language-js">

let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

// 
let s = Number(input[0]);

// 누적 시작
let cur = 0;
//총합
let sum = 0;

while ( sum &lt;= s ) {
  cur += 1;
  sum += cur;
}
console.log(cur);</code></pre>
<p>-오답 : 마지막에 -1을 하지 않았다.</p>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

let s = Number(input[0]);
let cur = 0;
let sum = 0;

while ( sum &lt;= s ) {
  cur += 1;
  sum += cur;
}
console.log(cur-1);
</code></pre>
<br>

<h2 id="4-신입-사원">4. 신입 사원</h2>
<p><a href="https://www.acmicpc.net/problem/1946">https://www.acmicpc.net/problem/1946</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-3">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>오름차순을 사용, 특정 지원자보다 두 시험 성적이 모두 높은 지원자가 있는지만 확인</li>
</ul>
<h3 id="제출-답안-3">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

let testCase = Number(input[0]); //테스트케이스 개수
let n = Number(input[1]); // 지원자수
let arr = [];
for(let i = 2; i &lt;=n; i++) {
  let [x, y] =  input[i].split(&#39; &#39;).map(Number);
  arr.push([x,y]);
}

arr.sort((a,b) =&gt; a[0] - b[0]); // 서류심사 성적순

let select = arr[0][1]; //비교 기준
let cnt = 0;
// 면접시험 비교
for (let j=1; j&lt;arr.length; j++) {
  if (select &gt;arr[j][1]) {
  select = arr[j][1];
  cnt += 1;
  }
}

console.log(cnt);</code></pre>
<p>-오답 : 테스트케이스를 다루지 못했다.</p>
<h3 id="정답-예시-3">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

let testCase = Number(input[0]); 
let line = 1;
for(let tc = 0; tc &lt;testCase; tc++) {
  let n = Number(input[line]);
  let arr = [];
  for (let i = line + 1; i &lt;=line +n; i++) {
    let data =  input[i].split(&#39; &#39;).map(Number);
    arr.push(data);
    }
arr.sort((x,y) =&gt; x[0] - y[0]);
let count = 0;
let minValue = 100001;
for (let [x,y] of arr) {
  if (y &lt; minValue) {
    minValue = y;
    count += 1;
  }
}
console.log(count);
line += n + 1;
}</code></pre>
<ul>
<li>사실 이 문제는 문제에 대한 이해도가 떨어져서 나중에 다시 풀어볼 예정이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[STUDY] 탐욕 알고리즘 문제풀이 1  230901]]></title>
            <link>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-1-230901</link>
            <guid>https://velog.io/@sky-pey/STUDY-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-1-230901</guid>
            <pubDate>Fri, 01 Sep 2023 13:11:00 GMT</pubDate>
            <description><![CDATA[<p><del>54일차</del></p>
<h2 id="1-동전-0">1. 동전 0</h2>
<p><a href="https://www.acmicpc.net/problem/11047">https://www.acmicpc.net/problem/11047</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>각 화폐 단위는 서로 배수관계</li>
<li>가치가 큰 동전은 가치가 작은 동전들의 합으로 표현 가능</li>
</ul>
<p>① 모든 화폐 단위를 내림차순으로 정렬
② 화폐의 단위를 확인하여, 해당 화폐로 나눌 때의 몫을 더하기</p>
<h3 id="제출-답안">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;./input.txt&#39;).toString().split(&#39;\n&#39;);

//동전 n종류, 총 합 k
let [n, k] = input[0].split(&#39; &#39;).map(Number);

// 동전 종류 n개만큼 가져오기
let arr = []
for(let i = 1; i &lt;=n; i++) {
  arr.push(Number(input[i]))
};

//내림차순 정렬
arr.sort((a,b) =&gt; b-a);

let coin = [];

//몫을 정수로 구해서 coin 배열에 넣어주고, 나머지를 다시 반환
for (let x = 0; x &lt; arr.length; x++) {
  if (arr[x] &lt; k) {
  coin.push(parseInt(k / arr[x]))
  return k %= arr[x]
  }
}

//coin 배열의 값 모두 더해서 출력
let answer = 0;
for (let i = 0; i &lt; coin.length; i++ ) {
  answer += coin[i];
}

console.log(answer);</code></pre>
<p>-오답 !</p>
<ul>
<li>터미널 자체에서는 에러 메세지가 뜨지 않았는데, 뜯어봤을 때 몫을 구하는 for문에서 동작하지 않은 걸 알 수 있었다.</li>
</ul>
<pre><code class="language-js">for (let x = 0; x &lt; arr.length; x++) {
  if (arr[x] &lt; k) {
    console.log(arr[x])
    }}</code></pre>
<p>이렇게 작성했을 때는 화폐들이 정상적으로 출력이 되었고,</p>
<pre><code class="language-js">  if (arr[x] &lt; k) {  
  console.log(parseInt(k / arr[x]))
  return k %= arr[x]
  }</code></pre>
<p>push 대신 콘솔을 찍어 봤을 땐 4 하나만 나왔다.
아무래도 <code>coin.push(parseInt(k / arr[x]))
  return k %= arr[x]</code> 여기서 연결이 잘 되지 않는 듯 싶었다.</p>
<h3 id="정답-예시">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;./input.txt&#39;).toString().split(&#39;\n&#39;);

let n = Number(input[0].split(&#39; &#39;)[0]);
let k = Number(input[0].split(&#39; &#39;)[1]);

let arr = [];
for(let i = 1; i &lt;=n; i++) arr.push(Number(input[i]));

let cnt = 0;
// 총개수 n개에서 n-1 = 뒤에서부터 시작, 내림차순이 된다
for (let i = n-1; i&gt;=0; i--) { 
  cnt += parseInt(k/arr[i]); // 해당 동전 몇개 사용 (몫)
  k%= arr[i]; // 해당 동전으로 거슬러 준 뒤 남은 금액 (나머지)
}

console.log(cnt);</code></pre>
<ul>
<li>정답예시와 비교
내 코드는 빈 배열에 몫을 하나씩 넣고 나중에 더 하는 방식이라 코드도 길어졌는데, 다음에는 정답 예시처럼 굳이 빈 배열을 만들 필요 없이 for문 안에서 더하는 걸 해봐야겠다. </li>
</ul>
<br>

<h2 id="2-atm">2. ATM</h2>
<p><a href="https://www.acmicpc.net/problem/11399">https://www.acmicpc.net/problem/11399</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-1">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>필요한 시간의 합의 최솟값 계산</li>
<li><blockquote>
<p>오름차순 정렬 후 누적 합 계산</p>
</blockquote>
</li>
</ul>
<h3 id="제출-답안-1">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

// 사람 수
let n = input[0].split(&#39; &#39;).map(Number);
// 각 사람이 돈을 인출하는데 걸리는 시간
let arr = input[1].split(&#39; &#39;).map(Number);
//시간 적게 소요되는 사람 우선 정렬
arr.sort((a,b) =&gt; a-b);

let answer = 0;

for (let i = 0; i &lt; n; i++) { 
  arr.reduce((acc, cur) =&gt; acc += cur) // 누적해서 누적값 리턴(으로 생각)
  answer += acc;  //Error - acc 밖으로 뺄 수 없음
}
console.log(answer);
</code></pre>
<p>-오답 : 누적 계산을 너무 어렵게만 생각했다.</p>
<h3 id="정답-예시-1">정답 예시</h3>
<pre><code class="language-js">
let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);


let n = Number(input[0]);
let arr = input[1].split(&#39; &#39;).map(Number);

arr.sort((a,b) =&gt; a-b);

let answer = 0;
let summary = 0;

for (let i = 0; i &lt; n; i++) { 
  summary += arr[i];
  answer += summary;
}
console.log(answer);</code></pre>
<br>

<h2 id="3-잃어버린-괄호">3. 잃어버린 괄호</h2>
<p><a href="https://www.acmicpc.net/problem/1541">https://www.acmicpc.net/problem/1541</a></p>
<h3 id="강의에서-제시한-문제-해결-아이디어-2">강의에서 제시한 문제 해결 아이디어</h3>
<ul>
<li>덧셈과 뺄셈 연산자로만 구성된 수식이 있을 때, 괄호를 적절히 넣어 값을 최소화 한다.</li>
<li>뺄셈 연산자를 기준으로 최대한 많은 수를 묶는다.</li>
</ul>
<h3 id="제출-답안-2">제출 답안</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

let minus = input[0].split(&#39;-&#39;);

// 미완성 미제출</code></pre>
<p>-오답 : 뺄셈 제거 후, 나온 값을 소괄호로 감싸는 방식을 생각했고 제대로 구현할 방법을 못찾고 시간이 되어 미제출로 마무리.</p>
<h3 id="정답-예시-2">정답 예시</h3>
<pre><code class="language-js">let fs = require(&#39;fs&#39;);
let input = fs.readFileSync(&#39;dev/stdin&#39;).toString().split(&#39;\n&#39;);

let groups = input[0].split(&#39;-&#39;); // [ &#39;55&#39;, &#39;50+40&#39; ]
let answer = 0;

for (let i = 0; i &lt; groups.length; i++) {
  // 각 그룹 내부에서 덧셈 연산 적용
  let cur = groups[i].split(&#39;+&#39;).map(Number).reduce((a,b)=&gt; a+b);
  if(i == 0) answer += cur // 첫번째 그룹은 항상 덧셈
  else answer -= cur; // 두번째 그룹부터 뺄셈
}
console.log(answer);</code></pre>
<ol>
<li><p>강의에서는 뺄셈을 기준으로 나눈 그룹을 그 안에서 덧셈 연산을 하도록 만들었다.</p>
</li>
<li><p>뺄셈을 제거하며 1 그룹과 2그룹, 3그룹이 나눠졌다고 하면, 뺄셈을 포함한 모습은 아래와 같을 것이다.
<code>(group1) - (group2) - (group3)</code></p>
</li>
</ol>
<p>=&gt; <code>group1</code>을 answer에 넣을 때는 덧셈으로 넣고,
그 다음 그룹은 뺄셈 연산하여 넣는 것이다.</p>
]]></description>
        </item>
    </channel>
</rss>