<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코드옆차기</title>
    <link>https://choosla.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 26 Jun 2026 15:43:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>세균없는세균맨</managingEditor>
    <image>
      <title>코드옆차기</title>
      <url>https://tistory1.daumcdn.net/tistory/5523232/attach/3f324938003f44e1a0eb40c44f34dfe0</url>
      <link>https://choosla.tistory.com</link>
    </image>
    <item>
      <title>[코드트리] 청약 챌린지 4회차 최우수 경품 언박싱 &amp;mdash; 로지텍 Wave Keys와 데스크테리어 세트</title>
      <link>https://choosla.tistory.com/31</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;4회차 최우수 후기 선정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞 선 회차의 최우수 후기들을 보면서 막연하게 나도 최우수가 되고 싶어 열심히 학습 후기를 적는 와중에 정말 운이 좋게도 나도 최우수 학습 후기로 선정되는 쾌거를 이루게 되었다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size26&quot; data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IujNy/dJMcaiRi9Vd/eL7Zmnau7Z3DweQfzkH8Y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IujNy/dJMcaiRi9Vd/eL7Zmnau7Z3DweQfzkH8Y1/img.png&quot; data-alt=&quot;코드트리 청약 챌린지 4회차 최우수 후기 선정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IujNy/dJMcaiRi9Vd/eL7Zmnau7Z3DweQfzkH8Y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIujNy%2FdJMcaiRi9Vd%2FeL7Zmnau7Z3DweQfzkH8Y1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;712&quot; height=&quot;710&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 청약 챌린지 4회차 최우수 후기 선정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;583&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Os01/dJMcadvB6GD/mN9olWOmtTVidyKvclc9gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Os01/dJMcadvB6GD/mN9olWOmtTVidyKvclc9gk/img.png&quot; data-alt=&quot;경품 발송 메시지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Os01/dJMcadvB6GD/mN9olWOmtTVidyKvclc9gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Os01%2FdJMcadvB6GD%2FmN9olWOmtTVidyKvclc9gk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;475&quot; height=&quot;237&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;583&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;경품 발송 메시지&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 내 글과 최우수 후기 간의 차이점을 열심히 분석해서 부족했던 '나만의 이야기'로 풀어 나갔던 게 최우수 선정의 이유가 아니였을까 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;매주 우수 학습 기록에 주는 10만 원 상당의 경품과 데스크테리어 세트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 청약 통장 챌린지는 매주 우수 학습 후기 한 편을 뽑아 10만 원 상당의 경품과 데스크테리어 세트를 보낸다. 4회차 북마크 오답노트 글이 그 회차의 최우수 학습 후기로 선정되면서, 며칠 뒤 책상 위에 키보드와 흰 박스 하나가 도착했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bynRDJ/dJMcahrnNI9/3pZAgYmNK7vxkSpoKWkFK1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bynRDJ/dJMcahrnNI9/3pZAgYmNK7vxkSpoKWkFK1/img.jpg&quot; data-alt=&quot;로지텍 Wave Keys 키보드 박스와 코드트리 경품 박스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bynRDJ/dJMcahrnNI9/3pZAgYmNK7vxkSpoKWkFK1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbynRDJ%2FdJMcahrnNI9%2F3pZAgYmNK7vxkSpoKWkFK1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;857&quot; height=&quot;643&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로지텍 Wave Keys 키보드 박스와 코드트리 경품 박스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;박스를 열기 전에 모니터에는 마침 코드트리 화면이 띄워져 있었다. 약점을 진단하고, 트레일을 밟고, 글을 쓰던 한 주의 결과물이 상자 하나로 책상에 도착한 셈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;박스를 열자 &quot;Thank You&quot; 한 줄&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뚜껑을 열면 가장 먼저 보이는 건 구성품이 아니라 메시지였다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3847&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nieNk/dJMcaiX0AQx/kzKBo26bv57cVSLhgduwE1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nieNk/dJMcaiX0AQx/kzKBo26bv57cVSLhgduwE1/img.jpg&quot; data-alt=&quot;박스 안쪽 &amp;quot;The Codetree Team says Thank You.&amp;quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nieNk/dJMcaiX0AQx/kzKBo26bv57cVSLhgduwE1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnieNk%2FdJMcaiX0AQx%2FkzKBo26bv57cVSLhgduwE1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;857&quot; height=&quot;674&quot; data-origin-width=&quot;3847&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;박스 안쪽 &quot;The Codetree Team says Thank You.&quot;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;The Codetree Team says Thank You.&quot; 학습 기록을 보내 준 참가자에게 운영진이 적어 둔 한 줄이다. 경품 자체보다 이 문장이 먼저 눈에 들어왔다. &lt;span style=&quot;background-color: #fdfdfc; color: #0a0a0a; text-align: start;&quot;&gt;이 한 줄에 좀 뭉클했다. 받는 사람 기분 알게 하는 패키징.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구성품 &amp;mdash; 키보드 하나와 데스크테리어 세트&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mx9Pl/dJMcafNTcBK/XfjMn2JkNUW5n9j8kzyFBK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mx9Pl/dJMcafNTcBK/XfjMn2JkNUW5n9j8kzyFBK/img.jpg&quot; data-alt=&quot;박스 내부에 차곡차곡 담긴 구성품&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mx9Pl/dJMcafNTcBK/XfjMn2JkNUW5n9j8kzyFBK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMx9Pl%2FdJMcafNTcBK%2FXfjMn2JkNUW5n9j8kzyFBK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;863&quot; height=&quot;647&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;박스 내부에 차곡차곡 담긴 구성품&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3842&quot; data-origin-height=&quot;2538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIll3M/dJMcaiKuJyW/6hANKeguOBdNpzS8QB9IV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIll3M/dJMcaiKuJyW/6hANKeguOBdNpzS8QB9IV0/img.jpg&quot; data-alt=&quot;데스크매트 위에 펼쳐 본 전체 구성품&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIll3M/dJMcaiKuJyW/6hANKeguOBdNpzS8QB9IV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIll3M%2FdJMcaiKuJyW%2F6hANKeguOBdNpzS8QB9IV0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;858&quot; height=&quot;567&quot; data-origin-width=&quot;3842&quot; data-origin-height=&quot;2538&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데스크매트 위에 펼쳐 본 전체 구성품&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경품은 크게 두 묶음이었다. 메인은 &lt;b&gt;로지텍 Wave Keys&lt;/b&gt; 무선 인체공학 키보드. 나머지는 코드트리 데스크테리어 세트로, 책상을 꾸미는 굿즈가 한 세트 들어 있었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;로지텍 Wave Keys&lt;/b&gt; &amp;mdash; 손목 받침이 붙은 무선 인체공학 키보드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데스크매트&lt;/b&gt; &amp;mdash; 책상 전체를 덮는 코드트리 로고 매트&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반팔 티셔츠&lt;/b&gt; &amp;mdash; 검은색 BECANVAS, XL 사이즈&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링 노트&lt;/b&gt; &amp;mdash; 초록색 코드트리 노트&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스티커&lt;/b&gt; &amp;mdash; 초록색 바탕에 흰 로고와 글자&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컵 받침대&lt;/b&gt; &amp;mdash; 미끌림 방지 매트가 있는 받침대&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스트랩&lt;/b&gt;&amp;nbsp; &amp;mdash; 카바리너 스트랩과 볼펜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;키캡&lt;/b&gt; &amp;mdash; 두꺼운 재질의 뭉툭한 키캡&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데스크테리어 세트 &amp;mdash; 책상이 초록으로 정리됐다&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CR4ka/dJMcahx7rzj/RxKhwc4TNAfR1WkRYbDEXK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CR4ka/dJMcahx7rzj/RxKhwc4TNAfR1WkRYbDEXK/img.jpg&quot; data-alt=&quot;데스크매트 위에 올린 노트와 티셔츠&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CR4ka/dJMcahx7rzj/RxKhwc4TNAfR1WkRYbDEXK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCR4ka%2FdJMcahx7rzj%2FRxKhwc4TNAfR1WkRYbDEXK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;847&quot; height=&quot;1129&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;데스크매트 위에 올린 노트와 티셔츠&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SxlkN/dJMcajinEb1/0ZWvKmdxhGKUB1S8RKhJ0K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SxlkN/dJMcajinEb1/0ZWvKmdxhGKUB1S8RKhJ0K/img.jpg&quot; data-alt=&quot;스티커, 컵 받침대, 스트랩, 키캡&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SxlkN/dJMcajinEb1/0ZWvKmdxhGKUB1S8RKhJ0K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSxlkN%2FdJMcajinEb1%2F0ZWvKmdxhGKUB1S8RKhJ0K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;855&quot; height=&quot;1140&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스티커, 컵 받침대, 스트랩, 키캡&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데스크매트를 책상에 까니 작업 공간이 한 번에 정리됐다. 그 위에 키보드와 마우스를 올리고, 굿즈 몇 개를 곁에 두니 책상이 제법 코드트리 색으로 채워졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자잘한 굿즈 중에서는 키캡 모양 핀버튼이 눈에 들어왔다. 삼각형 로고가 새겨진 작은 키캡 배지인데, 코딩테스트 사이트가 보내는 굿즈답다는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;검은 티셔츠와 스트랩은 바로 일상으로&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;3088&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/thfP4/dJMcacjdleU/d6YdPlf9BEGFfzVUBkLLZK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/thfP4/dJMcacjdleU/d6YdPlf9BEGFfzVUBkLLZK/img.jpg&quot; data-alt=&quot;코드트리 반팔 티셔츠를 입은 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/thfP4/dJMcacjdleU/d6YdPlf9BEGFfzVUBkLLZK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FthfP4%2FdJMcacjdleU%2Fd6YdPlf9BEGFfzVUBkLLZK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;852&quot; height=&quot;1136&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;3088&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 반팔 티셔츠를 입은 모습&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qs2HO/dJMcac4BZUC/43kpHgsctWrjt6sNAHGzzk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qs2HO/dJMcac4BZUC/43kpHgsctWrjt6sNAHGzzk/img.jpg&quot; data-alt=&quot;가방에 단 코드트리 스트랩&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qs2HO/dJMcac4BZUC/43kpHgsctWrjt6sNAHGzzk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQs2HO%2FdJMcac4BZUC%2F43kpHgsctWrjt6sNAHGzzk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;855&quot; height=&quot;1140&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;가방에 단 코드트리 스트랩&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;티셔츠는 받자마자 입어 봤다. 가슴께에 코드트리 로고가 작게 박힌 무난한 검은 반팔이라, 평소에도 부담 없이 입을 만했다. 코딩테스트 문제를 풀 때 이것을 입고 풀기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트랩은 가방에 달았다. 가방 자체에 스트랩을 달 수 있어서, 언젠간 달아야 겠다고 다짐했는데 드디어 달게 되었다. 코드트리 정말 감사하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그리고 데스크매트 위에서 다음 한 주가 이어졌다&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9APrH/dJMcacDCmkV/TsEoxvCLXnctI5vXkIxSik/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9APrH/dJMcacDCmkV/TsEoxvCLXnctI5vXkIxSik/img.jpg&quot; data-alt=&quot;키캡을 장착한 키보드 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9APrH/dJMcacDCmkV/TsEoxvCLXnctI5vXkIxSik/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9APrH%2FdJMcacDCmkV%2FTsEoxvCLXnctI5vXkIxSik%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;859&quot; height=&quot;1145&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;키캡을 장착한 키보드 모습&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 인생 첫 번째 키캡은 ESC 자리에 앉아 앞으로의 취소 동작을 수행하게 되었다. 기존 키보드가 화이트톤이라 다행이도 잘 어울리는 것 같다. 이것을 보면서 코드 챌린지를 작성하는 때가 기억나게 되어 느슨해지는 내 맘을 잡아주는 이정표가 되길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경품 박스가 책상 위에 자리를 잡은 뒤로, 데스크매트를 깔고 그 위에서 다음 회차의 문제를 풀고 글을 썼다. 받은 굿즈가 매일 눈에 들어오는 자리에 있다 보니, 다시 한번 열심히 살기로 다짐하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 보상 하나가 매주의 루틴을 어떻게 떠받치는지를 그때 처음 체감했다. 의지력만으로 두 달을 버티는 건 어렵지만, 책상 위에 놓인 작은 표식 하나가 &quot;오늘도 한 문제&quot;의 동기를 은근히 보탠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경품을 받게 해 준 4회차 글, 그리고 그 글로 시작된 7주의 완주 기록은 아래 글에 정리해 두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 4주차 최우수 학습 후기 : &lt;a href=&quot;https://choosla.tistory.com/27&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://choosla.tistory.com/27&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782313603964&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리 북마크] 맞은 문제를 다시 안 봤더니, 같은 실수를 세 번 반복하고 있었다&quot; data-og-description=&quot;Re/ 폴더와 -review.cpp로 만들던 수동 오답노트백준과 프로그래머스 시절, 깃허브 레포(CHOOSLA/Algorithm)에는 복습의 흔적이 남아 있다. 분할정복 곱셈을 다시 풀어본 Re/1629.cpp, 백트래킹을 두 번 짚어&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/27&quot; data-og-url=&quot;https://choosla.tistory.com/27&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cu9L0p/dJMb8U83Iyb/w7B1NwTlYPU52TVqBxMhcK/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/KjXdA/dJMb88Ge3YI/cfksoKUVIaUnOX7uAoVXWk/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/csTuN0/dJMb8Z3BuWG/PQceKb6eHaQ4lzFkAm6Lb0/img.png?width=2940&amp;amp;height=1652&amp;amp;face=0_0_2940_1652&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/27&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/27&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cu9L0p/dJMb8U83Iyb/w7B1NwTlYPU52TVqBxMhcK/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/KjXdA/dJMb88Ge3YI/cfksoKUVIaUnOX7uAoVXWk/img.png?width=800&amp;amp;height=490&amp;amp;face=0_0_800_490,https://scrap.kakaocdn.net/dn/csTuN0/dJMb8Z3BuWG/PQceKb6eHaQ4lzFkAm6Lb0/img.png?width=2940&amp;amp;height=1652&amp;amp;face=0_0_2940_1652');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리 북마크] 맞은 문제를 다시 안 봤더니, 같은 실수를 세 번 반복하고 있었다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Re/ 폴더와 -review.cpp로 만들던 수동 오답노트백준과 프로그래머스 시절, 깃허브 레포(CHOOSLA/Algorithm)에는 복습의 흔적이 남아 있다. 분할정복 곱셈을 다시 풀어본 Re/1629.cpp, 백트래킹을 두 번 짚어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 청약 통장 챌린지 7주 완주 후기 : &lt;a href=&quot;https://choosla.tistory.com/30&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://choosla.tistory.com/30&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782164695834&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리] 코드트리 7주 완주 후기, 의지력이 아니라 시스템이었다&quot; data-og-description=&quot;이전글https://choosla.tistory.com/29 [코드트리] 시뮬레이션은 왜 자꾸 같은 자리에서 틀리는가 &amp;mdash; 시간을 1초 단위로 쪼개는 사고법이전글https://choosla.tistory.com/28 [코드트리 갭체크 후기] 한 달 전 '불&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/30&quot; data-og-url=&quot;https://choosla.tistory.com/30&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0HWUs/dJMb9dHxSV6/cSDZedHnCr30Y9dWljj0qk/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/bK71ZH/dJMb9llgKTp/FhzFKkk011SSOzHNCRpgE0/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/bSqf0N/dJMb9eTZb0S/5KM2COcmRCL5gQjvwKeki0/img.png?width=1170&amp;amp;height=1708&amp;amp;face=0_0_1170_1708&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/30&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/30&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0HWUs/dJMb9dHxSV6/cSDZedHnCr30Y9dWljj0qk/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/bK71ZH/dJMb9llgKTp/FhzFKkk011SSOzHNCRpgE0/img.png?width=800&amp;amp;height=538&amp;amp;face=0_0_800_538,https://scrap.kakaocdn.net/dn/bSqf0N/dJMb9eTZb0S/5KM2COcmRCL5gQjvwKeki0/img.png?width=1170&amp;amp;height=1708&amp;amp;face=0_0_1170_1708');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리] 코드트리 7주 완주 후기, 의지력이 아니라 시스템이었다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이전글https://choosla.tistory.com/29 [코드트리] 시뮬레이션은 왜 자꾸 같은 자리에서 틀리는가 &amp;mdash; 시간을 1초 단위로 쪼개는 사고법이전글https://choosla.tistory.com/28 [코드트리 갭체크 후기] 한 달 전 '불&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 트레일 학습 안내 : &lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;https://www.codetree.ai/ko/trail-info&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782164519351&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩 테스트 학습 안내 | 코드트리&quot; data-og-description=&quot;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cDfAQO/dJMb9bwbSj2/ekExKYdwSuje9JqFTFzkk0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cDfAQO/dJMb9bwbSj2/ekExKYdwSuje9JqFTFzkk0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩 테스트 학습 안내 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>언박싱</category>
      <category>코드트리</category>
      <category>코드트리경품</category>
      <category>코딩테스트</category>
      <category>코딩테스트사이트추천</category>
      <category>코테공부</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/31</guid>
      <comments>https://choosla.tistory.com/31#entry31comment</comments>
      <pubDate>Tue, 23 Jun 2026 06:45:16 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리] 코드트리 7주 완주 후기, 의지력이 아니라 시스템이었다</title>
      <link>https://choosla.tistory.com/30</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;이전글&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/29&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://choosla.tistory.com/29&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782159026415&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리] 시뮬레이션은 왜 자꾸 같은 자리에서 틀리는가 &amp;mdash; 시간을 1초 단위로 쪼개는 사고법&quot; data-og-description=&quot;이전글https://choosla.tistory.com/28 [코드트리 갭체크 후기] 한 달 전 '불안정'이던 완전탐색, 다시 응시해봤다이전 글https://choosla.tistory.com/24 [코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/29&quot; data-og-url=&quot;https://choosla.tistory.com/29&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/OPvuQ/dJMb84qikou/SsaGN1kdmF6KjNDesvMYdk/img.png?width=800&amp;amp;height=694&amp;amp;face=0_0_800_694,https://scrap.kakaocdn.net/dn/hEj5n/dJMb887ivrg/XrODaztw0CI8orQKqsKDBK/img.png?width=800&amp;amp;height=694&amp;amp;face=0_0_800_694,https://scrap.kakaocdn.net/dn/ffifF/dJMb83kCIGZ/1pLciOSlxwjrtqe7mySR6k/img.png?width=1798&amp;amp;height=1562&amp;amp;face=0_0_1798_1562&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/29&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/29&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/OPvuQ/dJMb84qikou/SsaGN1kdmF6KjNDesvMYdk/img.png?width=800&amp;amp;height=694&amp;amp;face=0_0_800_694,https://scrap.kakaocdn.net/dn/hEj5n/dJMb887ivrg/XrODaztw0CI8orQKqsKDBK/img.png?width=800&amp;amp;height=694&amp;amp;face=0_0_800_694,https://scrap.kakaocdn.net/dn/ffifF/dJMb83kCIGZ/1pLciOSlxwjrtqe7mySR6k/img.png?width=1798&amp;amp;height=1562&amp;amp;face=0_0_1798_1562');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리] 시뮬레이션은 왜 자꾸 같은 자리에서 틀리는가 &amp;mdash; 시간을 1초 단위로 쪼개는 사고법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이전글https://choosla.tistory.com/28 [코드트리 갭체크 후기] 한 달 전 '불안정'이던 완전탐색, 다시 응시해봤다이전 글https://choosla.tistory.com/24 [코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[코드트리]&amp;nbsp;시뮬레이션은&amp;nbsp;왜&amp;nbsp;자꾸&amp;nbsp;같은&amp;nbsp;자리에서&amp;nbsp;틀리는가&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;2026년 6월 22일, 두 달치 깃허브 잔디가 한 칸도 비지 않았다&lt;/span&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pacAt/dJMcaff11Nr/nSceyRm3bSIiwHshB9KA91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pacAt/dJMcaff11Nr/nSceyRm3bSIiwHshB9KA91/img.png&quot; data-alt=&quot;깃허브 프로필 잔디 &amp;amp;mdash; 5월 초부터 6월 22일까지 두 달간 빈칸 없이 채워진 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pacAt/dJMcaff11Nr/nSceyRm3bSIiwHshB9KA91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpacAt%2FdJMcaff11Nr%2FnSceyRm3bSIiwHshB9KA91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;324&quot; height=&quot;233&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깃허브 프로필 잔디 &amp;mdash; 5월 초부터 6월 22일까지 두 달간 빈칸 없이 채워진 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 청약 통장 챌린지를 시작한 5월 초부터 오늘까지 매일 문제를 풀었다. 알고리즘 공부를 시작했다가 한 주 만에 멈추던 예전의 나를 떠올리면, 두 달이라는 숫자는 단순한 기간이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 두 달을 코드트리에만 쓴 것도 아니다. SSAFY 16기 코딩테스트에 합격한 뒤 면접까지 마치고 결과를 기다리고 있다. 트레일 2의 시뮬레이션 Ⅰ, Ⅱ에 쌓인 49개의 풀이가 깃허브 레포 &lt;a href=&quot;https://github.com/CHOOSLA/Algorithm&quot;&gt;CHOOSLA/Algorithm&lt;/a&gt;에 그대로 올라가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5월 10일 첫 갭체크에서 빨강, 노랑이던 네 유형은, 6월 9일 두 번째 갭체크에서 약점 목록을 모두 졸업했다. 두 달 전엔 손도 못 댄 백트래킹 문제가 이번엔 한 번에 통과로 떴다. 매주 한 편씩 6편의 학습 후기를 썼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5월 10일의 본인과 6월 23일의 본인은 숫자로도 감각으로도 다른 사람이 되어 있었다. 7주 동안 한 주도 빠짐없이 매일 자리에 앉은 본인에게, 이번 글로 축하를 한 번 보내고 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;갭체크가 한 달의 학습 좌표를 그려 주었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5월 10일, 첫 갭체크를 응시했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시뮬레이션 Ⅰ과 완전탐색 Ⅱ가 노란불(불안정)로 떴다. 완전탐색 Ⅲ와 백트래킹은 빨간불(부족).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백트래킹은 그래도 많이 풀어봤다고 자신하고 들어갔는데, 진단에서 15분 동안 두 번을 시도하고도 끝내 못 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스스로 &quot;구현이 약하다&quot;, &quot;DP가 어렵다&quot; 정도로만 막연히 잡고 있던 자기 진단이, 갭체크 결과 앞에서 구체적인 좌표로 다시 그려졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 유형에서 시간을 쓰고, 어떤 자리에서 실수가 반복되는지를 한 화면으로 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그제야 한 달의 학습 계획이 명확해졌다. 노란불 두 개를 트레일에서 직접 메우는 게 일차 목표였다. 빨간불 두 개는 노란불을 갈고 나면 자연스럽게 함께 풀리는 자리라고 보고, 트레일은 그다음 사이클로 미뤘다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드트레일 3단계로 약점을 좁혀나갔다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트레일의 3단계 기본 문제 &amp;rarr; 연습 문제 &amp;rarr; 테스트 문제&amp;nbsp; 는 단순히 풀이의 순서가 아니라, 본인의 사고가 어디서 어긋나는지를 짚어 주는 자가 진단 장치에 가까웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 이 구조를 체감한 순간은 시뮬레이션 Ⅰ의 한 테스트 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인 손으로 풀어내고 정답까지 받은 뒤 해설을 확인했더니, 해설은 변환 로직을 별도 함수로 분리해 두고 있었다. 본인 코드는 같은 로직을 &lt;code&gt;main()&lt;/code&gt; 안에 그대로 풀어 적은 형태였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;맞히긴 했는데, 풀이의 구조가 제대로 된 풀이는 아니었다&quot;는 자각이 거기서 처음 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 문제로 개념을 보고, 연습 문제에서 변형에 적용해 보고, 테스트 문제에서 본인 손으로 풀어낸 코드를 해설과 대조하는 흐름이라, 풀이 자체보다 사고의 결함이 더 분명하게 드러난다. 백준 시절에 익숙했던 &quot;일단 많이 풀어보자&quot;는 접근이 왜 자주 무너졌는지 이 구조 앞에서 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 사이클을 시뮬레이션 Ⅰ &amp;rarr; 완전탐색 Ⅱ &amp;rarr; 시뮬레이션 Ⅱ 순서로 한 달 가까이 돌렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉬운 사이클은 아니었다. 알림톡으로 매일의 학습을 시스템에 맡기고, 깃허브 자동 연동으로 통과 시점마다 잔디를 채우게 만들지 않았다면 중간에 끊겼을 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JwiXj/dJMcadvB5dw/O7SHBTkVM7AynsqEKoKwb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JwiXj/dJMcadvB5dw/O7SHBTkVM7AynsqEKoKwb0/img.png&quot; data-alt=&quot;코드트리 알림톡 카톡 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JwiXj/dJMcadvB5dw/O7SHBTkVM7AynsqEKoKwb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJwiXj%2FdJMcadvB5dw%2FO7SHBTkVM7AynsqEKoKwb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;581&quot; height=&quot;848&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1708&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 알림톡 카톡 화면&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 뒤 두 번째 갭체크에서 어떤 결과를 받게 될지는 알 수 없었지만, 매일 풀이는 멈추지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1차 갭체크와 2차 갭체크 사이 &amp;mdash; 가장 정확한 변화 세 가지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7주에서 가장 분명한 변화는 두 갭체크 결과 사이에 있다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;유형&lt;/th&gt;
&lt;th&gt;1차 (5/10)&lt;/th&gt;
&lt;th&gt;2차 (6/9)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;시뮬레이션 Ⅰ&lt;/td&gt;
&lt;td&gt;불안정(노랑)&lt;/td&gt;
&lt;td&gt;약점 목록서 빠짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;완전탐색 Ⅱ&lt;/td&gt;
&lt;td&gt;불안정(노랑)&lt;/td&gt;
&lt;td&gt;약점 목록서 빠짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;완전탐색 Ⅲ&lt;/td&gt;
&lt;td&gt;부족(빨강)&lt;/td&gt;
&lt;td&gt;2분 45초, 1트 '훌륭'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;백트래킹&lt;/td&gt;
&lt;td&gt;부족(빨강), 15분 두 시도 실패&lt;/td&gt;
&lt;td&gt;한 번에 해결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DP Ⅰ / BFS&lt;/td&gt;
&lt;td&gt;&amp;mdash;&lt;/td&gt;
&lt;td&gt;새 '부족'(빨강)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XzjME/dJMcaijtN8Y/U7Qv0iy5RhEKJTw6pfv9g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XzjME/dJMcaijtN8Y/U7Qv0iy5RhEKJTw6pfv9g1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XzjME/dJMcaijtN8Y/U7Qv0iy5RhEKJTw6pfv9g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXzjME%2FdJMcaijtN8Y%2FU7Qv0iy5RhEKJTw6pfv9g1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;354&quot; height=&quot;670&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ssuiS/dJMcaglDB5j/yccBohiXnznp0HK3NiQ2gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ssuiS/dJMcaglDB5j/yccBohiXnznp0HK3NiQ2gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ssuiS/dJMcaglDB5j/yccBohiXnznp0HK3NiQ2gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FssuiS%2FdJMcaglDB5j%2FyccBohiXnznp0HK3NiQ2gK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;299&quot; height=&quot;291&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;1496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT6faS/dJMcafG58vu/e0gisChjBmK1VwCUE2V0sK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT6faS/dJMcafG58vu/e0gisChjBmK1VwCUE2V0sK/img.png&quot; data-alt=&quot;코드트리 트레일 2 시뮬레이션 Ⅰ, Ⅱ 진행도 &amp;amp;mdash; 49문제 풀이 완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT6faS/dJMcafG58vu/e0gisChjBmK1VwCUE2V0sK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT6faS%2FdJMcafG58vu%2Fe0gisChjBmK1VwCUE2V0sK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;705&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;1496&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 트레일 2 시뮬레이션 Ⅰ, Ⅱ 진행도 &amp;mdash; 49문제 풀이 완료&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자보다 더 인상적이었던 변화는 세 자리에 남아 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변화 ① &amp;mdash; 백트래킹 한 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차 응시 때, 15분을 붙들고 두 번 시도하다 빈칸으로 넘긴 그 문제.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차에 다시 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 유형인 걸 알아챈 순간 한 달 전의 막막함부터 떠올랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 손이 먼저 움직였다. 한 번에 통과가 떴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;점수판의 색이 빨강에서 빠진 것보다, &quot;한 달 전엔 손도 못 댔는데 지금은 풀고 있다&quot;는 감각이 더 분명한 신호였다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변화 ② &amp;mdash; 깃허브 옛 풀이와 트레일 2 풀이의 차이&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RXDqI/dJMcaf74BKo/CiGEiGZcaDER5AUkK2qFD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RXDqI/dJMcaf74BKo/CiGEiGZcaDER5AUkK2qFD0/img.png&quot; data-alt=&quot;깃허브 CHOOSLA/Algorithm/SW Expert Academy/1954/ 폴더 &amp;amp;mdash; answer.cpp , main.cpp , input.txt 가 한 폴더에 놓인 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RXDqI/dJMcaf74BKo/CiGEiGZcaDER5AUkK2qFD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRXDqI%2FdJMcaf74BKo%2FCiGEiGZcaDER5AUkK2qFD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1128&quot; height=&quot;334&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깃허브 CHOOSLA/Algorithm/SW Expert Academy/1954/ 폴더 &amp;mdash; answer.cpp , main.cpp , input.txt 가 한 폴더에 놓인 화면&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SWEA 1954 달팽이 숫자 폴더에는 &lt;code&gt;answer.cpp&lt;/code&gt;와 &lt;code&gt;main.cpp&lt;/code&gt;가 같이 들어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번 틀린 뒤 정답을 옮겨 적고, 본인 코드로 다시 풀어 둔 자국이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛 &lt;code&gt;main.cpp&lt;/code&gt;도 방향 배열을 시계 방향(&lt;code&gt;{{0,1}, {1,0}, {0,-1}, {-1,0}}&lt;/code&gt;, 우-하-좌-상)으로 잡아 두긴 했다. 그러나 그 위에서 인덱스를 순환시키기 위해 별도의 헬퍼 함수를 정의해 사용했다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// 옛 SWEA 1954 main.cpp &amp;mdash; 시계 90도 회전을 위해 만든 헬퍼
int rotate(int num) {
    num = num + 1;
    if (num == 4) return 0;
    return num;
}
...
direction = rotate(direction);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 회전이 코드트리 트레일 2를 풀고 나서는 한 줄로 끝났다. 모듈러 산술을 인덱스 순환에 직접 쓰는 사고, 그리고 &lt;b&gt;문제 요구사항에 맞춰 방향 배열의 순서 자체를 새로 설계하는 사고&lt;/b&gt; 두 가지가 더해진 결과였다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;// [되돌아오기 2] &amp;mdash; 모듈러로 시계 90도 회전
dir = (dir + 1) % 4;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[작은 구슬의 이동]에서는 방향 배열을 옛 코드와 다른 순서로 새로 잡았다. &lt;code&gt;{하, 우, 좌, 상}&lt;/code&gt;. 이 순서에서는 반대 방향이 인덱스의 대칭 짝(0&amp;harr;3, 1&amp;harr;2)으로 떨어지기 때문에, 벽에 부딪힐 때의 반사는 &lt;code&gt;3 - dir&lt;/code&gt; 한 줄로 끝난다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// [작은 구슬의 이동] &amp;mdash; 방향 배열을 {하, 우, 좌, 상}으로 설계해 반사를 인덱스 대칭으로 표현
int moving[4][2] = {{1,0}, {0,1}, {0,-1}, {-1,0}};
dir = 3 - dir;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[거울에 레이저 쏘기 2]에서는 좌회전이 필요했는데, 단순히 &lt;code&gt;(dir - 1) % 4&lt;/code&gt;로 쓰면 C++의 음수 모듈로 때문에 인덱스가 음수로 튄다. &lt;code&gt;(dir + 3) % 4&lt;/code&gt;로 적으면 같은 좌회전이 음수 분기 없이 한 줄로 끝난다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// [거울에 레이저 쏘기 2] &amp;mdash; 음수 모듈로 회피한 좌회전
dir = (dir + 3) % 4;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 두 가지였다. &lt;b&gt;모듈러 연산을 인덱스 순환에 직접 쓰는 사고&lt;/b&gt;, 그리고 &lt;b&gt;문제마다 방향 배열의 순서를 다시 설계해 반사&amp;middot;회전을 인덱스 한 줄에 떨어지게 만드는 사고&lt;/b&gt;. 옛 코드에는 두 사고가 모두 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더에 나란히 놓인 두 풀이가 그 변화를 숫자보다 더 분명하게 증명하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변화 ③ &amp;mdash; 한 유형 전체를 한 줄짜리 골격으로 압축할 수 있게 됐다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 한 달이 끝나갈 무렵, 시뮬레이션 Ⅰ의 [만나는 그 순간] 한 문제에 네 번 연속 Wrong Answer를 받았다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctblZK/dJMcagza9Sz/CCurwrA1k5XZTOrzj5MAhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctblZK/dJMcagza9Sz/CCurwrA1k5XZTOrzj5MAhK/img.png&quot; data-alt=&quot;코드트리 [만나는 그 순간] 채점 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctblZK/dJMcagza9Sz/CCurwrA1k5XZTOrzj5MAhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctblZK%2FdJMcagza9Sz%2FCCurwrA1k5XZTOrzj5MAhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;850&quot; height=&quot;177&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 [만나는 그 순간] 채점 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번에 결과로 점프하려는 옛 손버릇이 두 달째에 들어와서도 같은 자리에서 같은 형태로 어긋났다는 사실이 그 화면에 그대로 떠 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 한 풀이의 실수가 아니라, 시뮬레이션 유형 전체에 대한 사고 습관의 구멍으로 받아들였다. 그 자리에서 트레일 2의 시뮬레이션 Ⅰ, Ⅱ를 끝까지 풀기로 했고, 49개의 문제를 풀고 나서야 하나의 골격이 손에 잡혔다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;상태를 정의하고, 시간을 1단위로만 전진시키고, 매 시각의 기록을 한 줄씩 적는다.&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;골격을 코드로 옮기면, 누적 시간을 가리키는 인덱스 &lt;code&gt;idx&lt;/code&gt;를 1부터 증가시키면서 매 1초의 위치를 배열에 그대로 적어 두는 한 줄로 끝난다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// [만나는 그 순간] &amp;mdash; 시간 누적 인덱스 idx에 매 초의 위치를 받아쓰는 한 줄
int idx = 1;
for (int i = 0; i &amp;lt; n; ++i) {
    for (int time = 0; time &amp;lt; t[i]; ++time) {
        p1[idx] = p1[idx - 1] + (d[i] == 'L' ? -1 : 1);
        idx++;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 한 줄짜리 패턴이, 시뮬레이션이라는 유형 전체를 풀 수 있는 표준 골격이 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;색이 빠진 자리와, 같은 문제를 한 번에 통과한 감각과, 한 유형을 한 줄로 압축하는 사고. 두 달 간의 학습이 만든 변화는 이 세 자리에 가장 정확하게 남아 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;중간에 그만두고 싶었던 고비 &amp;mdash; 매일 풀어도 나아지는지 안 보이던 한 주&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7주 동안 가장 큰 고비는 3주차 무렵이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때는 5월 23일에 SSAFY 16기 코딩테스트를 치른 직후라, 불안함 속에서 결과 발표를 기다리던 시기였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테에서 본인이 어느 자리에서 시간을 썼고 어떤 문제에서 손이 막혔는지를 떠올리면, 지금 트레일에서 풀고 있는 기본, 연습 문제들이 다음 실전 코딩테스트에서도 정말 도움이 될지 확신이 들지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 잔디는 채우고 있었다. 그러나 모니터 앞에서 손이 멈추는 자리는 여전히 경계값 조건이나 인덱스 1 차이의 실수였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이렇게 매일 조각 문제를 풀고 있는 게 정말 실력으로 쌓이고 있는 건가.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 회의감이 며칠 이어졌고, 불안 속에서도 일단 잔디를 채우는 하루하루가 2주 가까이 이어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비결은 두 가지였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비결 ① &amp;mdash; 시스템이 의지력을 대신했다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알림톡이 매일 저녁 카톡으로 학습 상태를 찔러줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브 잔디는 하루라도 빈칸이 생기면 시각적으로 도드라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그만두려고 마음먹은 날에도, 이 두 신호는 본인의 의지와 무관하게 작동했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;오늘만 하나 풀자&quot;가 되는 환경이 의지력의 부재를 메웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비결 ② &amp;mdash; 한 달 뒤 2차 갭체크에서 학습 결과가 숫자로 보였다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약점 4개가 한 달 만에 약점 목록에서 모두 빠졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과를 손으로 받고 나서야, &quot;매일 풀고 있는 것이 숫자로 쌓이고 있다&quot;는 사실이 눈에 들어왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 한 번의 숫자 확인이, 그 이후 3주를 의심 없이 채우는 데 충분한 연료가 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;두 달 동안 만든 다섯 개의 시스템&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의지력의&amp;nbsp;승리가&amp;nbsp;아니라&amp;nbsp;시스템의&amp;nbsp;승리라고&amp;nbsp;한&amp;nbsp;줄로&amp;nbsp;말할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;이유는&amp;nbsp;분명하다.&amp;nbsp;이&amp;nbsp;두&amp;nbsp;달&amp;nbsp;동안&amp;nbsp;다섯&amp;nbsp;개의&amp;nbsp;작은&amp;nbsp;시스템을&amp;nbsp;의식적으로&amp;nbsp;만들어&amp;nbsp;두었기&amp;nbsp;때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 자리에 앉히는 &lt;b&gt;알림톡&lt;/b&gt;, 그 결과를 시각화하는 &lt;b&gt;깃허브 자동 잔디&lt;/b&gt;, 틀린 문제를 다시 끌고 오는 &lt;b&gt;북마크 오답 폴더,&lt;/b&gt; 한 유형의 풀이를 한 문장으로 정리한 &lt;b&gt;시간 단위 시뮬 골격&lt;/b&gt;, 그리고 한 달 주기로 약점을 다시 진단하는 &lt;b&gt;갭체크 사이클&lt;/b&gt;. 이 다섯이다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;시스템&lt;/th&gt;
&lt;th&gt;작동 방식&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;알림톡&lt;/td&gt;
&lt;td&gt;매일 저녁 카톡으로 학습 상태 전달. 의지력을 시스템에 맡김&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;깃허브 자동 연동&lt;/td&gt;
&lt;td&gt;통과 시 자동 커밋. 빈 잔디는 시각적으로 도드라짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;북마크 오답 폴더 (4주차)&lt;/td&gt;
&lt;td&gt;&quot;한번에 못 푼 문제&quot;, &quot;해설이 더 나았던 문제&quot; 두 폴더&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;시간 단위 시뮬 골격 (6주차)&lt;/td&gt;
&lt;td&gt;&quot;상태 + 시간 1단위 전진 + 매 시각 기록&quot; 한 줄 골격&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;갭체크 주기 점검&lt;/td&gt;
&lt;td&gt;한 달마다 약점 진단 &amp;rarr; 재교정 루프&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CflIX/dJMcaccugdw/SakKC5qOaLf3WcAbktTCPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CflIX/dJMcaccugdw/SakKC5qOaLf3WcAbktTCPk/img.png&quot; data-alt=&quot;북마크 - 해설이 내 풀이보다 나았던 문제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CflIX/dJMcaccugdw/SakKC5qOaLf3WcAbktTCPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCflIX%2FdJMcaccugdw%2FSakKC5qOaLf3WcAbktTCPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;713&quot; height=&quot;221&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;북마크 - 해설이 내 풀이보다 나았던 문제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RsgiV/dJMcacDCkZu/kcyPRiZoEf9oONhJXWjTY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RsgiV/dJMcacDCkZu/kcyPRiZoEf9oONhJXWjTY1/img.png&quot; data-alt=&quot;북마크 - 한번에 못 푼 문제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RsgiV/dJMcacDCkZu/kcyPRiZoEf9oONhJXWjTY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRsgiV%2FdJMcacDCkZu%2FkcyPRiZoEf9oONhJXWjTY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;738&quot; height=&quot;357&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;북마크 - 한번에 못 푼 문제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 다섯은 따로 작동한 게 아니라 톱니바퀴처럼 맞물려 돌아갔다. 알림톡과 잔디가 매일을 자동화하고, 북마크가 틀린 문제로 끌고 가고, 골격이 풀이의 사고 비용을 낮추고, 갭체크가 한 달마다 다음 전선을 가리키는 식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1주차에 코드트리를 처음 켰을 때만 해도 머릿속에 없던 구조다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의지력만으로 코테 공부를 시작하려다 첫 주에 멈춰본 적이 있는 사람, 며칠 풀다 며칠 비우는 패턴을 못 깨본 사람이라면, 이 다섯 중 1번과 2번부터 켜 보길 권한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인의 의지보다 환경이 먼저 움직인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드트리 외 성과 &amp;mdash; SSAFY 16기 면접까지 마쳤다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 달이 코드트리 챌린지에만 쓰인 시간은 아니었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5월 23일에 SSAFY 16기 코딩테스트를 응시해 합격했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6월 8일에는 면접까지 마쳤다. 지금은 그 결과를 기다리고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s8ML5/dJMcahEQ2qh/rWfTl8oUhoBUIEqEBgb94K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s8ML5/dJMcahEQ2qh/rWfTl8oUhoBUIEqEBgb94K/img.png&quot; data-alt=&quot;싸피(SSAFY) 코팅테스트 합격&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s8ML5/dJMcahEQ2qh/rWfTl8oUhoBUIEqEBgb94K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs8ML5%2FdJMcahEQ2qh%2FrWfTl8oUhoBUIEqEBgb94K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;538&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;싸피(SSAFY) 코팅테스트 합격&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 흐름이 무관하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSAFY 코딩테스트 자체가 시뮬레이션과 완전탐색 비중이 큰 시험이다. 한 달간 트레일 2의 시뮬레이션 Ⅰ, Ⅱ를 갈고 있던 시기와 정확히 겹쳤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접 다음 날인 6월 9일에 2차 갭체크를 다시 응시했다. 1차에서 빨강, 노랑이던 네 유형이 모두 약점 목록에서 빠진 결과가 그날 떴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;면접의 긴장이 채 가시지 않은 자리에서 받은 객관적인 결과라, 한 달간의 학습이 어디까지 와 있는지가 가장 분명하게 잡힌 시점이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테 직전 한 달 동안 다듬은 시뮬레이션과 완전탐색의 풀이 흐름이, 시험장에서 시간 압박 속에 풀이 방향을 잡을 때 가장 자주 꺼내 쓴 자리였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 흐름을 병행할 수 있었던 이유는 위의 다섯 시스템 덕분이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알림톡과 잔디가 매일의 학습을 자동화해 두니, 의식적인 시간은 SSAFY 면접 준비에 쓸 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;앞으로의 다짐 &amp;mdash; 다음 전선은 DP Ⅰ과 BFS다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차 갭체크에서 새로 빨갛게 켜진 자리가 DP Ⅰ과 BFS다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 두 달 동안 시뮬레이션 Ⅰ, Ⅱ에 적용한 방식을, 같은 두 유형에 그대로 다시 걸어볼 계획이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서는 정해져 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;트레일에서 기본 &amp;rarr; 연습 &amp;rarr; 테스트 3단계를 차례로 밟는다.&lt;/li&gt;
&lt;li&gt;한번에 못 풀린 문제는 북마크 폴더에 넣는다.&lt;/li&gt;
&lt;li&gt;한 달 뒤에 다시 갭체크를 응시한다.&lt;/li&gt;
&lt;li&gt;마지막에&amp;nbsp;그&amp;nbsp;유형의&amp;nbsp;핵심&amp;nbsp;풀이&amp;nbsp;접근법을&amp;nbsp;한&amp;nbsp;문장으로&amp;nbsp;정리해&amp;nbsp;둔다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 한 사이클이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS라면 &quot;큐와 방문 배열, 그리고 처음 방문한 시각이 최단 거리&quot;라는 한 줄로 잡힐 거라고 보고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP Ⅰ은 &quot;상태 정의 + 점화식 + 메모이제이션&quot; 같은 한 줄을 빠르게 잡고 들어가고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 목표는 두 달 전과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삼성을 비롯한 대기업의 하반기 코딩테스트를 막힘 없이 통과하는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7주의 챌린지가 끝나도 시스템 다섯 개는 그대로 남는다. 코드트리는 만기 보상으로 8월까지 무료로 이용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 두 달을 BFS와 DP에 그대로 쓴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드트리에 바라는 점 &amp;mdash; 비교, 대조, 분석을 한 화면으로&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7주를 쓰면서 세 가지 기능이 있었으면 좋겠다고 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;바람 ① &amp;mdash; 갭체크 추이 뷰&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차, 2차 결과를 한 화면에 겹쳐 보여주는 기능이 있었으면 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 두 결과를 각각 캡처해 눈으로 대조해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직전 응시 대비 변화가 화살표나 차트로 자동 표시되면, &quot;한 달 동안 내가 어디서 어디까지 올랐는가&quot;라는 질문이 한 번의 클릭으로 답이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;바람 ② &amp;mdash; 오답 다시 풀 때 과거 제출 코드의 분할 뷰&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오답으로 분류해 둔 문제를 다시 풀 때, 이전에 작성했던 제출 코드를 문제 화면 옆에 분할 화면이나 슬라이드로 띄워 주는 UX가 있었으면 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 '제출 이력' 탭을 매번 새로 클릭하거나, 깃허브에 남아 있는 과거 버전을 따로 열어 대조해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복습의 본질은 과거의 잘못된 사고와 현재의 개선된 사고를 같은 화면에서 마주하는 것이라, 이 단계가 한 번에 보이게 되면 오답노트로서의 가치가 한 단계 올라간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;바람 ③ &amp;mdash; 갭체크 공통 실수 패턴 분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갭체크가 본인의 풀이를 해석해 주는 것처럼, 학습자들의 공통적인 실수 패턴을 분석해 보여 주는 화면이 있다면, 본인이 어디서 어떻게 어긋나고 있는지를 다른 학습자들과의 대비로 한 번 더 확인할 수 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;운영진께&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매주 글을 쓰게 만든 챌린지 구조 덕분에, 블로그 글로 생각을 정리하게 되었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인의 글을 매주 다시 점검하게 만든 학습 도구로서, 이 챌린지의 도움이 컸다. 감사합니다 코드트리!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AI 시대에도 알고리즘을 공부해야 하는 이유 &amp;mdash; 결국 워크플로우는 사람이 짠다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 챌린지의 마지막 미션 항목 중 하나가 &quot;AI 시대에도 우리가 알고리즘을 공부해야 하는 이유&quot;였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답은 두 달의 글 자체에 이미 적혀 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;직관의 함정은 사람과 AI가 공유한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[만나는 그 순간]에서 본인이 네 번 틀린 그 풀이 도착지 좌표만 계산하고 중간 경로를 잃어버리는 풀이는, 한 번에 결과로 점프하려는 직관의 가장 전형적인 형태다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 직관은 사람만 빠지는 함정이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 같은 함정에 빠진 코드를 그럴듯하게 완성해 놓으면, 코드 표면만으로 판별하기는 쉽지 않다. 일부 예제에서는 통과하기 때문이다. 그러나 두 객체가 3초나 5초에 스쳐 지나갔는지를 묻는 함정 케이스에서 틀린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 동안 트레일 2 시뮬레이션 Ⅰ, Ⅱ를 풀고 시간 단위 시뮬레이션 골격을 손에 갖추고 나서야 짚어낼 수 있는 종류의 결함이다. 이 표준적인 골격이 머릿속에 없으면, 코드의 표면만 보고 통과 여부를 가늠하다 같은 함정에 끌려간다. 골격이 있어야 그 코드가 어디서 무너질지를 짚어내고 교정할 수 있는 토대가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;워크플로우의 단계와 검수 지점은 사람이 정의한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 문제를 푼다는 것은 사실 한 가지 동작의 반복이다. 직관으로 한 번에 결과로 점프하지 않고, 문제를 작은 단계로 쪼갠 뒤, 각 단계의 상태를 정확히 정의하고, 그 상태를 한 줄씩 옮겨 적는 사고방식이다. 시뮬레이션이든 BFS든 DP든 본질은 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 문제 풀이는 &lt;b&gt;&quot;전체 흐름을 단계로 쪼개고, 각 단계에서 무엇이 결정되는지를 사람이 정의하는 작업&quot;&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 시대의 개발자가 하는 일도 같은 모양을 한다. AI는 단계 안의 코드 작성을 도울 수 있다. 그러나 어디서 어디까지가 한 단계인지, 어떤 상태를 추적해야 하는지, 단계 사이의 전이가 어떤 조건에서 일어나는지를 정의하는 것은 사람의 몫이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 AI가 만든 출력이 다음 단계로 넘어가도 되는지를 결정하는 검수 지점 &lt;b&gt;워크플로우의 어디에 사람이 끼어들지를 설계하는 것도 사람이 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 문제를 풀면서 손에 붙는 사고가 그것이다. 전체 흐름을 단계로 쪼개고, 단계 사이의 검수 지점을 직접 짠다는 사고방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 두 달이 본인에게 가르친 것은 시뮬레이션 골격 하나만이 아니었다. 한 문제 앞에서 직관에 기대지 않고 단계를 옮겨 적는 손버릇이었다. 같은 손버릇이 AI 시대에 사람이 짜야 하는 워크플로우의 단계 정의, AI 출력의 검수 지점 배치, 그리고 도메인의 복잡성을 단계로 치환하는 사고에 그대로 옮겨 간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 공부가 그 토대다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며 &amp;mdash; 7주는 의지력의 승리가 아니라 시스템의 승리였다&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/unisg/dJMcaay0JII/w34pSTiRNdrt5GaphDTJ01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/unisg/dJMcaay0JII/w34pSTiRNdrt5GaphDTJ01/img.png&quot; data-alt=&quot;코드트리 청약 통장 챌린지 마이페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/unisg/dJMcaay0JII/w34pSTiRNdrt5GaphDTJ01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Funisg%2FdJMcaay0JII%2Fw34pSTiRNdrt5GaphDTJ01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;691&quot; height=&quot;465&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 청약 통장 챌린지 마이페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7주 동안 가장 자주 확인한 사실은 의지력이 자주 꺾인다는 것이었다. 그 빈자리를 시스템이 바로 잡아주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알림톡이 매일 자리에 앉히고, 잔디가 시각화한다. 북마크가 틀린 문제로 끌고 가고, 골격이 풀이의 사고 비용을 낮춘다. 갭체크가 한 달마다 다음 목표를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7주의 만기는 끝이 아니다. 갭체크의 새 빨간불인 DP Ⅰ과 BFS가 다음 한 달의 목표로 켜져 있고, 위에서 언급했던 알림톡, 깃허브 자동 잔디, 북마크 오답 폴더, 알고리즘 분석, 갭체크 사이클의 시스템으로 학습한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두&amp;nbsp;달&amp;nbsp;전에&amp;nbsp;처음&amp;nbsp;만든&amp;nbsp;학습&amp;nbsp;구조가&amp;nbsp;두&amp;nbsp;달&amp;nbsp;뒤에도&amp;nbsp;본인을&amp;nbsp;매일&amp;nbsp;자리에&amp;nbsp;앉히고&amp;nbsp;있다는&amp;nbsp;사실&amp;nbsp;자체가,&amp;nbsp;이번&amp;nbsp;챌린지가&amp;nbsp;남긴&amp;nbsp;가장&amp;nbsp;값진&amp;nbsp;성과였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;챌린지 도중에 한 회차의 글이 그 회차의 &lt;b&gt;최우수 학습 후기로 선정&lt;/b&gt;되면서, 박스가 도착하기도 했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGHDsu/dJMcaff11RB/NcyYKkwpKK34S2lJsoXAK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGHDsu/dJMcaff11RB/NcyYKkwpKK34S2lJsoXAK0/img.png&quot; data-alt=&quot;4회차 최우수 학습 후기 선정 경품 (마우스는 아니다)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGHDsu/dJMcaff11RB/NcyYKkwpKK34S2lJsoXAK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGHDsu%2FdJMcaff11RB%2FNcyYKkwpKK34S2lJsoXAK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;550&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;4회차 최우수 학습 후기 선정 경품 (마우스는 아니다)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 박스가 책상 위에 자리를 잡은 뒤로는, 다음 회차들의 글을 이어 가는 일이 조금 덜 무겁게 느껴졌다. 도착한 경품의 구성품과 언박싱 기록은 따로 정리해 두었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;4회차&amp;nbsp;최우수&amp;nbsp;경품&amp;nbsp;언박싱&amp;nbsp;후기&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/31&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://choosla.tistory.com/31&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782164847280&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리] 청약 챌린지 4회차 최우수 경품 언박싱 &amp;mdash; 로지텍 Wave Keys와 데스크테리어 세트&quot; data-og-description=&quot;매주 우수 학습 기록에 주는 10만 원 상당의 경품코드트리 청약 통장 챌린지는 매주 우수 학습 후기 한 편을 뽑아 10만 원 상당의 경품을 보낸다. 4회차 북마크 오답노트 글이 그 회차의 최우수 학&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/31&quot; data-og-url=&quot;https://choosla.tistory.com/31&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/faekn/dJMb9jgG16t/tCMQSzdu1TMLUeq53l5210/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/b76nHl/dJMb9jOwyQd/EJj6UoLDPaeyhTUkqEEhb1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bgaF6s/dJMb9lMk710/HHtByJuR6NsWlEv62Z4MO1/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/31&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/31&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/faekn/dJMb9jgG16t/tCMQSzdu1TMLUeq53l5210/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/b76nHl/dJMb9jOwyQd/EJj6UoLDPaeyhTUkqEEhb1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bgaF6s/dJMb9lMk710/HHtByJuR6NsWlEv62Z4MO1/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리] 청약 챌린지 4회차 최우수 경품 언박싱 &amp;mdash; 로지텍 Wave Keys와 데스크테리어 세트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;매주 우수 학습 기록에 주는 10만 원 상당의 경품코드트리 청약 통장 챌린지는 매주 우수 학습 후기 한 편을 뽑아 10만 원 상당의 경품을 보낸다. 4회차 북마크 오답노트 글이 그 회차의 최우수 학&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7주를 잘 버틴 나에게, 그리고 7주의 글을 매주 읽어주신 코드트리 운영진과 다른 학습자분들께 축하와 감사를 보낸다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 트레일 2 학습 안내 : &lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;https://www.codetree.ai/ko/trail-info&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782158340612&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩 테스트 학습 안내 | 코드트리&quot; data-og-description=&quot;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cDfAQO/dJMb9bwbSj2/ekExKYdwSuje9JqFTFzkk0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cDfAQO/dJMb9bwbSj2/ekExKYdwSuje9JqFTFzkk0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩 테스트 학습 안내 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>SSAFY</category>
      <category>공채합격</category>
      <category>북마크오답노트</category>
      <category>시뮬레이션</category>
      <category>알고리즘</category>
      <category>완전탐색</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <category>코딩테스트사이트추천</category>
      <category>코테공부</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/30</guid>
      <comments>https://choosla.tistory.com/30#entry30comment</comments>
      <pubDate>Mon, 22 Jun 2026 23:57:30 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리] 시뮬레이션은 왜 자꾸 같은 자리에서 틀리는가 &amp;mdash; 시간을 1초 단위로 쪼개는 사고법</title>
      <link>https://choosla.tistory.com/29</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;이전글&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/28&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://choosla.tistory.com/28&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1782158933933&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리 갭체크 후기] 한 달 전 '불안정'이던 완전탐색, 다시 응시해봤다&quot; data-og-description=&quot;이전 글https://choosla.tistory.com/24 [코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/28&quot; data-og-url=&quot;https://choosla.tistory.com/28&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vl5rB/dJMb8XSfCet/PGgejxRwMr99DBUJ3SlxvK/img.png?width=800&amp;amp;height=853&amp;amp;face=0_0_800_853,https://scrap.kakaocdn.net/dn/sltra/dJMb8Xkpezt/0E2RH2YGs6rks4KoM3RYa1/img.png?width=800&amp;amp;height=853&amp;amp;face=0_0_800_853,https://scrap.kakaocdn.net/dn/PQwM4/dJMb8T99tyN/pyakkXVFFZLB8AH3bG03O0/img.png?width=932&amp;amp;height=1042&amp;amp;face=0_0_932_1042&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/28&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/28&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vl5rB/dJMb8XSfCet/PGgejxRwMr99DBUJ3SlxvK/img.png?width=800&amp;amp;height=853&amp;amp;face=0_0_800_853,https://scrap.kakaocdn.net/dn/sltra/dJMb8Xkpezt/0E2RH2YGs6rks4KoM3RYa1/img.png?width=800&amp;amp;height=853&amp;amp;face=0_0_800_853,https://scrap.kakaocdn.net/dn/PQwM4/dJMb8T99tyN/pyakkXVFFZLB8AH3bG03O0/img.png?width=932&amp;amp;height=1042&amp;amp;face=0_0_932_1042');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리 갭체크 후기] 한 달 전 '불안정'이던 완전탐색, 다시 응시해봤다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이전 글https://choosla.tistory.com/24 [코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;[코드트리&amp;nbsp;갭체크&amp;nbsp;후기]&amp;nbsp;한&amp;nbsp;달&amp;nbsp;전&amp;nbsp;'불안정'이던&amp;nbsp;완전탐색,&amp;nbsp;다시&amp;nbsp;응시해봤다&lt;/span&gt;&lt;/span&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;한 문제에서 네 번 연속 Wrong Answer를 받았다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[만나는 그 순간] 채점 화면에 Wrong Answer가 네 번 연속 떴다. 두 객체가 각자 방향과 속도로 움직이다가 최초로 같은 좌표에 놓이는 시각을 구하는 문제였고, 처음 봤을 땐 시뮬레이션이라기보다 산술 문제에 가까워 보였다. 명령어 인덱스를 따라 각 객체의 최종 좌표를 누적 합산하고, 그 값을 비교하는 코드 한 벌을 짜서 제출했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루프 범위와 조건문을 바꿔가며 세 번을 더 제출했지만 같은 답이 돌아왔다. &lt;b&gt;같은 문제에서 네 번 연속 오답을 받은 시점부터, 풀이 방식 자체가 틀렸다고 의심하기 시작했다.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YXG0Z/dJMcahY7X7v/NWb0RrRFR9tBvasknHkFY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YXG0Z/dJMcahY7X7v/NWb0RrRFR9tBvasknHkFY0/img.png&quot; data-alt=&quot;코드트리 [만나는 그 순간] 채점 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YXG0Z/dJMcahY7X7v/NWb0RrRFR9tBvasknHkFY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYXG0Z%2FdJMcahY7X7v%2FNWb0RrRFR9tBvasknHkFY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;206&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 [만나는 그 순간] 채점 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상한 일은, 4회차 글에서 북마크로 경계값 실수를 잡겠다고 다짐해 놓고 6회차에 들어 시뮬레이션 앞에서 같은 형태로 다시 어긋났다는 점이다. 깃허브 &lt;a href=&quot;https://github.com/CHOOSLA/Algorithm&quot;&gt;CHOOSLA/Algorithm&lt;/a&gt;의 &lt;code&gt;SW Expert Academy/1954&lt;/code&gt; 폴더를 열어보면 한 문제 안에 &lt;code&gt;answer.cpp&lt;/code&gt;와 &lt;code&gt;main.cpp&lt;/code&gt;가 나란히 들어 있다. 달팽이 숫자 &amp;mdash; 격자 회전 시뮬레이션 &amp;mdash; 를 한 번에 통과하지 못해 정답 풀이를 따로 옮겨 적어두고, 같은 문제를 본인 코드로 다시 한 번 풀어 둔 흔적이다. &lt;code&gt;1206&lt;/code&gt;, &lt;code&gt;1247&lt;/code&gt;에도 같은 짝이 있다. &lt;b&gt;시뮬레이션 유형만 만나면 한 번에 통과하지 못해 따로 다시 풀어 두는 패턴이 옛 폴더부터 반복되고 있었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxO2V/dJMcacwM4Bb/YdIkiQtIlIIc5Kuoq0yzf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxO2V/dJMcacwM4Bb/YdIkiQtIlIIc5Kuoq0yzf1/img.png&quot; data-alt=&quot;깃허브&amp;amp;nbsp; CHOOSLA/Algorithm/SW Expert Academy/1954/ &amp;amp;nbsp;&amp;amp;mdash;&amp;amp;nbsp; answer.cpp &amp;amp;nbsp;&amp;amp;middot;&amp;amp;nbsp; main.cpp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxO2V/dJMcacwM4Bb/YdIkiQtIlIIc5Kuoq0yzf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxO2V%2FdJMcacwM4Bb%2FYdIkiQtIlIIc5Kuoq0yzf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;211&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깃허브&amp;nbsp; CHOOSLA/Algorithm/SW Expert Academy/1954/ &amp;nbsp;&amp;mdash;&amp;nbsp; answer.cpp &amp;nbsp;&amp;middot;&amp;nbsp; main.cpp&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 시뮬레이션 유형을 배울 때의 정의는 단순했다. &quot;문제에 적힌 규칙을 그대로 따라 구현하면 되는 유형&quot; 정도로 이해하고 있었다. 그 정의로도 작은 문제들은 풀렸다. 그러나 트레일 2의 시뮬레이션 Ⅰ, Ⅱ 구간을 풀고 나서야 그 정의가 좁았다는 사실이 보였다. 시뮬레이션은 &quot;문제를 따라 구현하는 유형&quot;이 아니라, &lt;b&gt;&quot;시간의 흐름을 손실 없이 옮겨 적는 사고&quot;&lt;/b&gt; 였다. 한 번에 결과로 점프하려는 직관을 경계하지 않으면, 어떤 자료구조를 골라도 같은 자리에서 실수한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 한 회의 실수가 아니라, 시뮬레이션이라는 유형 자체에 대한 사고 습관의 구멍이었다. 6회차 미션이 &quot;나만의 방식으로 알고리즘 개념을 설명하기&quot;였기에, 이 글은 그 구멍을 메우기 위해 코드트리 트레일 2의 시뮬레이션 Ⅰ, Ⅱ를 끝까지 풀고 나서야 비로소 잡힌 하나의 골격 &lt;b&gt;시간에 따른 시뮬레이션&lt;/b&gt; 을 정리한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&quot;시뮬레이션&quot;이라는 이름이 가린 진짜 문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시뮬레이션이 어렵게 느껴지는 이유는 알고리즘이 까다로워서가 아니다. 자료구조도 단순하고, 시간복잡도도 대체로 여유롭다. 그런데도 매번 무너졌던 이유를 한 달 동안 트레일 2의 시뮬레이션 Ⅰ, Ⅱ 약 44문제를 풀고 나서야 알았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 &lt;b&gt;&quot;한 번에 결과로 점프하려는 직관&quot;&lt;/b&gt; 이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;A가 10초 동안 총 10미터를 갔다, B가 10초 동안 -3미터에 있다, 그러면 둘은 만나지 않는다.&quot; 머리로는 이렇게 한 번에 계산하는 게 빠르다. 그러나 시뮬레이션 문제는 종종 그 10초 사이의 3초나 5초 시점에서 둘이 스쳤는지를 묻는다. 도착지만 비교하는 코드는 중간 경로 전체를 통째로 잃어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 자리에서 깨달은 건 하나였다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시뮬레이션은 결과를 빠르게 계산하는 문제가 아니다. &lt;b&gt;시간의 흐름을 손실 없이 그대로 옮겨 적는&lt;/b&gt; 문제다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 인식이 트레일 2의 모든 시뮬레이션 문제를 푸는 공통 골격이 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패턴: 매 1초마다 상태를 한 줄씩 기록하는 골격&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손에 익은 골격을 한 줄로 압축하면 이렇다.&lt;/p&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;상태(state) = 시뮬레이션이 추적해야 하는 모든 정보
시간(time)  = 1초 (혹은 1 step) 단위로만 전진
기록(log)   = 매 시간마다 상태를 그대로 남겨둔다&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로 옮기면 항상 다음 두 종류 중 하나가 된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 형태 A: 배열에 매 초의 상태를 적어 둔다 (사후 비교용)
int p[MAX_TIME + 1];
int t = 1;
for (각 명령) {
    for (명령의 소요시간만큼) {
        p[t] = p[t - 1] + delta;   // 1초만큼 상태 갱신
        t++;
    }
}

// 형태 B: 매 초 상태를 갱신하되, 그 자리에서 종료 조건만 확인한다
state s = initial;
for (int t = 1; t &amp;lt;= T; ++t) {
    s = step(s);                   // 1초만큼 상태 전진
    if (조건(s)) { /* 처리 */ }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A는 &lt;b&gt;나중에 다시 봐야 하는 시점이 생기는 문제&lt;/b&gt;에 쓰고, B는 &lt;b&gt;결정이 그 시각에 즉시 끝나는 문제&lt;/b&gt;에 쓴다. 트레일 2의 시뮬레이션 Ⅰ&amp;middot;Ⅱ는 거의 전부 이 두 형태로 환원된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태 A로 푼 결과는 항상 시간 인덱스를 행으로 갖는 표 한 장으로 정리된다. 예를 들어 A가 R 방향으로 3초, L 방향으로 2초 움직이고, B가 L 방향으로 2초, R 방향으로 3초 움직이는 경우 두 객체의 위치 배열은 다음과 같이 채워진다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시각 t&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;th&gt;5&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;p1 (A 위치)&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;td&gt;+2&lt;/td&gt;
&lt;td&gt;+3&lt;/td&gt;
&lt;td&gt;+2&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p2 (B 위치)&lt;/td&gt;
&lt;td&gt;-1&lt;/td&gt;
&lt;td&gt;-2&lt;/td&gt;
&lt;td&gt;-1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p1[t] == p2[t]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✗&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매 시각의 위치를 한 줄씩 적어 두면, &quot;두 객체가 같은 좌표에 놓이는 최초 시각&quot;이라는 질문은 마지막 행을 왼쪽에서 오른쪽으로 훑는 한 줄로 끝난다. 한 번에 결과로 점프하던 사고가, 표를 옮겨 적는 사고로 바뀌는 지점이다. 이제 그 환원을 네 문제로 직접 따라가 본다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;적용 1 &amp;mdash; 만나는 그 순간: 두 시간선을 나란히 적어 비교한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[만나는 그 순간]의 핵심은 &lt;b&gt;두 객체가 최초로 같은 좌표에 있는 시각&lt;/b&gt;이다. 결과로 한 번에 점프하면 중간이 사라진다. 그래서 A와 B의 위치를 매 1초 단위로 따로 적은 뒤, 같은 시각 인덱스끼리 비교해야 한다. 이게 형태 A다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int p1[1000001], p2[1000001];

// 1. A의 1초당 위치 기록
int idx = 1;
for (int i = 0; i &amp;lt; n; ++i) {
    for (int time = 0; time &amp;lt; t[i]; ++time) {
        p1[idx] = p1[idx - 1] + (d[i] == 'L' ? -1 : 1);
        idx++;
    }
}
int total_time = idx - 1;

// 2. B의 1초당 위치 기록 (동일 방식)
idx = 1;
for (int i = 0; i &amp;lt; m; ++i) {
    for (int time = 0; time &amp;lt; t2[i]; ++time) {
        p2[idx] = p2[idx - 1] + (d2[i] == 'L' ? -1 : 1);
        idx++;
    }
}

// 3. 같은 시각 인덱스끼리 비교
int result = -1;
for (int i = 1; i &amp;lt;= total_time; ++i) {
    if (p1[i] == p2[i]) { result = i; break; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 점은 두 가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, 명령어 단위가 아니라 &lt;b&gt;시간 단위&lt;/b&gt;로 인덱스를 쌓는다. 명령어 인덱스로 루프를 돌리면 A의 3번째 명령과 B의 3번째 명령은 서로 다른 시각이라서 비교가 무의미해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 시간 인덱스가 객체마다 동일한 의미를 가져야 한다. &lt;code&gt;p1[5]&lt;/code&gt;와 &lt;code&gt;p2[5]&lt;/code&gt;는 둘 다 &lt;b&gt;시뮬레이션 시작 후 5초가 흐른 순간의 위치&lt;/b&gt;여야 한다. 이 동기화가 깨지면 결과가 어긋난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 크기 설정도 같은 맥락에서 사고가 필요하다. 명령어가 1000개이고 각 명령의 시간이 최대 1000이면, 누적 시간은 최대 1,000,000초까지 늘어난다. 습관적으로 &lt;code&gt;int p[10000]&lt;/code&gt;처럼 작게 잡으면 런타임 오류가 난다. &lt;b&gt;시간 단위 배열의 크기는 명령 개수가 아니라 누적 시간의 상한&lt;/b&gt;이라는 점이 시뮬레이션의 첫 번째 함정이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFGXYE/dJMcahx54Wb/ivfN9nSVZOzP1x5Z1dHH5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFGXYE/dJMcahx54Wb/ivfN9nSVZOzP1x5Z1dHH5K/img.png&quot; data-alt=&quot;[만나는 그 순간] Accepted 통과 화면 (시간 단위 풀이로 재제출 후)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFGXYE/dJMcahx54Wb/ivfN9nSVZOzP1x5Z1dHH5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFGXYE%2FdJMcahx54Wb%2FivfN9nSVZOzP1x5Z1dHH5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;641&quot; height=&quot;103&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[만나는 그 순간] Accepted 통과 화면 (시간 단위 풀이로 재제출 후)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;적용 2 &amp;mdash; 좌우로 움직이는 로봇: &quot;만남 횟수&quot;로 질문이 바뀌면, 한 줄을 더 본다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[좌우로 움직이는 로봇]은 만나는 그 순간과 골격이 같지만, 묻는 것이 다르다. 최초 시각이 아니라 &lt;b&gt;두 로봇이 만나는 횟수&lt;/b&gt;다. 그리고 한 로봇이 멈춰도 다른 로봇이 계속 움직일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 형태 A를 쓰되, 비교 단계에서 두 가지를 추가한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int max_time = max(time_a, time_b);
int now_time = 1;
int result = 0;

while (now_time &amp;lt;= max_time) {
    int now_a = min(now_time, time_a - 1);
    int now_b = min(now_time, time_b - 1);    // 멈춘 로봇은 마지막 위치 고정
    int prev_a = min(now_time - 1, time_a - 1);
    int prev_b = min(now_time - 1, time_b - 1);

    if (pos1[now_a] == pos2[now_b]
        &amp;amp;&amp;amp; pos1[prev_a] != pos2[prev_b]) {     // 직전엔 달랐다가 지금 같아짐
        result++;
    }
    now_time++;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 새로 들어온 사고 둘.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, &lt;b&gt;멈춤 처리&lt;/b&gt;. 명령이 끝난 객체는 마지막 위치에 그대로 머문다. 그래서 &lt;code&gt;now_a&lt;/code&gt;를 &lt;code&gt;time_a - 1&lt;/code&gt;로 클램프한다. 형태 A의 장점이 여기서 드러난다 &amp;mdash; 매 초 상태를 다 적어뒀기 때문에, 멈춘 객체도 마지막 인덱스를 그냥 다시 읽으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, &lt;b&gt;만남의 정의를 시간 두 줄로 확장&lt;/b&gt;. &quot;지금 같다&quot;만으로는 같은 칸에 계속 머무는 동안 매 초 카운트가 누적된다. &quot;직전엔 달랐고 지금은 같다&quot;로 두 줄을 비교해야 만남이 한 번으로 카운트된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만나는 그 순간과 골격은 같은데 묻는 질문 하나가 바뀌었을 뿐인데, 비교 단계에 두 줄이 늘었다. 시뮬레이션 문제의 변형은 대부분 이런 식이다. &lt;b&gt;상태 기록부는 같고, 질문에 맞게 해석부만 갈린다&lt;/b&gt;.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;적용 3 &amp;mdash; 작은 구슬의 이동: 상태가 (y, x)가 되어도 골격은 그대로다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[작은 구슬의 이동]은 격자 위에서 한 칸씩 움직이다가 벽에 부딪히면 반대 방향으로 튕긴다. 형태 B를 쓰는 사례다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int moving[4][2] = {{1,0}, {0,1}, {0,-1}, {-1,0}};

int y = r, x = c;
for (int time = 0; time &amp;lt; t; ++time) {
    int ny = y + moving[dir][0];
    int nx = x + moving[dir][1];
    if (inRange(ny, nx)) { y = ny; x = nx; }
    else                  { dir = 3 - dir; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태는 이제 1차원 정수가 아니라 &lt;code&gt;(y, x, dir)&lt;/code&gt; 셋이다. 그러나 시간은 여전히 1초씩 전진하고, 매 시각마다 상태가 한 번씩만 갱신된다. 골격은 정확히 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 따로 정리해 둘 만한 디테일이 &lt;code&gt;dir = 3 - dir&lt;/code&gt; 한 줄이다. 방향 배열을 &lt;code&gt;{D, R, L, U}&lt;/code&gt; 순으로 잡으면 인덱스 0과 3이 서로 반대, 1과 2가 서로 반대다. 그래서 &lt;code&gt;3 - dir&lt;/code&gt;이 곧 반대 방향이 된다. 매번 &lt;code&gt;if-else&lt;/code&gt;로 방향을 뒤집을 필요가 없다. &lt;b&gt;방향 배열을 어떻게 배치하느냐가 반사 로직의 코드 길이를 결정한다&lt;/b&gt; &amp;mdash; 이건 트레일 2를 풀면서 가장 늦게 손에 익은 사고였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;적용 4 &amp;mdash; 거울에 레이저 쏘기 2: 형태 A와 B를 한 풀이 안에 묶고, 풀기 전 8케이스를 종이에 적어 두었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[거울에 레이저 쏘기 2]는 트레일 2 시뮬레이션 Ⅱ의 &quot;어려움&quot; 난이도 문제다. n&amp;times;n 격자 외곽 임의 지점에서 k번째 진입 방향으로 레이저를 쏘면, 격자 안의 &lt;code&gt;/``\&lt;/code&gt; 거울에 부딪힐 때마다 방향이 바뀐다. 레이저가 격자를 빠져나갈 때까지 이동한 칸 수를 구해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 풀이 자체에 앞서 종이를 먼저 꺼냈다. 거울 두 종류와 진입 방향 네 가지의 조합(총 8개 케이스) 가 회전 방향에 어떻게 매핑되는지를 표로 먼저 정리한 뒤에 코드로 옮겼다. 종이 위의 표가 정리되기 전엔 코드를 한 줄도 쓰지 못했다. 도입에서 [만나는 그 순간]을 네 번 틀린 뒤에야 연필을 잡았다고 적었는데, 골격이 손에 붙고 나니 어려운 시뮬레이션 문제는 처음부터 종이를 먼저 꺼내는 순서로 바뀌었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1798&quot; data-origin-height=&quot;1562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwztEw/dJMcagy9PVi/ldZDfFKrwcKOIPQrGmD12K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwztEw/dJMcagy9PVi/ldZDfFKrwcKOIPQrGmD12K/img.png&quot; data-alt=&quot;거울 두 종류( / ,&amp;amp;nbsp; \ ) &amp;amp;times; 진입 방향 4가지 = 8케이스 회전 매핑을 종이에 정리한 표&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwztEw/dJMcagy9PVi/ldZDfFKrwcKOIPQrGmD12K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwztEw%2FdJMcagy9PVi%2FldZDfFKrwcKOIPQrGmD12K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;631&quot; height=&quot;548&quot; data-origin-width=&quot;1798&quot; data-origin-height=&quot;1562&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;거울 두 종류( / ,&amp;nbsp; \ ) &amp;times; 진입 방향 4가지 = 8케이스 회전 매핑을 종이에 정리한 표&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;골격의 관점에서 이 문제가 흥미로운 이유는, &lt;b&gt;형태 A와 B를 한 풀이 안에서 순서대로 사용해야 한다는 점&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int dirs[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};  // 우&amp;middot;하&amp;middot;좌&amp;middot;상 (시계방향)

// 1단계 (형태 A): 외곽 4n 지점의 좌표와 진입 방향을 미리 다 기록해 둔다
int coord[4 * n][2] = {0};
int entry[4 * n] = {0};
int y = 0, x = 0, dir = 0;
coord[0][0] = y; coord[0][1] = x;
for (int i = 2; i &amp;lt;= 4 * n; ++i) {
    int ny = y + dirs[dir][0];
    int nx = x + dirs[dir][1];
    if (ny &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;lt; n &amp;amp;&amp;amp; nx &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; n) { y = ny; x = nx; }
    else { dir = (dir + 1) % 4; }
    coord[i - 1][0] = y;
    coord[i - 1][1] = x;
    entry[i - 1] = (dir + 1) % 4;   // 진입 방향은 격자 안쪽 90도 회전
}

// 2단계 (형태 B): k번째 진입 지점부터 1칸씩 진행하며 거울 반사 처리
int now_y = coord[k - 1][0];
int now_x = coord[k - 1][1];
int now_dir = entry[k - 1];
int count = 0;
while (now_y &amp;gt;= 0 &amp;amp;&amp;amp; now_y &amp;lt; n &amp;amp;&amp;amp; now_x &amp;gt;= 0 &amp;amp;&amp;amp; now_x &amp;lt; n) {
    if (grid[now_y][now_x] == '/') {
        // 좌&amp;middot;우 진입(0, 2)이면 좌회전, 상&amp;middot;하 진입(1, 3)이면 우회전
        now_dir = (now_dir == 0 || now_dir == 2) ? (now_dir + 3) % 4
                                                  : (now_dir + 1) % 4;
    } else {
        // '\' 거울은 반대 규칙
        now_dir = (now_dir == 0 || now_dir == 2) ? (now_dir + 1) % 4
                                                  : (now_dir + 3) % 4;
    }
    now_y += dirs[now_dir][0];
    now_x += dirs[now_dir][1];
    count++;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1단계에서 외곽 진입 지점을 형태 A로 미리 다 기록해 두는 이유는, k라는 입력이 &quot;k번째 외곽 칸&quot;을 뜻하기 때문이다. 매번 외곽을 다시 도는 대신 한 번 기록해 두면 &lt;code&gt;coord[k - 1]&lt;/code&gt;로 O(1)에 진입 지점을 꺼낼 수 있다. 형태 A의 본래 용도 &amp;mdash; 나중에 다시 봐야 하는 시점이 생기는 문제 &amp;mdash; 와 정확히 일치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2단계는 형태 B다. 진입 지점에서 1칸씩 전진하면서 거울을 만날 때마다 방향만 바꾼다. 종료 조건은 좌표가 격자 바깥으로 나가는 시점.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 풀이의 핵심 디테일은 회전 표현에 있다. 좌회전을 &lt;code&gt;(dir - 1 + 4) % 4&lt;/code&gt; 대신 &lt;b&gt;&lt;code&gt;(dir + 3) % 4&lt;/code&gt;&lt;/b&gt; 로 쓰면 4를 따로 더해 음수 모듈로를 피할 필요가 없다. C++에서 &lt;code&gt;(-1) % 4&lt;/code&gt;는 &lt;code&gt;3&lt;/code&gt;이 아니라 &lt;code&gt;-1&lt;/code&gt;이라, 좌회전을 일반적인 방식으로 쓰면 인덱스가 음수로 튀어 디버깅이 어렵다. &lt;b&gt;방향 배열을 시계방향으로 배치한 뒤 좌회전을 &lt;code&gt;(dir + 3) % 4&lt;/code&gt;로 표현하는 한 줄&lt;/b&gt;이, 8케이스 표를 코드로 옮기는 과정 전체에서 가장 짧고 안전한 길이었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;네 문제를 관통하는 한 줄&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;1496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYeme2/dJMcagTuGQp/p1MlqdgcXp46PwEE5Z7mSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYeme2/dJMcagTuGQp/p1MlqdgcXp46PwEE5Z7mSk/img.png&quot; data-alt=&quot;코드트리 트레일 2 시뮬레이션 Ⅰ, Ⅱ 진행도 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYeme2/dJMcagTuGQp/p1MlqdgcXp46PwEE5Z7mSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYeme2%2FdJMcagTuGQp%2Fp1MlqdgcXp46PwEE5Z7mSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;705&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;1496&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 트레일 2 시뮬레이션 Ⅰ, Ⅱ 진행도 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 문제는 표면적으로 모두 다르다. 두 객체 만남, 만남 횟수, 격자 반사, 명령어 처리. 그러나 풀이의 골격은 동일하다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;문제&lt;/th&gt;
&lt;th&gt;시간 단위&lt;/th&gt;
&lt;th&gt;상태&lt;/th&gt;
&lt;th&gt;기록 방식&lt;/th&gt;
&lt;th&gt;종료 조건&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;만나는 그 순간&lt;/td&gt;
&lt;td&gt;1초&lt;/td&gt;
&lt;td&gt;위치 (정수)&lt;/td&gt;
&lt;td&gt;두 객체 배열 (형태 A)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;p1[i] == p2[i]&lt;/code&gt; 최초 시각&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;좌우 로봇&lt;/td&gt;
&lt;td&gt;1초&lt;/td&gt;
&lt;td&gt;위치 (정수)&lt;/td&gt;
&lt;td&gt;두 객체 배열 (형태 A)&lt;/td&gt;
&lt;td&gt;만남 횟수 누적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;작은 구슬 이동&lt;/td&gt;
&lt;td&gt;1초&lt;/td&gt;
&lt;td&gt;(y, x, dir)&lt;/td&gt;
&lt;td&gt;매 초 in-place (형태 B)&lt;/td&gt;
&lt;td&gt;T초 후 위치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;거울에 레이저 쏘기 2&lt;/td&gt;
&lt;td&gt;외곽 칸 / 1칸&lt;/td&gt;
&lt;td&gt;(y, x, dir)&lt;/td&gt;
&lt;td&gt;외곽 4n 배열 (A) + 진행 in-place (B)&lt;/td&gt;
&lt;td&gt;격자 밖 이탈 시각&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 골격은 이렇다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. 상태가 무엇인지 명확히 정의한다 (정수? 좌표? 방향까지?)
2. 시간을 1단위로만 전진시킨다 (한 번에 점프 금지)
3. 매 시각마다 상태를 갱신하거나, 배열에 적어 둔다
4. 종료 조건은 질문에 맞춰 비교부에만 작성한다&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그동안 시뮬레이션 문제를 풀 때마다 &quot;이 문제는 어떻게 접근하지?&quot;부터 시작했다. 그래서 매번 처음 보는 문제처럼 느껴졌다. 트레일 2의 시뮬레이션 Ⅰ&amp;middot;Ⅱ를 처음부터 끝까지 풀고 나서야 보였다 &amp;mdash; &lt;b&gt;시뮬레이션 문제는 골격이 같고, 매번 바뀌는 것은 상태의 정의와 종료 조건뿐&lt;/b&gt;이다. 한 번에 점프하지 않고 매 시각을 1단위로만 적어 내려가는 사고가 손에 붙으면, 문제별 변형은 비교부의 한두 줄로 끝난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 사실이 5월의 1차 갭체크에서 노란불이 켜졌던 시뮬레이션 Ⅰ과, 그 위의 시뮬레이션 Ⅱ를 한 달간 갈아 풀어내고 나서야 비로소 한 문장으로 잡힌 것이다. 6월의 2차 갭체크에서 시뮬레이션 Ⅰ이 약점 목록에서 빠진 것은 정답률이 올라서가 아니라 이 골격이 손에 붙어서였다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;옛 SWEA 1954 main.cpp가 보여준 같은 손버릇&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달간 트레일 2를 풀고 나서 도입에서 언급한 &lt;code&gt;SW Expert Academy/1954/main.cpp&lt;/code&gt;를 다시 열어봤다. 달팽이 숫자를 본인 코드로 다시 풀어 둔 그 파일이다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;int rotate(int num) {
  num = num + 1;
  if (num == 4) return 0;
  return num;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛 main.cpp는 방향 인덱스의 순환을 위해 &lt;code&gt;rotate(num)&lt;/code&gt;이라는 별도 헬퍼 함수를 만들어 두었다. 그러나 같은 종류의 방향 회전은 트레일 2의 [작은 구슬의 이동]에서 &lt;code&gt;dir = 3 - dir&lt;/code&gt; 한 줄로 끝났고, [거울에 레이저 쏘기 2]에서는 시계방향 배열 위에 좌회전을 &lt;code&gt;(dir + 3) % 4&lt;/code&gt;, 우회전을 &lt;code&gt;(dir + 1) % 4&lt;/code&gt;로 표현해 두 회전을 한 줄씩으로 압축했다. &lt;b&gt;방향 배열의 배치를 어떻게 잡느냐에 따라 코드 한 줄이 헬퍼 함수 여러 줄을 대체한다&lt;/b&gt;는 사고가 옛 풀이에는 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛 폴더에 남은 시뮬레이션 풀이를 다시 훑어보면 비슷한 형태의 실수가 반복적으로 보인다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령어 단위로 루프를 돌렸다 (시간 단위가 아님)&lt;/li&gt;
&lt;li&gt;도착지 좌표만 계산하고 중간 경로를 비교하지 않았다&lt;/li&gt;
&lt;li&gt;배열 크기를 명령 개수 기준으로 잡아 시간 누적을 감당하지 못했다&lt;/li&gt;
&lt;li&gt;방향 배열의 배치를 활용하지 않아 회전 로직이 불필요하게 길어졌다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 사람이 같은 종류의 실수를 다른 문제에서 반복하고 있었다는 사실이 옛 폴더에 그대로 남아 있었다. 한 번에 결과로 점프하려는 손버릇이, 시뮬레이션 유형 앞에서는 매번 비슷한 자리에서 어긋났다. 이번 6회차에 들어 [만나는 그 순간]에서 네 번 틀린 것도 우연한 실수가 아니라, &lt;b&gt;직관을 경계하는 사고가 아직 손끝까지는 내려오지 않았다는 신호&lt;/b&gt;였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 시뮬레이션 문제를 만나면 먼저 연필을 잡고 매 초의 상태를 적어 내려간다. 상태를 정의하고, 시간을 1단위로 쪼개고, 매 시각의 기록을 한 줄씩 남긴다. 골격이 손에 붙고 나면, 시뮬레이션은 직관에 기대지 않고 &lt;b&gt;시간 흐름을 그대로 옮겨 적는 절차&lt;/b&gt;로 바뀐다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며 &amp;mdash; 다음 전선은 그래프와 동적 계획법이다&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2hzWX/dJMcadvASiv/2rBidE1YKLrkYhtIQwJwq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2hzWX/dJMcadvASiv/2rBidE1YKLrkYhtIQwJwq0/img.png&quot; data-alt=&quot;2차 갭체크 결과 &amp;amp;mdash; 시뮬레이션 Ⅰ이 약점 목록에서 빠진 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2hzWX/dJMcadvASiv/2rBidE1YKLrkYhtIQwJwq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2hzWX%2FdJMcadvASiv%2F2rBidE1YKLrkYhtIQwJwq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;409&quot; height=&quot;383&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2차 갭체크 결과 &amp;mdash; 시뮬레이션 Ⅰ이 약점 목록에서 빠진 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5회차 글에서 시뮬레이션 Ⅰ과 완전탐색이 갭체크 약점 목록에서 빠졌다고 적었다. 대신 DP Ⅰ과 BFS가 새 빨간불로 들어왔다. 이번 6회차에 시뮬레이션을 하나의 골격으로 정리하면서 깨달은 것은, &lt;b&gt;유형별 직관을 한 줄짜리 골격으로 압축할 수 있을 때 비로소 그 유형이 손에 붙는다&lt;/b&gt;는 점이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 회차에는 BFS를 같은 방식으로 정리해볼 생각이다. 큐와 방문 배열, 그리고 &quot;처음 방문한 시각이 최단 거리&quot;라는 골격을 한 줄로 잡고 나면, 시뮬레이션이 그랬듯 변형 문제들이 비교부의 한두 줄로 정리될 거라고 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시뮬레이션 문제 앞에서 매번 같은 자리에서 어긋나는 사람, 직관으로 한 번에 풀고 싶어지는 손버릇이 잡히지 않는 사람에게 이 골격이 짧은 지름길이 됐으면 한다. 트레일 2의 시뮬레이션 Ⅰ, Ⅱ를 전부 풀면서 손에 잡힌 한 줄짜리 골격이라, 같은 유형을 마주칠 때마다 처음부터 다시 설계하는 부담을 한 단계 줄여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서 다룬 네 문제는 모두 트레일 2에서 직접 풀어보고 &lt;a href=&quot;https://github.com/CHOOSLA/Algorithm&quot;&gt;CHOOSLA/Algorithm&lt;/a&gt; &lt;code&gt;Codetree/trail2/&lt;/code&gt;에 올려둔 풀이다. 시간 단위 시뮬레이션의 골격을 직접 손으로 확인해보고 싶다면 아래에서 시작할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리 트레일 2 시뮬레이션 바로가기: &lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;https://www.codetree.ai/ko/trail-info&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781956702924&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩 테스트 학습 안내 | 코드트리&quot; data-og-description=&quot;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dFrDEf/dJMb8SpRvkx/U9neUemxpk0eFx8QcdBBOk/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dFrDEf/dJMb8SpRvkx/U9neUemxpk0eFx8QcdBBOk/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩 테스트 학습 안내 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>시뮬레이션</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <category>코테공부</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/29</guid>
      <comments>https://choosla.tistory.com/29#entry29comment</comments>
      <pubDate>Mon, 15 Jun 2026 23:18:51 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리 갭체크 후기] 한 달 전 '불안정'이던 완전탐색, 다시 응시해봤다</title>
      <link>https://choosla.tistory.com/28</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;이전 글&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/24&quot;&gt;https://choosla.tistory.com/24&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1780954405873&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&quot; data-og-description=&quot;기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는지 막막한 고민이 앞섰다. 이건 비단 나뿐만 아니라 다른 개발자들도 똑같은 고민을 가&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/24&quot; data-og-url=&quot;https://choosla.tistory.com/24&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bFDQgx/dJMb9iIOPoX/UyJrC815lqmerqKPJdE5hk/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/Vvpmp/dJMb82eUX0W/mB5lAlTD43WxFkvB047t11/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/df1ZLU/dJMb9g5iWVq/TPVqX2bDjKEPD8Y2CXiOsK/img.png?width=1868&amp;amp;height=1440&amp;amp;face=0_0_1868_1440&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/24&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/24&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bFDQgx/dJMb9iIOPoX/UyJrC815lqmerqKPJdE5hk/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/Vvpmp/dJMb82eUX0W/mB5lAlTD43WxFkvB047t11/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/df1ZLU/dJMb9g5iWVq/TPVqX2bDjKEPD8Y2CXiOsK/img.png?width=1868&amp;amp;height=1440&amp;amp;face=0_0_1868_1440');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는지 막막한 고민이 앞섰다. 이건 비단 나뿐만 아니라 다른 개발자들도 똑같은 고민을 가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;한 달 전, 갭체크가 빨간색으로 알려준 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준이 사라진 뒤 알고리즘을 어디서 풀어야 할지 막막하던 차에 코드트리로 자리를 옮겼고, 가장 먼저 한 일이 갭체크였다. 10분 남짓한 진단이 끝나자 그래프가 내 수준을 유형별로 갈라서 보여줬다. 그때 '불안정'(노랑)으로 잡힌 게 &lt;b&gt;완전탐색 Ⅱ&lt;/b&gt;와 &lt;b&gt;시뮬레이션 Ⅰ&lt;/b&gt;, 아예 '부족'(빨강)으로 뜬 게 &lt;b&gt;완전탐색 Ⅲ&lt;/b&gt;와 &lt;b&gt;백트래킹&lt;/b&gt;이었다. 백트래킹은 그래도 많이 풀어봤다고 자신했는데, 막상 진단에서는 15분을 붙들고 두 번을 시도하고도 끝내 못 풀었다. 시뮬레이션 한 문제는 네 번을 틀린 끝에 18분 만에 겨우 통과했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;1042&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bM3LeC/dJMcaiDB58y/rsnEdy4wpsW6mzIlKm73F0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bM3LeC/dJMcaiDB58y/rsnEdy4wpsW6mzIlKm73F0/img.png&quot; data-alt=&quot;한 달 전 1차 갭체크 결과 그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bM3LeC/dJMcaiDB58y/rsnEdy4wpsW6mzIlKm73F0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbM3LeC%2FdJMcaiDB58y%2FrsnEdy4wpsW6mzIlKm73F0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;787&quot; height=&quot;880&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;1042&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한 달 전 1차 갭체크 결과 그래프&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 세운 목표는 단순했다. 빨간 영역을 하나씩 메워서 여러 기업의 코딩테스트를 감당할 수 있는 상태까지 끌어올리는 것. 한 달이 지났다. 목표를 향해 잘 가고 있는지 확인할 방법은 결국 같은 진단을 다시 받아보는 것뿐이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;약점을 좁히려고 한 달간 한 일&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 동안 한 일을 돌아보면, 기능을 구경한 게 아니라 그 빨간 두 영역을 좁히는 데 쓴 시간이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;완전탐색과 시뮬레이션부터 다시 밟았다.&lt;/b&gt; 갭체크가 불안정으로 짚은 시뮬레이션 Ⅰ과 완전탐색을 코드트레일로 열어, 기본 문제 &amp;rarr; 연습 문제 &amp;rarr; 테스트 문제 순으로 다시 올라갔다. 무작정 많이 푸는 방식이 아니라, 개념을 본 뒤 변형 문제에 적용하고 마지막에 힌트 없이 풀어내는 3단계라 접근법 자체가 손에 남았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;매일 앉는 환경부터 만들었다.&lt;/b&gt; 알림톡을 켜서 까먹은 날 저녁에 다시 접속하게 만들었고, 깃허브 자동 연동으로 정답을 받으면 잔디가 알아서 심겼다. 의지로 버티는 대신 환경이 대신 찔러주게 한 셈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;132&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GFasg/dJMcajbl4To/xKBoA8KYoZDDbKqWhM2Op1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GFasg/dJMcajbl4To/xKBoA8KYoZDDbKqWhM2Op1/img.png&quot; data-alt=&quot;깃허브 잔디 한 달치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GFasg/dJMcajbl4To/xKBoA8KYoZDDbKqWhM2Op1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGFasg%2FdJMcajbl4To%2FxKBoA8KYoZDDbKqWhM2Op1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;251&quot; height=&quot;240&quot; data-origin-width=&quot;132&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깃허브 잔디 한 달치&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;틀린 문제를 모아두기 시작했다.&lt;/b&gt; 4회차에 만든 북마크 오답노트가 컸다. '한번에 못 풀었던 문제'와 '해설이 내 풀이보다 나았던 문제' 두 폴더로 나눠, 찜찜한 문제는 그 자리에서 담아뒀다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 한 달 내내 매끄럽기만 했던 건 아니다. 2주차에 해설을 보고 &quot;변환 로직을 함수로 빼는 모듈화 습관을 들이자&quot;고 적어놓고, 3주차 진수 변환 문제에서는 또 &lt;code&gt;main()&lt;/code&gt;에 전부 때려넣었다. 같은 다짐을 같은 자리에서 반복한 기록이 블로그에 그대로 남아 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다시 응시한 갭체크, 비포와 애프터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달간의 학습이 진단 결과를 실제로 움직였는지 보려고, 5월 10일 이후 한 달 만에 갭체크를 다시 응시했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;984&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BApK7/dJMcahSb863/OtSkEkzjgtHRqFcKGLGMC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BApK7/dJMcahSb863/OtSkEkzjgtHRqFcKGLGMC0/img.png&quot; data-alt=&quot;2차 갭체크 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BApK7/dJMcahSb863/OtSkEkzjgtHRqFcKGLGMC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBApK7%2FdJMcahSb863%2FOtSkEkzjgtHRqFcKGLGMC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;793&quot; height=&quot;846&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;984&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2차 갭체크 결과&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QMZy7/dJMcahSb87v/YUbKUBk6PLeQN322Gyt0b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QMZy7/dJMcahSb87v/YUbKUBk6PLeQN322Gyt0b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QMZy7/dJMcahSb87v/YUbKUBk6PLeQN322Gyt0b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQMZy7%2FdJMcahSb87v%2FYUbKUBk6PLeQN322Gyt0b1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;354&quot; height=&quot;670&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OEkd0/dJMcaiKkofe/OVFn6wIwVvrbWuHS1ayrok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OEkd0/dJMcaiKkofe/OVFn6wIwVvrbWuHS1ayrok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OEkd0/dJMcaiKkofe/OVFn6wIwVvrbWuHS1ayrok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOEkd0%2FdJMcaiKkofe%2FOVFn6wIwVvrbWuHS1ayrok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;299&quot; height=&quot;291&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1차(5/10) &amp;middot; 2차(6/9) 핵심 요약 비교&lt;/span&gt;&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table style=&quot;height: 129px;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;유형&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;1차 (5/10)&lt;/th&gt;
&lt;th style=&quot;height: 24px;&quot;&gt;2차 (6/9)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;시뮬레이션 Ⅰ&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;불안정(노랑)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;약점 목록에서 빠짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;완전탐색 Ⅱ&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;불안정(노랑)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;약점 목록에서 빠짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;완전탐색 Ⅲ&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;부족(빨강)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;2분 45초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;백트래킹&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;부족(빨강) &amp;middot; 끝내 못 풂&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;한 번에 해결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;DP Ⅰ / BFS&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&amp;mdash;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;새로 '부족'(빨강)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 전 빨갛고 노랗던 네 유형(시뮬레이션 Ⅰ, 완전탐색 Ⅱ&amp;middot;Ⅲ, 백트래킹)이 이번 진단의 약점 목록에서 전부 빠졌다. 트레일에서도 '부족'으로 찍힌 빨강 구간이 눈에 띄게 줄었고, 앞쪽 기초 구간은 한 달 전엔 없던 '완벽하게 이해한 범위'로 넘어가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 새 빨간불이 켜졌다. &lt;b&gt;DP Ⅰ과 BFS.&lt;/b&gt; 둘 다 이번엔 손도 못 대고 건너뛴 문제다. 약점이 사라진 게 아니라 전선이 한 칸 위로 올라갔다는 뜻이다. 시뮬레이션과 완전탐색을 붙들고 있던 한 달이 끝나니, 그 너머의 그래프 탐색과 동적 계획법이 다음 벽으로 모습을 드러냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;한 달 전 못 풀던 문제가, 이번엔 풀렸다&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교표의 숫자보다 더 실감 났던 건 백트래킹 한 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/606yt/dJMcajicuQl/bLCmb2IK0TgUl3ShmPSAZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/606yt/dJMcajicuQl/bLCmb2IK0TgUl3ShmPSAZ1/img.png&quot; data-alt=&quot;저번 갭체크&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/606yt/dJMcajicuQl/bLCmb2IK0TgUl3ShmPSAZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F606yt%2FdJMcajicuQl%2FbLCmb2IK0TgUl3ShmPSAZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;762&quot; height=&quot;55&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저번 갭체크&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmvsj3/dJMcadCce9c/dZ8ITtGlj1JEjTJXgpG3S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmvsj3/dJMcadCce9c/dZ8ITtGlj1JEjTJXgpG3S1/img.png&quot; data-alt=&quot;이번에 본 갭체크&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmvsj3/dJMcadCce9c/dZ8ITtGlj1JEjTJXgpG3S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmvsj3%2FdJMcadCce9c%2FdZ8ITtGlj1JEjTJXgpG3S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;63&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이번에 본 갭체크&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 전 1차 갭체크 때, 백트래킹 유형 앞에서 15분을 붙들고 두 번을 시도하다 결국 빈칸으로 넘겼다. 그땐 '부족'이라는 빨간 딱지가 당연하게 느껴졌다. 그 백트래킹이 이번 2차 갭체크에 다시 나왔다. 같은 유형인 걸 알아챈 순간 한 달 전의 막막함부터 떠올랐는데, 이번엔 손이 먼저 움직였고 한 번에 통과가 떴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점수판의 색이 '부족'에서 빠진 것보다, '한 달 전엔 손도 못 댔는데 지금은 풀고 있다'는 그 감각이 더 분명한 신호였다. 약점이 강점으로 바뀐다는 게 이런 거구나 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;갭체크에 한 가지 바라는 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갭체크는 이번 회차에 도달한 유형별 난이도는 잘 보여주지만, &lt;b&gt;1차와 2차 결과를 한 화면에 겹쳐서 &quot;어디가 얼마나 올랐는지&quot; 추이로 보여주는 기능&lt;/b&gt;은 없다. 지금은 두 결과를 각각 캡처해 눈으로 대조해야 한다. 성장 그래프를 겹쳐 그려주거나, 직전 응시 대비 변화를 화살표로 표시해주면 '중간점검'이라는 이름에 더 맞는 도구가 될 것 같다. 한 달을 버틴 사람에게 가장 보고 싶은 건 결국 &quot;그래서 내가 올랐나&quot;이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;최종 목표와 다짐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달 전 갭체크의 빨간 영역을 좁히는 게 목표였다면, 최종 목표는 그보다 멀리 있다. &lt;b&gt;삼성을 비롯한 대기업 코딩테스트를 막힘 없이 통과하는 것.&lt;/b&gt; 이번 갭체크는 그 길에서 내가 어디까지 왔는지를 정확히 짚어줬다. 완전탐색과 시뮬레이션은 일단 빨간색에서 빠졌고, 대신 &lt;b&gt;DP Ⅰ과 BFS&lt;/b&gt;라는 다음 관문이 새로 빨갛게 떴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법은 이미 한 달이 증명했다. 갭체크로 약점을 진단하고, 코드트레일로 메우고, 북마크로 틀린 자리를 다시 밟는다. 똑같은 사이클을 이번엔 그래프 탐색과 동적 계획법에 걸어볼 차례다. 다음 중간점검에서는 지금 손도 못 대고 건너뛴 DP Ⅰ과 BFS 자리에 초록색이 들어와 있는 것, 그게 다음 목표다. 한 달마다 빨간 칸이 초록으로 바뀌는 것으로 뿌듯함 더해져갈 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리에서 직접 갭체크로 현재 위치를 확인해보고 싶다면 아래에서 시작할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;https://www.codetree.ai/ko/trail-info&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1780956087015&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩 테스트 학습 안내 | 코드트리&quot; data-og-description=&quot;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bGG813/dJMb88e8GYk/KMzJJOwxqeEkGkIV49s6b1/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bGG813/dJMb88e8GYk/KMzJJOwxqeEkGkIV49s6b1/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩 테스트 학습 안내 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>개발자취업</category>
      <category>갭체크</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <category>코딩테스트준비</category>
      <category>코테공부</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/28</guid>
      <comments>https://choosla.tistory.com/28#entry28comment</comments>
      <pubDate>Mon, 8 Jun 2026 23:32:46 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리 북마크] 맞은 문제를 다시 안 봤더니, 같은 실수를 세 번 반복하고 있었다</title>
      <link>https://choosla.tistory.com/27</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;code&gt;Re/&lt;/code&gt; 폴더와 &lt;code&gt;-review.cpp&lt;/code&gt;로 만들던 수동 오답노트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준과 프로그래머스 시절, 깃허브 레포(&lt;a href=&quot;https://github.com/CHOOSLA/Algorithm&quot;&gt;CHOOSLA/Algorithm&lt;/a&gt;)에는 복습의 흔적이 남아 있다. 분할정복 곱셈을 다시 풀어본 &lt;code&gt;Re/1629.cpp&lt;/code&gt;, 백트래킹을 두 번 짚어본 &lt;code&gt;1182-review.cpp&lt;/code&gt;와 &lt;code&gt;9663-review.cpp&lt;/code&gt;. 풀이가 흐릿한 문제는 별도 폴더와 접미사로 강제로 다시 풀게 만들어 둔 자국이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 의도는 맞았지만 오래가지 못했다. 복습 한 번을 위해 폴더를 새로 파고, 파일명을 바꾸고, 커밋 메시지를 구분해 다시 푸시하는 과정이 매번 요구되었다. 손이 많이 가는 절차는 의지력이 약해진 날을 견디지 못한다. 며칠을 미루다 보면 맞춘 문제는 그대로 지나치는 옛 습관이 다시 자리를 잡았다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;북마크로 옮겨온 뒤 사라진 번거로움&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리로 환경을 옮긴 뒤에도 한동안은 같은 패턴이 이어졌다. 정답을 받으면 다음 문제로 곧장 넘어갔다. 지난 3회차 글에서는 알림톡으로 '매일 푸는 루틴'은 만들었다고 적었는데, 정작 '틀린 문제로 돌아가는 루틴'은 없는 상태였다. 4회차 미션을 준비하면서 플랫폼 안의 '북마크' 기능을 써보기로 했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-06-01 오후 9.06.51.png&quot; data-origin-width=&quot;2783&quot; data-origin-height=&quot;1708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3Da6F/dJMcacJ78Fx/Bewqqqbp2ogTK7698kVYK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3Da6F/dJMcacJ78Fx/Bewqqqbp2ogTK7698kVYK1/img.png&quot; data-alt=&quot;코드트리 북마크 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3Da6F/dJMcacJ78Fx/Bewqqqbp2ogTK7698kVYK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3Da6F%2FdJMcacJ78Fx%2FBewqqqbp2ogTK7698kVYK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2783&quot; height=&quot;1708&quot; data-filename=&quot;스크린샷 2026-06-01 오후 9.06.51.png&quot; data-origin-width=&quot;2783&quot; data-origin-height=&quot;1708&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 북마크 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 자체는 단순하다. 문제 화면에서 버튼을 누르면 내가 지정한 폴더로 들어간다. 다만 그동안 깃허브에서 직접 구현하려 했던 '복습 보관소'가, 별도 에디터나 커밋 없이 클릭 하나로 채워진다는 점이 달랐다. 복습을 시작하기까지 거쳐야 하는 단계가 거의 사라졌다. 3회차에 채우지 못했던 루틴의 빈 칸이, 이번 회차에서 드디어 메워질 자리를 잡은 셈이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;두 개의 폴더&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 시뮬레이션 I 단계를 돌고 있는 시점이라 푼 문제의 양은 많지 않았다. 유형별로 잘게 쪼개는 대신, 지금 단계에서 의미가 있는 두 폴더만 만들었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-06-01 오후 9.27.25.png&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n2gfn/dJMcad3eXxf/nMKI19uOZxvkrpzP7x4691/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n2gfn/dJMcad3eXxf/nMKI19uOZxvkrpzP7x4691/img.png&quot; data-alt=&quot;북마크 폴더 목록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n2gfn/dJMcad3eXxf/nMKI19uOZxvkrpzP7x4691/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn2gfn%2FdJMcad3eXxf%2FnMKI19uOZxvkrpzP7x4691%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;352&quot; data-filename=&quot;스크린샷 2026-06-01 오후 9.27.25.png&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;북마크 폴더 목록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;한번에 못 풀었던 문제&lt;/b&gt;: 첫 제출에서 컴파일 에러나 오답을 받았거나, 풀이 흐름을 잡는 데 30분 이상 걸린 문제.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해설이 내 풀이보다 나았던 문제&lt;/b&gt;: 정답은 받았지만 해설의 모듈화나 네이밍이 내 코드보다 명확해 다시 짚어볼 가치가 있는 문제.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;한번에 못 풀었던 문제&lt;/code&gt; 폴더에는 현재 정확히 두 개가 들어 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;잔해물을 덮기 위한 사각형의 최소 넓이&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연속되는 수 2&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;두 문제를 한 화면에 띄워봤다&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-06-01 오후 9.30.48.png&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmd4M8/dJMcaciX3GP/A05K3IZqAWNUqddr4ajga1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmd4M8/dJMcaciX3GP/A05K3IZqAWNUqddr4ajga1/img.png&quot; data-alt=&quot;틀린 문제 복기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmd4M8/dJMcaciX3GP/A05K3IZqAWNUqddr4ajga1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmd4M8%2FdJMcaciX3GP%2FA05K3IZqAWNUqddr4ajga1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2940&quot; height=&quot;1652&quot; data-filename=&quot;스크린샷 2026-06-01 오후 9.30.48.png&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1652&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;틀린 문제 복기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책상에 앉아 폴더를 열고 두 문제를 한 화면에 띄웠다. 처음에는 그냥 다시 풀 생각이었다. 두 코드의 어긋난 지점을 따라가다 한참을 멍하니 모니터만 봤다. 같은 실수였다. 흩어진 채로는 보이지 않던 공통적인 문제가 한 화면에 모이니 또렷해졌다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;같은 자리에서 두 번 미끄러진 흔적&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;잔해물을 덮기 위한 사각형의 최소 넓이&lt;/code&gt;는 두 직사각형이 겹친 후 남은 영역을 감싸는 최소 사각형의 넓이를 구하는 문제다. 처음 풀 때는 좌표 평면의 음수 인덱스를 배열로 매핑하기 위한 &lt;code&gt;offset&lt;/code&gt; 설정과, 겹친 뒤 남은 영역의 경계를 계산하는 부분에서 막혔다. &quot;이 정도 범위면 충분하다&quot;는 어림으로 마무리하다가 1의 오차로 오답을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;연속되는 수 2&lt;/code&gt;도 결이 비슷했다. 같은 숫자가 연속해서 등장하는 최대 횟수를 카운트하는 단순 탐색이지만, 루프가 끝난 직후 마지막으로 누적된 카운트를 최댓값과 비교하지 않아 마지막 구간이 통째로 누락되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 문제를 한 폴더에 모아두지 않았다면 &quot;그냥 실수했네&quot; 정도로 흘려보냈을 가능성이 크다. 모아놓고 비교하니 결론은 분명했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;루프의 마지막 경계 처리, 인덱스 1 차이의 디테일하게 생각하지않고 직관에 기대 코드를 끝맺는 습관이 반복되고 있었다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 다시 보니 내가 가진 약점을 파악했던 순간이었다. 솔직히 조금 머쓱했다. 머릿속에서 &quot;다음에는 경계 조건부터 챙겨야지&quot; 하고 미뤄두었던 다짐이, 같은 자리에서 두 번이나 미끄러져 있었다는 걸 그제야 알아챘다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그 자리에서 다시 풀어봤다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자각한 패턴을 그대로 두기 아쉬워서 두 문제를 다시 풀어봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잔해물 사각형은 offset 경계점을 종이에 먼저 적어두고 들어갔다. 저번에는 두 번 틀리고 통과했던 문제가 이번에는 첫 제출에서 그대로 통과했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신감이 붙은 채로 연속되는 수 2를 다시 열었다. 같은 약점을 의식하고 들어갔는데도 두 번을 더 틀린 뒤에야 통과 판정을 받았다. 마지막 구간 갱신 한 줄이 또 빠져 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번에 네 번 틀렸던 부분에서 두 번으로 줄어든 결과를 가만히 들여다봤다. 머리로 안다고 손이 따라오는 것은 아니었다. 패턴을 기록하는 것과 패턴을 손에 새기는 것은 다른 작업이라는 결론이 남았다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;북마크 복습에 바라는 한 가지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능을 쓰면서 한 가지 아쉬운 점이 남았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;북마크 폴더에 모은 문제를 다시 풀 때, &lt;b&gt;이전에 작성해 틀렸거나 애매하게 맞췄던 제출 코드를 문제 화면 옆에 분할 화면이나 슬라이드로 띄워주는 UX&lt;/b&gt;가 있었으면 한다. 지금은 '제출 이력' 탭을 매번 새로 클릭하거나, 깃허브에 남아 있는 과거 버전을 따로 열어 대조해야 한다. 복습의 본질은 과거의 잘못된 사고와 현재의 개선된 사고를 같은 화면에서 마주하는 것이라, 이 단계가 한 번에 보이게 되면 오답노트로서의 가치가 한 단계 올라갈 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 글을 쓰다가 생각나는 아이디어가 있는데, 캡체크에서 우리의 풀이를 해석해주는 것 처럼 이런 공통적인 사용자의 실수를 분석해서 보여주면 코드트리가 더 완벽한 학습 사이트가 되지 않을지 상상해본다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;내가 정한 복습 루틴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수동 깃허브 관리의 번거로움에서 벗어나 플랫폼 북마크의 기능을 사용해서 두 단계로 통하는 루틴을 만들었다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;풀이 직후의 1초 분류&lt;/b&gt;&lt;br /&gt;문제를 풀고 나서 애매하게 맞췄거나 한 번이라도 막혔다면 주저 없이 북마크 폴더에 넣는다. 분류 기준을 완벽하게 다듬으려 하지 않고, 찜찜함이 남았다는 신호만으로 버튼을 누른다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주말의 오답 세션&lt;/b&gt;&lt;br /&gt;주말에는 새 진도를 나가기 전에&amp;nbsp;&lt;code&gt;한번에 못 풀었던 문제&lt;/code&gt; 폴더를 연다. 경계값 조건과 오프셋 예외 처리를 의식적으로 점검하며 처음부터 다시 작성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복습을 미뤘던 이유는 의지력의 문제가 아니었다. 복습에 도달하기 전 거쳐야 하는 절차가 너무 번거로웠을 뿐이었다. 북마크가 그 절차를 걷어낸 만큼, 이번에 세운 루틴을 그대로 유지하며 인덱스 1 차이의 실수를 하나씩 지워 나갈 계획이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;나처럼 맞춘 문제는 뒤도 안 돌아보던 사람이라면, 코드트리의 북마크 폴더 하나쯤 만들어보길 권한다!&lt;br /&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.codetree.ai/ko/trail-info&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1780318184578&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩 테스트 학습 안내 | 코드트리&quot; data-og-description=&quot;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/L4kiF/dJMb85W0pyH/E1tiTRqVbolWKRNdxHq6HK/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/L4kiF/dJMb85W0pyH/E1tiTRqVbolWKRNdxHq6HK/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩 테스트 학습 안내 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>공부습관</category>
      <category>오답노트</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <category>코테공부</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/27</guid>
      <comments>https://choosla.tistory.com/27#entry27comment</comments>
      <pubDate>Mon, 1 Jun 2026 21:50:04 +0900</pubDate>
    </item>
    <item>
      <title>[코테 독학] 바쁜 일상 속 코드트리 알림톡으로 코테 독학 루틴 지키기</title>
      <link>https://choosla.tistory.com/26</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;이전 글&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/24&quot;&gt;https://choosla.tistory.com/24&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779697154544&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&quot; data-og-description=&quot;기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는지 막막한 고민이 앞섰다. 이건 비단 나뿐만 아니라 다른 개발자들도 똑같은 고민을 가&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/24&quot; data-og-url=&quot;https://choosla.tistory.com/24&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0GGui/dJMb8Rj8i16/uskKZPubngkOt5eYFxagX1/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/ch4hEf/dJMb9kT9aLH/kmIFaAhXjQCIcPVl6UgJRK/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/OUMpP/dJMb9bv8tYM/7Iujvg5nbIDsgi8Miy1Bh1/img.png?width=2086&amp;amp;height=1350&amp;amp;face=0_0_2086_1350&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/24&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/24&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0GGui/dJMb8Rj8i16/uskKZPubngkOt5eYFxagX1/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/ch4hEf/dJMb9kT9aLH/kmIFaAhXjQCIcPVl6UgJRK/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/OUMpP/dJMb9bv8tYM/7Iujvg5nbIDsgi8Miy1Bh1/img.png?width=2086&amp;amp;height=1350&amp;amp;face=0_0_2086_1350');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는지 막막한 고민이 앞섰다. 이건 비단 나뿐만 아니라 다른 개발자들도 똑같은 고민을 가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/25&quot;&gt;https://choosla.tistory.com/25&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779697160482&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리] 완전 탐색 알고리즘 극복 학습, 갭체크 이후&quot; data-og-description=&quot;이전 글https://choosla.tistory.com/24 [코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/25&quot; data-og-url=&quot;https://choosla.tistory.com/25&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/X68xS/dJMb8XklGE8/EraV5EFwsmxLnjySwJf3q1/img.png?width=800&amp;amp;height=622&amp;amp;face=0_0_800_622,https://scrap.kakaocdn.net/dn/qmJhL/dJMb8QesqPc/BiSygAF43hS190IKHB1A5K/img.png?width=800&amp;amp;height=622&amp;amp;face=0_0_800_622,https://scrap.kakaocdn.net/dn/AIgZa/dJMb8WMvTvX/O36ZAtWX35yzu4Qs1JpG9K/img.png?width=2896&amp;amp;height=1542&amp;amp;face=0_0_2896_1542&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/25&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/25&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/X68xS/dJMb8XklGE8/EraV5EFwsmxLnjySwJf3q1/img.png?width=800&amp;amp;height=622&amp;amp;face=0_0_800_622,https://scrap.kakaocdn.net/dn/qmJhL/dJMb8QesqPc/BiSygAF43hS190IKHB1A5K/img.png?width=800&amp;amp;height=622&amp;amp;face=0_0_800_622,https://scrap.kakaocdn.net/dn/AIgZa/dJMb8WMvTvX/O36ZAtWX35yzu4Qs1JpG9K/img.png?width=2896&amp;amp;height=1542&amp;amp;face=0_0_2896_1542');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리] 완전 탐색 알고리즘 극복 학습, 갭체크 이후&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이전 글https://choosla.tistory.com/24 [코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[코드트리] 완전 탐색 알고리즘 극복 학습, 갭체크 이후&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3주차, 어려운 건 문제가 아니라 매일 앉는 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1주차에 갭체크로 나의 약점을 파악하고, 2주차에 시뮬레이션 문제를 풀어보며 코드트리의 학습 흐름에 익숙해졌다. 그런데 3주차에 들어오면서 느낀 건 의외로 단순한 거였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 자체의 난이도보다, 매일 빠짐없이 앉아서 푸는 것이 훨씬 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 며칠은 의욕 넘치게 하루에 서너 문제씩 풀다가도 바쁜 일정이 겹치면 하루 이틀 건너뛰게 되고, 그 하루가 이틀이 되고 일주일이 되어 결국 흐지부지되는 경험... 다들 한 번쯤 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 3회차 미션은 이 꾸준함을 유지하기 위한 동기부여 방식을 공유하는 것인데, 내가 가장 도움을 받고 있는 두 가지 기능을 소개하려고 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;알림톡 설정: 까먹을 수가 없는 카카오톡 리마인더&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리에는 카카오톡으로 학습 알림을 보내주는 기능이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;828&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bguSFw/dJMcajbbO4s/GXGp6wP9CehsCCxuTNUIe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bguSFw/dJMcajbbO4s/GXGp6wP9CehsCCxuTNUIe0/img.png&quot; data-alt=&quot;홈페이지 &amp;amp;gt; My &amp;amp;gt; 계정 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bguSFw/dJMcajbbO4s/GXGp6wP9CehsCCxuTNUIe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbguSFw%2FdJMcajbbO4s%2FGXGp6wP9CehsCCxuTNUIe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;319&quot; height=&quot;560&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;828&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;홈페이지 &amp;gt; My &amp;gt; 계정 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1230&quot; data-origin-height=&quot;866&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccZZkP/dJMcafGKKPi/C3wrW7SINETBXzk0lIVMd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccZZkP/dJMcafGKKPi/C3wrW7SINETBXzk0lIVMd1/img.png&quot; data-alt=&quot;핸드폰 번호 등록하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccZZkP/dJMcafGKKPi/C3wrW7SINETBXzk0lIVMd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccZZkP%2FdJMcafGKKPi%2FC3wrW7SINETBXzk0lIVMd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;451&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1230&quot; data-origin-height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;핸드폰 번호 등록하기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 방법은 간단하다. 코드트리 설정 페이지의 알림탭에서 핸드폰 번호를 등록하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ylbGy/dJMcaarUgYA/mj35KaGeGSFebRlaEjU9M0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ylbGy/dJMcaarUgYA/mj35KaGeGSFebRlaEjU9M0/img.png&quot; data-alt=&quot;코드트리 학습 리마인더 등록 알림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ylbGy/dJMcaarUgYA/mj35KaGeGSFebRlaEjU9M0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FylbGy%2FdJMcaarUgYA%2Fmj35KaGeGSFebRlaEjU9M0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;656&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1544&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 학습 리마인더 등록 알림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 카카오톡으로 오늘의 학습 상태와 스트릭 현황을 알려주는 메시지가 온다. 카카오톡은 어차피 하루에도 수십 번 들여다보는 앱이기 때문에 이 알림을 놓치기가 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 이번 주에 일이 바빠서 알고리즘 공부를 완전히 까먹고 있었던 날이 있었다. 저녁때 날아온 알림톡을 보고 &quot;아 맞다, 오늘 아직 안 풀었지&quot; 하면서 접속하게 됐다. 이게 없었으면 그날 스트릭이 깨졌을 거다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그날 풀었던 문제, '진수 to 진수'&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알림톡 덕분에 접속해서 풀었던 문제가 바로 진수 변환 레슨의 &lt;b&gt;'진수 to 진수'&lt;/b&gt; 문제였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2880&quot; data-origin-height=&quot;1526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqqrRy/dJMcacpIHr6/kGTiHzS99sqFq933JwyfS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqqrRy/dJMcacpIHr6/kGTiHzS99sqFq933JwyfS1/img.png&quot; data-alt=&quot;코드트리 문제풀이 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqqrRy/dJMcacpIHr6/kGTiHzS99sqFq933JwyfS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqqrRy%2FdJMcacpIHr6%2FkGTiHzS99sqFq933JwyfS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;968&quot; height=&quot;513&quot; data-origin-width=&quot;2880&quot; data-origin-height=&quot;1526&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 문제풀이 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A진수로 표현된 숫자를 입력받아 B진수로 변환해서 출력하는 문제인데, 풀이 흐름 자체는 간단하다. A진수를 10진수로 바꾸고, 10진수를 다시 B진수로 바꾸면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;code&gt;main()&lt;/code&gt; 함수 안에 변환 로직을 쭉 이어서 작성했다. A진수 &amp;rarr; 10진수 변환은 각 자릿수에 가중치를 곱해가며 누적하고, 10진수 &amp;rarr; B진수 변환은 나머지를 &lt;code&gt;vector&lt;/code&gt;에 담아 역순으로 출력하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀고 나서 해설을 확인해봤는데, 해설에서는 10진수 변환 부분과 B진수 변환 부분을 각각 별도 함수로 분리해서 구현하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 2주차 시뮬레이션 때도 비슷한 깨달음을 얻었었다. 그때 해설에서 '달을 일로 변환하는 로직'을 함수로 빼놓은 걸 보고 &quot;이런 모듈화 습관을 들여야겠다&quot;고 다짐했었는데, 이번에도 또 main에 다 때려넣었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 지금처럼 쉬운 문제에서는 main에 다 넣어도 돌아가긴 한다. 그런데 저번에 삼성 코딩테스트를 봐본 결과 조건 분기가 많아질수록 main이 점점 길어지면서 어디서 틀렸는지 찾기가 너무 힘들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;결국 함수를 쪼개는 건 &quot;깔끔해 보이려고&quot;가 아니라 &quot;디버깅할 때 안 죽으려고&quot;인 것 같다.&lt;/i&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;깃허브 연동: 정답 맞추면 자동으로 잔디 심기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리의 또 다른 유용한 기능은 깃허브 자동 연동이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;828&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2FLvK/dJMcahdt4EQ/rnFm95E14KO5jvLDgAP3a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2FLvK/dJMcahdt4EQ/rnFm95E14KO5jvLDgAP3a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2FLvK/dJMcahdt4EQ/rnFm95E14KO5jvLDgAP3a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2FLvK%2FdJMcahdt4EQ%2FrnFm95E14KO5jvLDgAP3a1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;345&quot; height=&quot;608&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;828&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;1132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zdkf4/dJMcafGKKUs/8FvZKkP5k8K0i6amjKDkLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zdkf4/dJMcafGKKUs/8FvZKkP5k8K0i6amjKDkLk/img.png&quot; data-alt=&quot;코드트리 깃허브 연동 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zdkf4/dJMcafGKKUs/8FvZKkP5k8K0i6amjKDkLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzdkf4%2FdJMcafGKKUs%2F8FvZKkP5k8K0i6amjKDkLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;590&quot; height=&quot;555&quot; data-origin-width=&quot;1204&quot; data-origin-height=&quot;1132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코드트리 깃허브 연동 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초에 깃허브 계정을 한 번만 연동해 두면, 문제를 풀고 정답 판정을 받는 순간 내 깃허브 저장소에 자동으로 커밋이 생성된다. 폴더 구조를 맞추거나 파일을 직접 올릴 필요가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;1188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZmiTG/dJMcafGKKVG/N3qCopa0k6Cch59qkPCOB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZmiTG/dJMcafGKKVG/N3qCopa0k6Cch59qkPCOB1/img.png&quot; data-alt=&quot;깃허브에 자동으로 커밋된 코드트리 학습기록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZmiTG/dJMcafGKKVG/N3qCopa0k6Cch59qkPCOB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZmiTG%2FdJMcafGKKVG%2FN3qCopa0k6Cch59qkPCOB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;634&quot; height=&quot;485&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;1188&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깃허브에 자동으로 커밋된 코드트리 학습기록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cy741G/dJMcaaem8Iy/7WjKQ4UWLOOOx1OAsoaaz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cy741G/dJMcaaem8Iy/7WjKQ4UWLOOOx1OAsoaaz1/img.png&quot; data-alt=&quot;깃허브 커밋 잔디&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cy741G/dJMcaaem8Iy/7WjKQ4UWLOOOx1OAsoaaz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcy741G%2FdJMcaaem8Iy%2F7WjKQ4UWLOOOx1OAsoaaz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;915&quot; height=&quot;228&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깃허브 커밋 잔디&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 풀이에만 집중하면 알아서 매일 잔디가 심어지기 때문에, 기록이 쌓이는 것을 눈으로 확인하는 재미가 있다. 솔직히 처음에는 &quot;잔디가 뭐 대수인가&quot; 싶었는데, 11일째 연속으로 초록칸이 채워진 걸 보니까 괜히 깨기 싫어진다.. 이게 은근히 &quot;오늘 하루만 더 하자&quot;의 원동력이 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기존 플랫폼과의 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 백준을 사용할 때는 깃허브 잔디를 심기 위해 '백준허브' 같은 크롬 익스텐션을 별도로 깔아야 했다. 이 익스텐션이 꽤 편리하긴 한데, 가끔 로그인 세션이 풀리거나 익스텐션 업데이트가 안 맞아서 정답 코드가 누락되는 경우가 있었다. 분명 맞췄는데 잔디가 안 심어져 있으면 은근히 짜증이 난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 백준에는 매일 문제를 풀라고 카카오톡으로 알림을 보내주는 순정 기능이 없다. 결국 알아서 챙겨야 하는데, 바쁜 날은 그냥 넘어가기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리는 이 두 가지를 플랫폼 자체에서 지원해 준다. 깃허브 연동은 서드파티 없이 안정적으로 작동하고, 알림톡은 내가 설정한 시간에 맞춰 정확히 도착한다. 별거 아닌 것 같지만 이런 사소한 편의성이 장기적으로 공부 루틴을 유지하는 데 큰 차이를 만든다고 느끼고 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;후기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3주차까지 스트릭을 유지하며 학습을 이어온 것은 순전히 의지력의 힘이 아니다. 알림톡이 매일 &quot;오늘 아직 안 풀었다&quot;고 찔러주고, 깃허브 잔디가 하루라도 빈칸이 생기면 눈에 보이기 때문에 버틸 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 꾸준한 학습의 핵심은 의지가 아니라 환경이라는 걸 체감하는 중이다. 나처럼 매번 코테 공부를 시작만 하고 작심삼일로 끝났던 사람이라면 이 두 기능을 꼭 켜두고 시작해보길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4주차에는&amp;nbsp;진수&amp;nbsp;변환&amp;nbsp;때&amp;nbsp;못&amp;nbsp;했던&amp;nbsp;함수&amp;nbsp;분리를&amp;nbsp;의식적으로&amp;nbsp;적용해볼&amp;nbsp;생각이다.&amp;nbsp;결과는&amp;nbsp;다음&amp;nbsp;후기에서!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;https://www.codetree.ai/ko/trail-info&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779702340991&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩 테스트 학습 안내 | 코드트리&quot; data-og-description=&quot;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/KBCJy/dJMb9iaXlKQ/c4ayqczd1HcalRg80sQEEk/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/KBCJy/dJMb9iaXlKQ/c4ayqczd1HcalRg80sQEEk/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩 테스트 학습 안내 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업하자!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드트리 청약 통장 챌린지 참여 안내&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot;&gt;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779702346294&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;3년 만에 돌아온, 코드트리 청약 통장 챌린지 | 코드트리&quot; data-og-description=&quot;매주 학습 납입하고 7주 만기 채우면 코드트리 8월까지 무료. 매주 추첨권을 모아 맥북&amp;middot;에어팟&amp;middot;애플워치 응모까지. 신청 인원에 따라 조기마감될 수 있어요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot; data-og-url=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/crdA3J/dJMb8WeF1AB/hJ9A8EfBwbQrfhny2WPOY0/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/bpvOXQ/dJMb8Yp1E1H/LZKshCCCBbyeweKEVWN9cK/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/crdA3J/dJMb8WeF1AB/hJ9A8EfBwbQrfhny2WPOY0/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/bpvOXQ/dJMb8Yp1E1H/LZKshCCCBbyeweKEVWN9cK/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;3년 만에 돌아온, 코드트리 청약 통장 챌린지 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;매주 학습 납입하고 7주 만기 채우면 코드트리 8월까지 무료. 매주 추첨권을 모아 맥북&amp;middot;에어팟&amp;middot;애플워치 응모까지. 신청 인원에 따라 조기마감될 수 있어요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3년 만에 돌아온, 코드트리 청약 통장 챌린지&lt;br /&gt;매주 학습 납입하고 7주 만기 채우면 코드트리 8월까지 무료. 매주 추첨권을 모아 맥북,에어팟,애플워치 응모 가능&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 지금 코드트리가 코드트리 청약 통장 챌린지를 통해서 최대 8월까지 무료로 코스를 학습할 수 있는 기회를 주고 있으니 당장 참가해 보자!&lt;/p&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>1일1코테</category>
      <category>개발자루틴</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <category>코테공부</category>
      <category>코테독학</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/26</guid>
      <comments>https://choosla.tistory.com/26#entry26comment</comments>
      <pubDate>Mon, 25 May 2026 18:46:10 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리] 완전 탐색 알고리즘 극복 학습, 갭체크 이후</title>
      <link>https://choosla.tistory.com/25</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이전 글&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/24&quot;&gt;https://choosla.tistory.com/24&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778912503594&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&quot; data-og-description=&quot;기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는지 막막한 고민이 앞섰다. 이건 비단 나뿐만 아니라 다른 개발자들도 똑같은 고민을 가&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/24&quot; data-og-url=&quot;https://choosla.tistory.com/24&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cqSGGX/dJMb88Gabd1/z40WxRgwZofLHvbj6GJzu0/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/HqrFE/dJMb82eScvq/m9k6i0gYZJF1Nb4wk6k3K1/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/bLlcjx/dJMb887d1Yx/TpXGd1dqLsLKQfekyonKhk/img.png?width=2086&amp;amp;height=1350&amp;amp;face=0_0_2086_1350&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/24&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/24&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cqSGGX/dJMb88Gabd1/z40WxRgwZofLHvbj6GJzu0/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/HqrFE/dJMb82eScvq/m9k6i0gYZJF1Nb4wk6k3K1/img.png?width=800&amp;amp;height=404&amp;amp;face=0_0_800_404,https://scrap.kakaocdn.net/dn/bLlcjx/dJMb887d1Yx/TpXGd1dqLsLKQfekyonKhk/img.png?width=2086&amp;amp;height=1350&amp;amp;face=0_0_2086_1350');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;기존 플랫폼의 한계와 새로운 발견최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는지 막막한 고민이 앞섰다. 이건 비단 나뿐만 아니라 다른 개발자들도 똑같은 고민을 가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;코드트리의 학습방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리에서는 크게 두개의 학습 방법을 통해 알고리즘 스킬을 키워주고 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;갭체크&lt;/b&gt; : 간단한 문제 풀이를 통해 평소에 내가 약한 부분을 파악, 맞춤형 문제 자료 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드트레일&lt;/b&gt; : 체계적인 커리큘럼을 기반으로한 '기본 문제 - 연습 문제 - 테스트 문제'의 3단계의 점진적 학습 제공&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 문제 : 특정 알고리즘 유형의 핵심 원리와 필수 구현 로직을 학습&lt;/li&gt;
&lt;li&gt;연습 문제 : 습득한 기본 개념을 다양한 다양한 변형 문제에 적용&lt;/li&gt;
&lt;li&gt;테스트 문제 : 앞서 배운 내용을 바탕으로 힌트나 해설 없이 문제해결&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 코드트레일의 3단계 구조는 기존 사이트에서 행하던 마냥 문제 많이 풀이를 방지해준다는 점이 인상깊다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 어려운 문제를 풀기위해서는 그 문제에 어떻게 접근하냐가 정말 중요한데 이런 접근법에 대한 학습을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;갭체크 이후&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-05-16 오후 3.14.00.png&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;1420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEm2Fe/dJMcadvcL6E/nmf7xqmXFiW7AxOMrYjeP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEm2Fe/dJMcadvcL6E/nmf7xqmXFiW7AxOMrYjeP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEm2Fe/dJMcadvcL6E/nmf7xqmXFiW7AxOMrYjeP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEm2Fe%2FdJMcadvcL6E%2Fnmf7xqmXFiW7AxOMrYjeP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1824&quot; height=&quot;1420&quot; data-filename=&quot;스크린샷 2026-05-16 오후 3.14.00.png&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;1420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번에 했던 갭체크 결로 불안정한 지식인 시뮬레이션 Ⅰ, 완전탐색 Ⅱ 을 학습해보기로 했다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해설을 보면 같은 알고리즘 개념이라도 완전탐색 Ⅰ, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;완전탐색 Ⅱ&lt;span&gt;, &lt;/span&gt;&lt;/span&gt;완전탐색 Ⅲ 같이 이렇게 세부적으로 나뉘어져 있다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 같은 개념에서도 세부적으로 난이도를 나누어 학습 단계에 디테일을 챙겼다는 게 이 사이트의 또다른 좋은 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-05-16 오후 3.56.21 1.png&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;761&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lmdm8/dJMcaiwznzm/MAzHOYo3iJyqt8lk9gTClK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lmdm8/dJMcaiwznzm/MAzHOYo3iJyqt8lk9gTClK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lmdm8/dJMcaiwznzm/MAzHOYo3iJyqt8lk9gTClK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flmdm8%2FdJMcaiwznzm%2FMAzHOYo3iJyqt8lk9gTClK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1800&quot; height=&quot;761&quot; data-filename=&quot;스크린샷 2026-05-16 오후 3.56.21 1.png&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;761&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습하기를 누르게 되면 이렇게 바로 내가 불안정했던 지식을 학습할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 코드 트레일을 통해서 학습을 하게 되면 Chapter 1부터 차근차근 올라와야 되는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 학습이 됐다고 판단되는 개념에 대해서는 뛰어 넘을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'&lt;b&gt;Chapter 열기&lt;/b&gt;'를 눌러서 학습을 시작해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;코드트레일&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;1242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/04Yar/dJMcacQFNKt/axHZojMMMjhiqy9ufWEwAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/04Yar/dJMcacQFNKt/axHZojMMMjhiqy9ufWEwAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/04Yar/dJMcacQFNKt/axHZojMMMjhiqy9ufWEwAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F04Yar%2FdJMcacQFNKt%2FaxHZojMMMjhiqy9ufWEwAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;512&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;1242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 내가 공부해 볼 '시뮬레이션 Ⅰ'은 또 세부적으로 4개의 Lesson 으로 나뉘어져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것또한 코드트리의 섬세한 코스 구성을 볼 수 있다 ( 대게 이렇게 디테일하게 나뉘어 있지 않다.. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'&lt;b&gt;기본 문제 -&amp;gt; 연습 문제 -&amp;gt; 테스트 문제&lt;/b&gt;' 으로 가면서 각 시뮬레이션 분야를 마스터 해보자!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;레슨으로 공부하기&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;1180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/exERNb/dJMcaiQSlv8/oXleAmN2MoL8FWxFS9vAQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/exERNb/dJMcaiQSlv8/oXleAmN2MoL8FWxFS9vAQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/exERNb/dJMcaiQSlv8/oXleAmN2MoL8FWxFS9vAQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FexERNb%2FdJMcaiQSlv8%2FoXleAmN2MoL8FWxFS9vAQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;512&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;1180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 &lt;b&gt;연습문제(Warm Up)에서는 기본 개념을 먼저 보고 습득한 후 문제를 풀게 된다&lt;/b&gt;. 이 기본 개념은 레슨 동안 계속 확인할 수 있어서 까먹었다면 다시 보고 문제를 풀 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나하나 블로그를 통해서 찾는 시간이 줄어드니 빠르게 배울 수 있는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 탭을 눌러서 기본 개념 창작한채로 풀어보자!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2896&quot; data-origin-height=&quot;1542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0GRAK/dJMcagleDUx/dIKyAnniKQe955J3kYAmik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0GRAK/dJMcagleDUx/dIKyAnniKQe955J3kYAmik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0GRAK/dJMcagleDUx/dIKyAnniKQe955J3kYAmik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0GRAK%2FdJMcagleDUx%2FdIKyAnniKQe955J3kYAmik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2896&quot; height=&quot;1542&quot; data-origin-width=&quot;2896&quot; data-origin-height=&quot;1542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 개념을 그대로 이용한 문제로 시간 차이를 물어보는 문제인데, 시뮬레이션스럽게 풀어봤다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제가 어려울 경우, 토론과 해설&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 다 풀리는 문제 였으면 좋겠지만 어려운 문제를 때때로 정말 풀 수 없는 경우도 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때는 &lt;b&gt;코드트리에서 문제마다 토론 페이지가 있어 자신의 알고리즘을 가지고 토론&lt;/b&gt;해 볼 수 있다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;1380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSaS9a/dJMcacb5hL8/KKtAW2xkSS9sQSYqo8ose0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSaS9a/dJMcacb5hL8/KKtAW2xkSS9sQSYqo8ose0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSaS9a/dJMcacb5hL8/KKtAW2xkSS9sQSYqo8ose0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSaS9a%2FdJMcacb5hL8%2FKKtAW2xkSS9sQSYqo8ose0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;561&quot; height=&quot;527&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;1380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금만 더 하면 풀릴 것 같은 문제는 바로 정답을 보기 아까운 경우가 많을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 토론을 통해 내 알고리즘 기준으로 대화를 나누어 푸는 경우도 있을 것 같은 느낌이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;b&gt;문제에 대한 다른 궁금증도 해결&lt;/b&gt;할 수 있는 좋은 창구가 마련되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데도 정말 모르겠는 건, 해설 탭을 눌러서 정답을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, &lt;b&gt;못 푼 문제에 대한 해설은 오직 '도전(Challenge)' 단계&lt;/b&gt; 에서만 볼 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;도전(Challenge) 문제에서 해설을 눌렀을 때&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQpFiQ/dJMcagS6xYK/MkzvKqXdui2B3GRfdblWkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQpFiQ/dJMcagS6xYK/MkzvKqXdui2B3GRfdblWkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQpFiQ/dJMcagS6xYK/MkzvKqXdui2B3GRfdblWkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQpFiQ%2FdJMcagS6xYK%2FMkzvKqXdui2B3GRfdblWkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;428&quot; height=&quot;249&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해설을 볼 수 있지만 경험치를 얻을 수 없는 것을 볼 수 있다... 이러면 포기할 수가 없을 것 같다...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;테스트(Test) 문제에서 해설을 눌렀을 때&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/skD8q/dJMcaaFnw2I/M40WkC5eg1WZMxmNkrQyx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/skD8q/dJMcaaFnw2I/M40WkC5eg1WZMxmNkrQyx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/skD8q/dJMcaaFnw2I/M40WkC5eg1WZMxmNkrQyx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FskD8q%2FdJMcaaFnw2I%2FM40WkC5eg1WZMxmNkrQyx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;436&quot; height=&quot;269&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스트 문제는 풀지 않는 이상 해설을 볼 수 없으니&lt;/b&gt; 토론을 통해서 정답을 얻어야 겠다는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;테스트 문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trails/complete/curated-cards/test-the-day-of-the-day/description&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.codetree.ai/ko/trails/complete/curated-cards/test-the-day-of-the-day/description&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779098050301&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;그 요일은 설명 | 코드트리&quot; data-og-description=&quot;그 요일은을 통해 문제 요구사항과 입력&amp;middot;출력 예시를 꼼꼼히 확인해 정확한 풀이 전략을 세워보세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trails/complete/curated-cards/test-the-day-of-the-day/description&quot; data-og-url=&quot;https://www.codetree.ai/ko/trails/complete/curated-cards/test-the-day-of-the-day/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ercGww/dJMb84qd5Ls/onpuF6kcLNy5OKzUBPTkn0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trails/complete/curated-cards/test-the-day-of-the-day/description&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trails/complete/curated-cards/test-the-day-of-the-day/description&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ercGww/dJMb84qd5Ls/onpuF6kcLNy5OKzUBPTkn0/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;그 요일은 설명 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;그 요일은을 통해 문제 요구사항과 입력&amp;middot;출력 예시를 꼼꼼히 확인해 정확한 풀이 전략을 세워보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 문제를 풀어보고 나의 정답과 해설을 비교해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;1288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw92Bn/dJMcafNsJQ9/VLW72nu01skC20y8Y2oAQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw92Bn/dJMcafNsJQ9/VLW72nu01skC20y8Y2oAQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw92Bn/dJMcafNsJQ9/VLW72nu01skC20y8Y2oAQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw92Bn%2FdJMcafNsJQ9%2FVLW72nu01skC20y8Y2oAQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;561&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;1288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 항상 문제를 풀었어도 정답과 비교를 하는 편이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정석적인 풀이를 봐야지 내가 어디 부분에서 애매하게 코딩하고 있는지 보이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해설에서는 미리 달을 일로 변환하는 로직을 함수로 만들어 재사용성을 챙겨서 풀은 것을 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 달을 변환하지 않고 그때마다 카운트하는 로직이었다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시뮬레이션은 어려운 문제의 경우 엄청 복잡하기 때문에 이런 모듈화가 필수인 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 굳이 그렇게 안풀어도 되겠지만, 해설과 같은 습관을 들여 추후 난이도 높은 문제에 도전해야 겠다는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;후기&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BqJfg/dJMcadhL1yn/TOyV7Y1K2SKmJWCqHBVkvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BqJfg/dJMcadhL1yn/TOyV7Y1K2SKmJWCqHBVkvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BqJfg/dJMcadhL1yn/TOyV7Y1K2SKmJWCqHBVkvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBqJfg%2FdJMcadhL1yn%2FTOyV7Y1K2SKmJWCqHBVkvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;320&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘도 열심히 잔디를 심었으니 뿌듯하다 ! 화이팅!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 알고리즘 사이트를 풀면서 알고리즘 풀이와 '게이미피케이션'에 관심이 있었고, 실제로 프로젝트를 만들어 본 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트레일과 내장 IDE, 해설과 토론의 배치가 자연스럽게 이어질 수 있게 설계한 것이 느껴지는 사이트이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 읽는 독자라면 아래 링크를 통해서 한번 풀어보길 바란다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.codetree.ai/ko/trail-info&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779098667770&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩 테스트 학습 안내 | 코드트리&quot; data-og-description=&quot;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-url=&quot;https://www.codetree.ai/ko/trail-info&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uEiUF/dJMb9jOsh0b/tTFUDsYbeRhdk5EK6Ppri1/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/trail-info&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uEiUF/dJMb9jOsh0b/tTFUDsYbeRhdk5EK6Ppri1/img.png?width=1400&amp;amp;height=1400&amp;amp;face=0_0_1400_1400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩 테스트 학습 안내 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;막막한 코딩테스트 준비, 혼자 헤매지 말고 체계적인 코딩 학습과 단계별 가이드로 빠르게 실력을 쌓아 취업에 성공하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>알고리즘 기초</category>
      <category>완전탐색</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <category>코테공부</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/25</guid>
      <comments>https://choosla.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 18 May 2026 19:10:13 +0900</pubDate>
    </item>
    <item>
      <title>[코드트리] 코드트리 갭체크, 내가 부족한 부분 검사하기</title>
      <link>https://choosla.tistory.com/24</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;기존 플랫폼의 한계와 새로운 발견&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 사라진 '백준'을 대체하여 어디서 이제 알고리즘을 풀어야하는지 막막한 고민이 앞섰다. 이건 비단 나뿐만 아니라 다른 개발자들도 똑같은 고민을 가지고 있을 거라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 이들이 백준을 사용하고 있었지만 백준이라는 사이트는 꽤나 불친절한 사이트였던 걸로 기억하고 있다. 처음 시작을 하였을 때는 제대로 제출해도 컴파일러 문제라고 하니 AI 없던 시절이라 블로그 글에서 원인을 찾고 겨우겨우 냈던 경험이 있다. 특히 어떤 한 문제에 대한 해설을 찾기위해서 구글링을 해도 너무 다양한 언어과 풀이법들이 혼재해서 알고리즘을 공부하는 것에 대한 막연한 공포심이 있었던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 중 '코드트리'라는 사이트를 발견하게 되어 추후 문제에 대한 풀이는 여기로 하기로 마음을 먹게 되었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;어디서부터 시작해야 할까?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 이들이 알고리즘 공부를 시작함에 있어서 고민인 점은 역시나 &quot;어디서 부터 내가 시작을 해야하지?&quot;일 것이다. 정말 다양한 알고리즘들이 존재하고 난이도가 높아질 수록 여러가지 알고리즘을 섞어서 풀어야하니 기존에 존재하는 그저 문제만 존재하고 풀으라고 하는 방식은 쉽게 포기로 이어지기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 대해서 코드트리는 새로운 방식으로 어쩌면 왜 이제까지 이런게 없었을까 하는 방식으로 우리에게 친근하게 다가왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 체계적인 커리큘럼을 통한 개개인 맞춤형 문제풀이&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1890&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LgcQx/dJMcacwjvpY/fkgXC2ZlnSKay76yQwrLr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LgcQx/dJMcacwjvpY/fkgXC2ZlnSKay76yQwrLr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LgcQx/dJMcacwjvpY/fkgXC2ZlnSKay76yQwrLr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLgcQx%2FdJMcacwjvpY%2FfkgXC2ZlnSKay76yQwrLr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1890&quot; height=&quot;924&quot; data-origin-width=&quot;1890&quot; data-origin-height=&quot;924&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람마다 알고있는 개념의 범위와 그 깊이가 다르므로 스스로 그것을 체크하면서 푸는 것은 또 하나의 장벽이 된다고 생각한다. 하지만 코드트리에서는 나에게 부족한 개념과 난이도를 알아서 제시하게 되준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;코드트리만의 차별점, '실력 진단(갭체크)'&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 나에게 맞는 난이도는 어떻게 체크하게 될까 ?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1642&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U95T0/dJMcagS0lko/2slNh4k2yY9sSfIqnVk7mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U95T0/dJMcagS0lko/2slNh4k2yY9sSfIqnVk7mk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U95T0/dJMcagS0lko/2slNh4k2yY9sSfIqnVk7mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU95T0%2FdJMcagS0lko%2F2slNh4k2yY9sSfIqnVk7mk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1642&quot; height=&quot;830&quot; data-origin-width=&quot;1642&quot; data-origin-height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 '갭체크'가 이 코드트리의 차별점이자 특징이라고 할 수 있다. 여러 개의 간단한 문제들을 10~20분 내로 풀어보며 사용자가 어디를 어디까지 풀 수 있는지 확연하게 테스트해볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 또한 이것을 통해 갭체크를 해서 나의 수준을 확인하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 쉬운 문제부터 어려운 문제까지 서서히 난이도를 높혀가면서 풀게 되는데 만약에 알고 있는 유형의 문제가 나오게 된다면 금방 풀리지만 잠깐이라도 막히게 된다면 시간이 부족하게 되니 집중하면서 풀어보길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 문제를 풀게 되었을 때 지문을 빠르게 읽어보고 그 다음 입력 값의 크기로 어떤 알고리즘까지 '무식하게'풀 수 있게 되는지 판단한다. 물론 효율적인 알고리즘이 있다면 그것을 쓰면 되지만 대게 그것까지 생각을 하는 것은 시간이 오래걸린다. 그리고 간단히 종이에 입력하는 변수명과 문제에 주는 예제 케이스를 최대 두개까지 손으로 풀어가며 적절한 알고리즘을 선택하고 의사코드(pseudo code) 형태로 간단히 나타낸 후 코드를 적기 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;선행 학습 가이드와 체계적인 로드맵&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/banp4O/dJMcaiwuaiC/E1c84j65C4umb5f7tBbwBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/banp4O/dJMcaiwuaiC/E1c84j65C4umb5f7tBbwBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/banp4O/dJMcaiwuaiC/E1c84j65C4umb5f7tBbwBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbanp4O%2FdJMcaiwuaiC%2FE1c84j65C4umb5f7tBbwBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1848&quot; height=&quot;614&quot; data-origin-width=&quot;1848&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqHO9C/dJMcaiwuaiH/AE2aXi3wUkWS7x9RR4zsu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqHO9C/dJMcaiwuaiH/AE2aXi3wUkWS7x9RR4zsu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqHO9C/dJMcaiwuaiH/AE2aXi3wUkWS7x9RR4zsu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqHO9C%2FdJMcaiwuaiH%2FAE2aXi3wUkWS7x9RR4zsu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1844&quot; height=&quot;912&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 검사가 끝나게 되면 그래프를 통해서 내가 어디 난이도 까지 풀 수 있는지 한눈에 볼 수 있게끔 잘 표현되어 있다. 이러한 시각적인 지표를 잘 보여주는 것도 코드트리의 장점이라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백트래킹 문제를 많이 풀어보았지만 역시나 오랜만에 시작하게 되니 틀리는 모습을 볼 수 있다. 이렇게 내가 풀었던 알고리즘에 대해서도 다시 리마인드를 알아서 해주게 되니 이것또한 편하다!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1868&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OFl8L/dJMcajoznz9/F3qpckKMGod6EDHyQxbi6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OFl8L/dJMcajoznz9/F3qpckKMGod6EDHyQxbi6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OFl8L/dJMcajoznz9/F3qpckKMGod6EDHyQxbi6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOFl8L%2FdJMcajoznz9%2FF3qpckKMGod6EDHyQxbi6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1868&quot; height=&quot;1440&quot; data-origin-width=&quot;1868&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그리고 디테일하게 세부적으로 문제들을 풀기 위해서 어떤 알고리즘이 '선행'되어야 하는지도 자세히 알려주고 있다는 점은 이제까지 어렵다고만 느꼇던 학습과정을 좀더 수월하게 해주는 좋은 지침일꺼라고 생각된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2086&quot; data-origin-height=&quot;1350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/35hXG/dJMcacQAegA/pUtw96wpTKnEcIKjpNGm30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/35hXG/dJMcacQAegA/pUtw96wpTKnEcIKjpNGm30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/35hXG/dJMcacQAegA/pUtw96wpTKnEcIKjpNGm30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F35hXG%2FdJMcacQAegA%2FpUtw96wpTKnEcIKjpNGm30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2086&quot; height=&quot;1350&quot; data-origin-width=&quot;2086&quot; data-origin-height=&quot;1350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드트리의 코드트레일 부분을 들어가게 되면 이렇게 하나의 코스별로 알고리즘을 분류해서 코스요리처럼 우리에게 안내해주고 있다. 이런 체계적인 학습코스와 나의 실력을 평가해주는 시스템으로 여러 기업의 코딩테스트를 준비하겠다는 마음가짐을 되새기게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;코드트리 청약 통장 챌린지 참여 안내&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778424973606&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;3년 만에 돌아온, 코드트리 청약 통장 챌린지 | 코드트리&quot; data-og-description=&quot;매주 학습 납입하고 7주 만기 채우면 코드트리 8월까지 무료. 매주 추첨권을 모아 맥북&amp;middot;에어팟&amp;middot;애플워치 응모까지. 신청 인원에 따라 조기마감될 수 있어요.&quot; data-og-host=&quot;www.codetree.ai&quot; data-og-source-url=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot; data-og-url=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cQiw4N/dJMb8WMt45V/TWWq0z74ON1YaeS7XbJ8Z1/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/ckEo4r/dJMb8TCeapb/PvMotajkyB5jcaD7cSeZR0/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890&quot;&gt;&lt;a href=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.codetree.ai/ko/no-free-lunch-2026/?ref=YPD4SX&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cQiw4N/dJMb8WMt45V/TWWq0z74ON1YaeS7XbJ8Z1/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/ckEo4r/dJMb8TCeapb/PvMotajkyB5jcaD7cSeZR0/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;3년 만에 돌아온, 코드트리 청약 통장 챌린지 | 코드트리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;매주 학습 납입하고 7주 만기 채우면 코드트리 8월까지 무료. 매주 추첨권을 모아 맥북&amp;middot;에어팟&amp;middot;애플워치 응모까지. 신청 인원에 따라 조기마감될 수 있어요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.codetree.ai&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;현재 지금 코드트리가 코드트리 청약 통장 챌린지를 통해서 최대 8월까지 무료로 코스를 학습할 수 있는 기회를 주고 있으니 당장 참가해 보자!&lt;/p&gt;</description>
      <category>알고리즘/코드트리</category>
      <category>갭체크</category>
      <category>알고리즘공부</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <category>코테공부</category>
      <category>코테준비</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/24</guid>
      <comments>https://choosla.tistory.com/24#entry24comment</comments>
      <pubDate>Mon, 11 May 2026 00:10:21 +0900</pubDate>
    </item>
    <item>
      <title>연속 펄스 부분 수열의 합</title>
      <link>https://choosla.tistory.com/23</link>
      <description>&lt;pre id=&quot;code_1754955055435&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;limits.h&amp;gt;

using namespace std;

long long best = LLONG_MIN;


long long solution(vector&amp;lt;int&amp;gt; sequence) {
    long long answer = 0;
    
    const int n = sequence.size();
    
    long long best = LLONG_MIN;
    
    // 카데인 알고리즘
    // 이전 까지의 최대 연속 합 vs 현재의 값
    // 현재의 값이 만약에 크다면 어떤 짓을 해도 이길 수 없는다
    long long currentA = 0;
    long long currentB = 0;
    
    for(int i=0; i &amp;lt; n; i++){
        long long pulseA = (i % 2 == 0) ? 1LL : -1LL;
        long long pulseB = -pulseA;
        
        long long a = pulseA * (long long) sequence[i];
        long long b = pulseB * (long long) sequence[i];
        
        currentA = max(a, a + currentA);
        currentB = max(b, b + currentB);
        
        best = max(best, max(currentA, currentB));
    }
    
    
    
    return best;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/23</guid>
      <comments>https://choosla.tistory.com/23#entry23comment</comments>
      <pubDate>Tue, 12 Aug 2025 08:31:05 +0900</pubDate>
    </item>
    <item>
      <title>[알고스팟] 합친 LIS ( JLIS )</title>
      <link>https://choosla.tistory.com/22</link>
      <description>&lt;pre id=&quot;code_1754748807230&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;limits.h&amp;gt;

using namespace std;

vector&amp;lt;int&amp;gt; a,b;
int cache[101][101];

// 합친 것의 최대 길이는 구하는 문제
// 최댁 길이는 200으로 int로도 충분
int func(int idxA, int idxB){
    // 0부터 시작하기 위한 트릭
    int&amp;amp; ret = cache[idxA + 1][idxB + 1];

    if(ret != -1) return ret;

    // 없을 경우 부분문제 시작
    // 기본값은 2이다.
    // A와 B에서 하나씩 선택되었기 때문이다.
    ret = 2;

    // 원소들은 32비트 부호 있는 정수에 저장이 가능하다고 명시 되어있음
    // 최소값으로 초기화 하기 위해서는 32비트를 넘는 자료형이 필요함
    // 여기서는 longlong을 사용하겠음
    // 처음에 시작을 할 경우에 대해서 처리를 위해 LLONG_MIN을 사용했음
    // 이러지 않는다면 각 자리마다 이 함수를 실행시켜줘야하는 불상사 발생
    // 즉 100 * 100 = 10000번을 함수 호출해줘야함
    long long nowA = (idxA == -1) ? LLONG_MIN : a[idxA];
    long long nowB = (idxB == -1) ? LLONG_MIN : b[idxB];
    
    // 현재 선택된 것 중 큰 값을 지정해준다 &amp;gt;&amp;gt; 기준값
    long long maxEle = max(nowA,nowB);

    // a와 b 중 하나씩 뽑는 것을 가정 &amp;gt;&amp;gt; 완전 탐색
    for(int start = idxA + 1; start &amp;lt; a.size() ; start ++){
        if(maxEle &amp;lt; a[start]){
            ret = max(ret , 1 + func(start,idxB));
        }
    }

    for(int start = idxB +1; start &amp;lt; b.size(); start++){
        if(maxEle &amp;lt; b[start]){
            ret = max(ret , 1 + func(idxA , start));
        }
    }

    return ret;
}

int main(void){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int cc;
    cin &amp;gt;&amp;gt; cc;
    for(int c = 0; c &amp;lt; cc; c++){
        // 케이스 시작전 초기화
        memset(cache,-1,sizeof(cache));
        a.clear();
        b.clear();

        int sizeA, sizeB;
        cin &amp;gt;&amp;gt; sizeA &amp;gt;&amp;gt; sizeB;

        // 동적할당 최소화
        a.reserve(sizeA);
        b.reserve(sizeB);

        for(int i=0; i &amp;lt; sizeA; i++){
            int tmp;
            cin &amp;gt;&amp;gt; tmp;
            a.push_back(tmp);
        }

        for(int i=0; i &amp;lt; sizeB; i++){
            int tmp;
            cin &amp;gt;&amp;gt; tmp;
            b.push_back(tmp);
        }

        // 여기서 2를 빼주어야 한다.
        // 가상으로 추가한 입력 값이기 때문에 최종에선 제거
        cout &amp;lt;&amp;lt; func(-1,-1) -2 &amp;lt;&amp;lt; endl;
    }



    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/알고스팟</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/22</guid>
      <comments>https://choosla.tistory.com/22#entry22comment</comments>
      <pubDate>Sat, 9 Aug 2025 23:13:31 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.8 패키지</title>
      <link>https://choosla.tistory.com/19</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 4.8 패키지&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741485089549&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.8 패키지&quot; data-og-description=&quot;4.8 패키지(Packages)자바에서는 class들을 package(패키지)라는 컬렉션으로 그룹화할 수 있다. 패키지를 사용하면 코드를 체계적으로 정리할 수 있고, 자신의 코드와 외부 라이브러리를 충돌 없이 분&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/19&quot; data-og-url=&quot;https://choosla.tistory.com/19&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CUI5S/hyYmTWhlNi/iwwggbRshBu1IlKRGwyRm1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4h7NF/hyYmZvsAFJ/lwdVRu6NWlO592xosd4Mz0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/19&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CUI5S/hyYmTWhlNi/iwwggbRshBu1IlKRGwyRm1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4h7NF/hyYmZvsAFJ/lwdVRu6NWlO592xosd4Mz0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.8 패키지&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.8 패키지(Packages)자바에서는 class들을 package(패키지)라는 컬렉션으로 그룹화할 수 있다. 패키지를 사용하면 코드를 체계적으로 정리할 수 있고, 자신의 코드와 외부 라이브러리를 충돌 없이 분&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 자바 패키지(Packages) 정리: import&amp;middot;접근 권한&amp;middot;구조 잡는 방법 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.8 패키지(Packages)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서는 &lt;code&gt;class&lt;/code&gt;들을 &lt;code&gt;package&lt;/code&gt;(패키지)라는 컬렉션으로 그룹화할 수 있다. 패키지를 사용하면 코드를 체계적으로 정리할 수 있고, 자신의 코드와 외부 라이브러리를 충돌 없이 분리할 수 있다. 이번 섹션에서는 패키지를 사용하는 방법과 생성&amp;middot;설계하는 방법에 대해 살펴본다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.8.1 패키지 이름&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지를 사용하는 중요한 이유 중 하나는 &lt;code&gt;class&lt;/code&gt; 이름의 고유성을 보장하기 위해서다.&lt;br /&gt;예를 들어, 두 명의 프로그래머가 각각 동일한 이름의 &lt;code&gt;Employee&lt;/code&gt; &lt;code&gt;class&lt;/code&gt;를 만들었다고 가정하자. 이 두 클래스를 모두 사용해야 한다면 이름 충돌이 발생한다. 그러나 각 &lt;code&gt;class&lt;/code&gt;를 서로 다른 패키지에 넣으면 충돌을 피할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 패키지 이름을 지을 때는 인터넷 도메인 이름(고유함이 보장됨)을 역순으로 작성한다. 예를 들어, 도메인이 &lt;code&gt;choosla.tistory.com&lt;/code&gt;이라면 이를 역순으로 작성한 &lt;code&gt;com.tistory.choosla&lt;/code&gt;를 패키지 기본 이름으로 삼고, 프로젝트명 등을 붙여 &lt;code&gt;com.tistory.choosla.corejava&lt;/code&gt;와 같은 형태로 확장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만든 패키지 안에 &lt;code&gt;Employee&lt;/code&gt; &lt;code&gt;class&lt;/code&gt;를 둔다면, 이 클래스의 완전한 이름(fully qualified name)은 아래와 같이 된다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;com.tistory.choosla.corejava.Employee&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.8.2 클래스 임포트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 &lt;code&gt;class&lt;/code&gt;를 사용하려면, 우선 해당 &lt;code&gt;class&lt;/code&gt;가 속한 패키지의 공개 멤버(즉, &lt;code&gt;public&lt;/code&gt; &lt;code&gt;class&lt;/code&gt;)를 참조할 수 있어야 한다. 자바에서 다른 패키지에 있는 &lt;code&gt;class&lt;/code&gt;를 가져오는 방법은 두 가지이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;완전한 패키지 경로(fully qualified name)를 사용하는 방법&lt;/b&gt;&lt;br /&gt;예를 들어,와 같이 패키지 경로 전체( &lt;code&gt;java.time&lt;/code&gt; )를 붙이면 되지만, 매번 긴 이름을 작성해야 하므로 번거롭다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;java.time.LocalDate today = java.time.LocalDate.now();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;import&lt;/code&gt; 문을 사용하는 방법&lt;/b&gt;&lt;br /&gt;더 간단하고 흔히 쓰는 방법이다.이렇게 하면 &lt;code&gt;java.time&lt;/code&gt; 패키지 내의 모든 &lt;code&gt;class&lt;/code&gt;를 사용할 수 있다. 혹은 아래처럼 특정 &lt;code&gt;class&lt;/code&gt;만 가져올 수도 있다.&lt;code&gt;import&lt;/code&gt; 구문은 반드시 소스 파일 최상단(즉, &lt;code&gt;package&lt;/code&gt; 선언 바로 아래)에 작성해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import java.time.LocalDate; LocalDate today = LocalDate.now();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import java.time.*; LocalDate today = LocalDate.now();&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;import&lt;/code&gt; 문법에서 &lt;code&gt;*&lt;/code&gt;는 해당 패키지 내 모든 &lt;code&gt;class&lt;/code&gt;를 임포트한다는 의미이며, 예를 들어 &lt;code&gt;import java.time.*;&lt;/code&gt;는 &lt;code&gt;java.time&lt;/code&gt; 패키지 안의 모든 공개 클래스를 임포트한다. 다만, &lt;code&gt;import java.*;&lt;/code&gt;처럼 하위 모든 패키지를 한꺼번에 불러오는 것은 불가능하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이름 충돌 상황&lt;/b&gt;&lt;br /&gt;만약 서로 다른 패키지에서 동일한 이름의 &lt;code&gt;class&lt;/code&gt;를 사용하려 할 때 충돌이 발생할 수 있다. 예를 들어, &lt;code&gt;java.util.Date&lt;/code&gt;와 &lt;code&gt;java.sql.Date&lt;/code&gt;는 둘 다 &lt;code&gt;Date&lt;/code&gt;라는 클래스 이름을 사용한다.이 경우, 아래와 같이 임포트를 명시적으로 처리해야 한다.혹은 두 개의 &lt;code&gt;Date&lt;/code&gt;가 모두 필요하다면, 패키지 이름 전체를 기술하는 방식으로 구분한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;var startTime = new java.util.Date();
var now = new java.sql.Date(...);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import java.util.*;
import java.sql.*;
import java.util.Date; // java.util.Date만 명시적 임포트&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import java.util.*;
import java.sql.*;
Date today; // ❌ 컴파일 에러 (이름 충돌)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(C++ 비교문)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.8.3 정적 임포트(&lt;code&gt;static import&lt;/code&gt;)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 5부터는 메소드와 필드(주로 &lt;code&gt;static&lt;/code&gt;으로 선언된 것)를 임포트할 때도 &lt;code&gt;import&lt;/code&gt;를 사용할 수 있다. 이를 &lt;b&gt;정적 임포트&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 아래와 같이 작성하면&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;import static java.lang.System.*;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;System&lt;/code&gt; &lt;code&gt;class&lt;/code&gt;의 정적 &lt;code&gt;out&lt;/code&gt;, &lt;code&gt;exit&lt;/code&gt; 등을 사용할 때 &lt;code&gt;System&lt;/code&gt;을 명시하지 않아도 된다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;out.println(&quot;Good&quot;);
exit(0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 특정 정적 멤버만 골라서 임포트할 수도 있다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;import static java.lang.System.out;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 정적 임포트를 과도하게 사용하면 코드의 가독성이 떨어질 수 있으므로 필요할 때만 적절히 사용하는 것이 좋다. 가령 수학 연산에 관해서는 다음 두 코드 중 어느 쪽이 더 직관적인지는 논쟁의 여지가 있다.&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;// 정적 임포트 시 (import static java.lang.Math.*;)
sqrt(pow(x, 2) + pow(y, 2));&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// 일반 import 혹은 완전한 패키지 경로 사용 시
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.8.4 패키지 안에 &lt;code&gt;class&lt;/code&gt; 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 패키지에 &lt;code&gt;class&lt;/code&gt;를 두려면, 소스 파일 최상단에 &lt;code&gt;package&lt;/code&gt; 구문을 명시해야 한다. 예를 들어,&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;package com.tistory.choosla;
public class Employee {
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Unnamed Package&lt;/b&gt;&lt;br /&gt;&lt;code&gt;package&lt;/code&gt; 구문을 전혀 쓰지 않으면 그 파일은 &amp;ldquo;이름 없는 패키지(unnamed package)&amp;rdquo;에 속하게 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디렉토리 구조&lt;/b&gt;&lt;br /&gt;실제로 소스 파일을 컴파일할 때, 이 &lt;code&gt;package&lt;/code&gt; 구문을 기반으로 디렉토리 구조가 잡힌다. 예를 들어, &lt;code&gt;com.tistory.choosla&lt;/code&gt;라는 패키지라면, 소스 파일은 &lt;code&gt;com/tistory/choosla&lt;/code&gt; 폴더 안에 있어야 하며, 컴파일 시점에 동일한 구조를 따라 &lt;code&gt;.class&lt;/code&gt; 파일이 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.8.5 패키지 엑세스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전까지 &lt;code&gt;public&lt;/code&gt;과 &lt;code&gt;private&lt;/code&gt; 접근 제어자에 대해 다뤄왔다. 실제로 자바에는 다음과 같은 네 가지 접근 수준이 존재한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;public&lt;/code&gt;: 어디서든 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;protected&lt;/code&gt;: 같은 패키지 또는 상속받은 하위 &lt;code&gt;class&lt;/code&gt; 내에서만 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패키지 접근(기본 접근, default)&lt;/b&gt;: 아무런 접근 제어자를 붙이지 않았을 때. 같은 패키지 내에서만 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;private&lt;/code&gt;: 해당 &lt;code&gt;class&lt;/code&gt; 내부에서만 접근 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;class&lt;/code&gt; 자체가 &lt;code&gt;public&lt;/code&gt;으로 선언되지 않았다면, 같은 패키지 내에서만 해당 &lt;code&gt;class&lt;/code&gt;를 사용할 수 있다. 즉, &lt;code&gt;public&lt;/code&gt;이 없는 &lt;code&gt;class&lt;/code&gt;는 패키지 내부에서만 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수(필드)의 경우도 마찬가지다. &lt;code&gt;public&lt;/code&gt;이나 &lt;code&gt;private&lt;/code&gt;을 붙이지 않으면, 해당 필드는 같은 패키지 내에서는 자유롭게 접근할 수 있다(패키지 접근). 그러나 &lt;b&gt;캡슐화(encapsulation)&lt;/b&gt; 원칙에 따라, 일반적으로 필드는 &lt;code&gt;private&lt;/code&gt;로 선언하고 &lt;code&gt;public&lt;/code&gt; 메서드(&lt;code&gt;getter&lt;/code&gt;/&lt;code&gt;setter&lt;/code&gt;)를 통해 제어하는 것이 권장된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정리하면&lt;/b&gt;, 패키지는 자바에서 코드 충돌을 방지하고, 코드를 깔끔하게 조직화하는 중요한 도구이다. 패키지 이름의 고유성을 확보하기 위해 도메인 역순을 활용하는 관행이 널리 쓰이며, &lt;code&gt;import&lt;/code&gt;와 정적 임포트(&lt;code&gt;static import&lt;/code&gt;)를 통해 손쉽게 클래스를 불러와 사용할 수 있다. 또한, 접근 제어자(&lt;code&gt;public&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;, etc.) 및 패키지 접근(기본 접근) 개념을 잘 활용하면 프로젝트 구조를 더욱 명확하게 관리할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>import</category>
      <category>디렉토리구조</category>
      <category>자바</category>
      <category>접근제어자</category>
      <category>코어자바</category>
      <category>패키지</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/19</guid>
      <comments>https://choosla.tistory.com/19#entry19comment</comments>
      <pubDate>Sat, 8 Mar 2025 20:44:44 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.7 레코드(Records)</title>
      <link>https://choosla.tistory.com/18</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.6 객체 생성&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741485016207&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.6 객체 생성&quot; data-og-description=&quot;4.6 객체 생성(Object Construction)객체(object)가 생성될 때, 자바(Java)에서는 다양한 방법으로 필드 초기화와 생성자 호출이 이루어진다. 어떤 경우든 객체가 만들어질 때 내부 상태가 어떻게 결정되는&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/17&quot; data-og-url=&quot;https://choosla.tistory.com/17&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rftFU/hyYm9kxGmu/ugHPobYiKDLTJkX0BQ0sQ1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4cpZZ/hyYm1z1anW/eFFfRyqZvRGcK0u8pDYn2K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/17&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rftFU/hyYm9kxGmu/ugHPobYiKDLTJkX0BQ0sQ1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4cpZZ/hyYm1z1anW/eFFfRyqZvRGcK0u8pDYn2K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.6 객체 생성&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.6 객체 생성(Object Construction)객체(object)가 생성될 때, 자바(Java)에서는 다양한 방법으로 필드 초기화와 생성자 호출이 이루어진다. 어떤 경우든 객체가 만들어질 때 내부 상태가 어떻게 결정되는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 자바 레코드(Records) 완전 정복: 불변 객체 설계와 예제 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h1&gt;4.7 레코드(Records)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때때로 객체 지향 프로그래밍이 제공하는 데이터 은닉(캡슐화)이 오히려 방해가 될 때가 있다. 예를 들어, 평면에서 좌표를 나타내기 위한 &lt;code&gt;Point&lt;/code&gt; 클래스를 생각해보자. 보통은 다음과 같이 작성한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;class Point {
    private final double x;
    private final double y;
    public Point(double x, double y) { this.x = x; this.y = y; }
    public double getX() { return x; }
    public double getY() { return y; }
    public String toString() { 
        return &quot;Point[x=%f, y=%f]&quot;.formatted(x, y); 
    }
    // equals, hashCode 등...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 &lt;code&gt;x&lt;/code&gt;와 &lt;code&gt;y&lt;/code&gt;를 감추고 게터 메소드를 통해 값을 얻는 방식이 꼭 유용하지만은 않을 때가 있다. 자바 16부터는 이러한 단순한 데이터 구조를 보다 간결하게 정의하기 위해 &lt;b&gt;레코드(&lt;code&gt;record&lt;/code&gt;)&lt;/b&gt;라는 문법을 도입했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.7.1 레코드 컨셉&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;레코드(&lt;code&gt;record&lt;/code&gt;)&lt;/b&gt;는 상태가 &lt;b&gt;불변(immutable)&lt;/b&gt;이며 공개적으로 읽을 수 있는 특수한 형태의 클래스이다. 예컨대 &lt;code&gt;Point&lt;/code&gt;를 레코드로 정의하면 다음 한 줄로 충분하다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;record Point(double x, double y) {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 작성하면 컴파일러가 아래 사항을 자동으로 만들어 준다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;private final&lt;/code&gt; 필드&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;private final double x;
private final double y;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;정식 생성자(Canonical Constructor)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;Point(double x, double y) {
    this.x = x;
    this.y = y;
}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;접근자 메소드(게터)&lt;br /&gt;레코드에서는 자동 생성되는 게터 이름이 &lt;code&gt;x()&lt;/code&gt;, &lt;code&gt;y()&lt;/code&gt;가 된다. (&lt;code&gt;getX()&lt;/code&gt;나 &lt;code&gt;getY()&lt;/code&gt;가 아님)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;public double x() { return x; }
public double y() { return y; }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toString()&lt;/code&gt;, &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt;&lt;br /&gt;각 필드의 내용을 사용해 자동 생성된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;code&gt;Point&lt;/code&gt; 레코드는 아래와 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;var p = new Point(3, 4);
System.out.println(p.x() + &quot; &quot; + p.y()); &lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의&lt;/b&gt;&lt;br /&gt;레코드의 필드는 자동으로 &lt;code&gt;private final&lt;/code&gt;이며, 한 번 설정되면 변경할 수 없다(불변). 하지만 레코드가 가변 객체(예: &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;StringBuilder&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt; 등)를 참조한다면, 그 내부 상태는 변경될 수 있다. 완전한 불변을 원하면 필드에 가변 객체를 쓰지 않거나, 방어적 복사(defensive copy) 등을 적용해야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메소드 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드에서도 사용자 정의 메소드를 추가할 수 있다. 예를 들어, &lt;code&gt;(0,0)&lt;/code&gt; 원점으로부터의 거리를 구하는 메소드를 추가해보자.&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;record Point(double x, double y) {
    public double distanceFromOrigin() {
        return Math.hypot(x, y);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;distanceFromOrigin()&lt;/code&gt;을 이용해 좌표 &lt;code&gt;(x, y)&lt;/code&gt;가 원점에서 얼마나 떨어져 있는지를 알 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;static&lt;/code&gt; 필드와 메소드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드는 &lt;code&gt;static&lt;/code&gt; 필드와 메소드를 가질 수 있다. 다만, &lt;b&gt;인스턴스 필드&lt;/b&gt;는 레코드의 컴포넌트로 선언된 것들만 가능하며, 새로운 인스턴스 필드를 추가할 수는 없다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;record Point(double x, double y) {
    public static Point ORIGIN = new Point(0, 0);
    public static double distance(Point p, Point q) {
        return Math.hypot(p.x - q.x, p.y - q.y);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 선언하면 &lt;code&gt;Point.ORIGIN&lt;/code&gt;이나 &lt;code&gt;Point.distance(p, q)&lt;/code&gt;로 정적 필드&amp;middot;메소드를 호출할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의&lt;/b&gt;&lt;br /&gt;레코드는 &lt;b&gt;추가 인스턴스 필드&lt;/b&gt;를 가질 수 없다. 선언된 컴포넌트만 필드가 된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.7.2 레코드 생성자: 정식(Canonical), 사용자 정의(Custom), 간결(Compact)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드는 다양한 방식의 생성자를 지원한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(1) 정식 생성자(Canonical Constructor)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드를 선언하면 자동으로 만들어지는 생성자를 &lt;b&gt;정식 생성자&lt;/b&gt;(canonical constructor)라고 한다. 예를 들어,&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;record Point(double x, double y) {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 선언하면 내부적으로 아래 생성자가 생긴다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public Point(double x, double y) {
    this.x = x;
    this.y = y;
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하다면 이 정식 생성자를 &lt;b&gt;직접&lt;/b&gt; 정의해 덮어쓸 수 있다. 필드에 값을 넣기 전에 검증하거나 변환 등을 하고 싶을 때 유용하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(2) 사용자 정의(Custom) 생성자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레코드는 여러 개의 생성자를 가질 수 있다. 이때 생성자의 &lt;b&gt;첫 번째 문장&lt;/b&gt;에서 반드시 다른 생성자를 호출해야 하며, 결국 정식 생성자로 이어져야 한다. 예를 들어:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;record Point(double x, double y) {
    public Point() {
        this(0, 0); // 정식 생성자 호출
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;new Point()&lt;/code&gt;처럼 인자가 없는 생성자를 호출하면 결과적으로 &lt;code&gt;(0,0)&lt;/code&gt;을 가지는 &lt;code&gt;Point&lt;/code&gt; 인스턴스를 얻게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(3) 간결 생성자(Compact Constructor)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정식 생성자의 본문을 간단하게 쓰고 싶을 때는 &lt;b&gt;간결 생성자&lt;/b&gt;(compact constructor)를 사용한다. 간결 생성자는 매개변수 목록을 명시하지 않고, 레코드에 선언된 컴포넌트 이름을 그대로 사용한다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;record Range(int from, int to) {
    public Range {
        if (from &amp;gt; to) {
            int tmp = from;
            from = to;
            to = tmp;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간결 생성자에서는 아직 &lt;code&gt;this.from&lt;/code&gt;이나 &lt;code&gt;this.to&lt;/code&gt;에 값이 대입되기 &lt;b&gt;직전&lt;/b&gt;에 검증 및 수정 로직을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;마지막에 &lt;code&gt;this.from = from; this.to = to;&lt;/code&gt;가 자동으로 붙는다고 보면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.7.3 레코드 예제 코드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 레코드를 종합적으로 보여주는 예제 코드이다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;package Chapter04;

import java.util.Date;

public class RecordTest {
    public static void main(String[] args) {
        var p = new Point(3, 4);
        System.out.println(&quot;Coordinates of p: &quot; + p.x() + &quot; &quot; + p.y());
        System.out.println(&quot;Distance from origin: &quot; + p.distanceFromOrigin());
        System.out.println(&quot;Distance from origin: &quot; + Point.distance(Point.ORIGIN, p));

        // 가변 객체를 필드로 가진 레코드 예시
        var pt = new PointInTime(3, 4, new Date());
        System.out.println(&quot;Before: &quot; + pt);
        pt.when().setTime(0); // Date는 가변 객체이므로 수정 가능
        System.out.println(&quot;After: &quot; + pt);

        // 간결 생성자 사용 예시
        var r = new Range(4, 3);
        System.out.println(&quot;r: &quot; + r);
    }
}

record Point(double x, double y) {
    // 사용자 정의 생성자(인자 없는)
    public Point() {
        this(0, 0);
    }

    // 원점까지의 거리 계산
    public double distanceFromOrigin() {
        return Math.hypot(x, y);
    }

    // 정적 필드와 정적 메소드
    public static Point ORIGIN = new Point(0, 0);

    public static double distance(Point p, Point q) {
        return Math.hypot(p.x - q.x, p.y - q.y);
    }
}

// 가변 객체(Date)를 필드로 가진 레코드
record PointInTime(double x, double y, Date when) {}

// 간결 생성자를 통해 from과 to를 자동 교정하는 레코드
record Range(int from, int to) {
    public Range {
        if (from &amp;gt; to) {
            int temp = from;
            from = to;
            to = temp;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;PointInTime&lt;/code&gt;은 불변처럼 보이지만, 실제로 &lt;code&gt;Date&lt;/code&gt;(가변 객체)를 필드로 갖고 있으므로 &lt;code&gt;when()&lt;/code&gt; 메소드를 통해 내부 값이 변경될 수 있다.&lt;/li&gt;
&lt;li&gt;완전한 불변 객체를 원한다면, 가변 객체 대신 불변 객체를 사용하거나 방어적 복사를 적용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정리하자면&lt;/b&gt;, 레코드는 다음과 같은 특징을 지닌다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;레코드 컴포넌트(필드)는 자동으로 &lt;code&gt;private final&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toString()&lt;/code&gt;, &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt;, (필드이름)형태의 게터 생성.&lt;/li&gt;
&lt;li&gt;인스턴스 필드는 추가할 수 없고, &lt;code&gt;static&lt;/code&gt; 필드&amp;middot;메소드는 가능.&lt;/li&gt;
&lt;li&gt;정식 생성자를 덮어쓸 수도 있고, 간결 생성자를 통해 생성 과정에서 필드 검증 및 수정 로직을 간단히 넣을 수 있다.&lt;/li&gt;
&lt;li&gt;불변 구조를 표현하기에 적합하지만, 내부에 가변 객체를 넣으면 그 자체는 변경 가능성이 존재한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 4.8 패키지&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741485030683&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.8 패키지&quot; data-og-description=&quot;4.8 패키지(Packages)자바에서는 class들을 package(패키지)라는 컬렉션으로 그룹화할 수 있다. 패키지를 사용하면 코드를 체계적으로 정리할 수 있고, 자신의 코드와 외부 라이브러리를 충돌 없이 분&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/19&quot; data-og-url=&quot;https://choosla.tistory.com/19&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CUI5S/hyYmTWhlNi/iwwggbRshBu1IlKRGwyRm1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4h7NF/hyYmZvsAFJ/lwdVRu6NWlO592xosd4Mz0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/19&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CUI5S/hyYmTWhlNi/iwwggbRshBu1IlKRGwyRm1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4h7NF/hyYmZvsAFJ/lwdVRu6NWlO592xosd4Mz0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.8 패키지&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.8 패키지(Packages)자바에서는 class들을 package(패키지)라는 컬렉션으로 그룹화할 수 있다. 패키지를 사용하면 코드를 체계적으로 정리할 수 있고, 자신의 코드와 외부 라이브러리를 충돌 없이 분&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>record</category>
      <category>레코드</category>
      <category>불변객체</category>
      <category>자바</category>
      <category>코어자바</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/18</guid>
      <comments>https://choosla.tistory.com/18#entry18comment</comments>
      <pubDate>Sat, 8 Mar 2025 20:40:17 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.6 객체 생성</title>
      <link>https://choosla.tistory.com/17</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.5 메소드 매개변수&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484828103&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.5 메소드 매개변수&quot; data-og-description=&quot;4.5 메소드 매개변수 (Method Parameters)자바와 같은 프로그래밍 언어에서 메소드(또는 함수)의 매개변수가 호출될 때 어떻게 전달되는지 살펴보자. 이것을 이해하기 위해서는 call by value와 call by refer&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/16&quot; data-og-url=&quot;https://choosla.tistory.com/16&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bAuckt/hyYmYQNRan/keQvQsnNa5Iv9fDForuuVk/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/tsvvI/hyYmNBJU5v/zotUvB1MJxN4SmaeTRpMS0/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/EtuM5/hyYmU8JeUZ/JJHLxFPkf2yx3d1pJRIk90/img.png?width=631&amp;amp;height=395&amp;amp;face=0_0_631_395&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/16&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bAuckt/hyYmYQNRan/keQvQsnNa5Iv9fDForuuVk/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/tsvvI/hyYmNBJU5v/zotUvB1MJxN4SmaeTRpMS0/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/EtuM5/hyYmU8JeUZ/JJHLxFPkf2yx3d1pJRIk90/img.png?width=631&amp;amp;height=395&amp;amp;face=0_0_631_395');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.5 메소드 매개변수&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.5 메소드 매개변수 (Method Parameters)자바와 같은 프로그래밍 언어에서 메소드(또는 함수)의 매개변수가 호출될 때 어떻게 전달되는지 살펴보자. 이것을 이해하기 위해서는 call by value와 call by refer&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 객체 생성과 생성자(Constructors) 완벽 이해: 오버로딩부터 초기화 블록까지 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.6 객체 생성(&lt;code&gt;Object Construction&lt;/code&gt;)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체(&lt;code&gt;object&lt;/code&gt;)가 생성될 때, 자바(&lt;code&gt;Java&lt;/code&gt;)에서는 다양한 방법으로 &lt;b&gt;필드 초기화&lt;/b&gt;와 &lt;b&gt;생성자 호출&lt;/b&gt;이 이루어진다. 어떤 경우든 객체가 만들어질 때 내부 상태가 어떻게 결정되는지를 정확히 이해하는 것이 중요하다. 이 섹션에서는 &lt;b&gt;오버로딩(overloading)&lt;/b&gt;, &lt;b&gt;기본값 초기화&lt;/b&gt;, &lt;b&gt;매개변수 없는 생성자&lt;/b&gt;, &lt;b&gt;명시적 필드 초기화&lt;/b&gt;, &lt;b&gt;생성자 이름 짓기&lt;/b&gt;, &lt;b&gt;다른 생성자를 부르는 방법(&lt;code&gt;this(...)&lt;/code&gt;)&lt;/b&gt;, &lt;b&gt;초기화 블럭&lt;/b&gt;, 마지막으로 &lt;b&gt;객체 소멸(&lt;code&gt;finalize&lt;/code&gt;)&lt;/b&gt;에 관한 내용을 자세히 살펴본다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.1 &lt;b&gt;오버로딩(&lt;code&gt;Overloading&lt;/code&gt;)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 클래스 안에서 &lt;b&gt;생성자를 포함한 메서드 이름이 같고&lt;/b&gt; 매개변수 목록이 다르면, 이를 &lt;i&gt;오버로딩(overloading)&lt;/i&gt; 이라고 한다. 예를 들어, &lt;code&gt;StringBuilder&lt;/code&gt; 객체를 생성할 때 다음 두 가지 방법이 있다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;// 빈 객체 생성
var messages = new StringBuilder();

// 특정 문자열로 초기화하며 생성
var todoList = new StringBuilder(&quot;To do:\n&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두 생성자는 모두 &lt;code&gt;StringBuilder&lt;/code&gt;라는 같은 이름을 가지지만, &lt;b&gt;매개변수 형태가 다르다&lt;/b&gt;는 점에서 오버로딩된 생성자다. 컴파일러는 메서드 호출 시점에 넘기는 인자의 타입과 개수를 보고, 호출할 생성자를 구분한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오버로딩된 생성자의 장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자의 이름은 동일하지만, &lt;b&gt;매개변수가 다름&lt;/b&gt;으로써 객체를 생성하는 여러 방식을 제공할 수 있다.&lt;/li&gt;
&lt;li&gt;다양한 초기화 로직을 매개변수 구성에 따라 달리 적용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.2 &lt;b&gt;기본적인 필드 초기화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자에서 특정 필드값을 &lt;b&gt;명시적으로 설정&lt;/b&gt;하지 않는다면, 자바는 해당 필드를 &lt;b&gt;기본값&lt;/b&gt;으로 자동 초기화한다. 기본값 규칙은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자 타입(&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt; 등)은 &lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;논리 타입(&lt;code&gt;boolean&lt;/code&gt;)은 &lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;객체 참조 타입(예: &lt;code&gt;String&lt;/code&gt;, 사용자 정의 클래스 등)은 &lt;code&gt;null&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 다음 코드에서 &lt;code&gt;hireDay&lt;/code&gt;를 생성자에서 따로 초기화해주지 않으면 &lt;code&gt;null&lt;/code&gt;로 설정된다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay; // 따로 초기화하지 않으면 null

    public Employee() {
        // name과 salary는 각각 &quot;&quot;(빈 문자열)이나 0으로 초기화할 수 있지만
        // hireDay는 명시적으로 설정하지 않으면 기본값인 null이 됨
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은, 이런 기본값 방식에 너무 의존하면, 예기치 않은 &lt;code&gt;NullPointerException&lt;/code&gt;이 발생하기 쉽다는 것이다. 가능한 한 생성자를 통해 &lt;b&gt;명시적으로 초기화&lt;/b&gt;하는 편이 안전하며, 코드 가독성도 높아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 팁&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;필드 vs 로컬 변수&lt;/b&gt;: 로컬 변수(메서드 안에서 선언된 임시 변수)는 &lt;b&gt;반드시&lt;/b&gt; 사용 전에 초기화해야 하지만, &lt;b&gt;필드는 자동으로 기본값&lt;/b&gt;을 갖는다.&lt;/li&gt;
&lt;li&gt;초깃값 의도가 분명하지 않으면 유지보수 시 혼란을 야기할 수 있으므로, &lt;b&gt;명시적 초기화&lt;/b&gt;를 적극 권장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.3 &lt;b&gt;매개변수 없는 생성자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 클래스가 &lt;b&gt;매개변수를 받지 않는 생성자&lt;/b&gt;를 정의한다. 이를 &amp;ldquo;디폴트 생성자&amp;rdquo; 또는 &amp;ldquo;인자가 없는 생성자&amp;rdquo;라고 부르기도 한다. 매개변수 없는 생성자에서는 객체 상태를 특별한 값으로 초기화한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;

    // 매개변수 없는 생성자
    public Employee() {
        name = &quot;&quot;;
        salary = 0;
        hireDay = LocalDate.now();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;b&gt;아무 생성자도&lt;/b&gt; 정의하지 않은 클래스라면, 자바가 자동으로 &lt;b&gt;인자가 없는 생성자&lt;/b&gt;를 제공한다. 단, 아래와 같은 조건이 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 생성자가 전혀 없을 때만, 자바 컴파일러가 인자가 없는 생성자를 자동으로 제공한다.&lt;/li&gt;
&lt;li&gt;자동 생성된 디폴트 생성자는 &lt;b&gt;모든 필드를 기본값(0, &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;)&lt;/b&gt;으로 초기화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 대개는 직접 생성자를 정의하여 &lt;b&gt;의도한 초기값&lt;/b&gt;으로 세팅하는 편이 더 안전하고 명확하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.4 &lt;b&gt;명시적 필드 초기화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 안에서뿐만 아니라, &lt;b&gt;필드를 선언&lt;/b&gt;하는 시점에 값을 부여할 수도 있다. 이를 &amp;ldquo;명시적 필드 초기화(explicit field initialization)&amp;rdquo;라고 한다. 예를 들어:&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Employee {
    private String name = &quot;&quot;; // 선언부에서 직접 초기화
    private double salary;
    private LocalDate hireDay;

    public Employee(double s) {
        salary = s;
        hireDay = LocalDate.now();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서는 &lt;code&gt;name&lt;/code&gt; 필드를 선언부에서 &lt;code&gt;&quot;&quot;&lt;/code&gt;로 초기화했다. 생성자를 여러 개 두거나, 초기화 로직이 조금 복잡할 경우에도 특정 필드에 대해서는 동일한 초깃값을 부여하기 편리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의&lt;br /&gt;명시적 필드 초기화는 &lt;b&gt;생성자가 호출되기 직전에&lt;/b&gt; 수행된다.&lt;br /&gt;즉, &amp;ldquo;명시적 필드 초기화&amp;rdquo; &amp;rarr; &amp;ldquo;초기화 블럭(있다면)&amp;rdquo; &amp;rarr; &amp;ldquo;생성자 본문&amp;rdquo; 순서로 실행됨을 기억하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;명시적 필드 초기화에 &lt;code&gt;static&lt;/code&gt; 메소드 활용하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 실행 전에도 호출 가능한 &lt;code&gt;static&lt;/code&gt; 메소드를 사용할 수 있다. 예:&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;class Employee {
    private static int nextId;
    private int id = advanceId(); // static 메소드로 미리 계산된 값 할당

    private static int advanceId() {
        int r = nextId;
        nextId++;
        return r;
    }
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;id&lt;/code&gt;가 할당될 때 &lt;code&gt;advanceId()&lt;/code&gt;가 먼저 호출되어 &lt;code&gt;id&lt;/code&gt;값을 결정한 뒤, 그 값이 필드에 대입된다.&lt;br /&gt;이처럼 &lt;b&gt;명시적 초기화와 &lt;code&gt;static&lt;/code&gt; 메소드&lt;/b&gt;를 결합해 여러 초기화 로직을 처리하는 것이 가능하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.5 &lt;b&gt;매개변수 이름&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자를 작성할 때, 종종 다음과 같이 &lt;b&gt;매개변수 이름&lt;/b&gt;을 지을지 고민하게 된다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public Employee(String n, double s) {
    name = n;
    salary = s;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;n&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt;는 의미가 분명하지 않아 가독성이 떨어질 수 있다.&lt;br /&gt;이를 개선하기 위해 &lt;b&gt;프로그래머들은&lt;/b&gt; 보통 다음과 같은 방식을 사용한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;의미 있는 이름&lt;/b&gt;을 짓는다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;public Employee(String aName, double aSalary) {
    name = aName;
    salary = aSalary;
}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필드와 매개변수 이름을 동일하게 두고&lt;/b&gt;, 구분을 위해 &lt;code&gt;this&lt;/code&gt; 키워드를 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;public Employee(String name, double salary) {
    this.name = name;     // this.name: 인스턴스 필드
    this.salary = salary; // 매개변수 salary가 인자로 들어옴
}&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 방법은 인스턴스 필드와 매개변수 이름이 같아 &lt;b&gt;헷갈리지 않을까?&lt;/b&gt; 싶지만, &lt;code&gt;this.name&lt;/code&gt;과 같이 묵시적(&lt;code&gt;this&lt;/code&gt;) 파라미터를 명시하면 헷갈림이 사라진다. 코드 양이 줄어들어 간결함을 선호하는 프로그래머들도 많다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.6 &lt;b&gt;다른 생성자 부르기 (&lt;code&gt;this(...)&lt;/code&gt;)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;this&lt;/code&gt; 키워드는 &amp;ldquo;현재 객체&amp;rdquo;를 가리킨다. 하지만 &lt;b&gt;생성자&lt;/b&gt; 내에서 &lt;code&gt;this(...)&lt;/code&gt;를 사용하면, 동일 클래스의 &lt;i&gt;다른 생성자&lt;/i&gt;를 호출할 수 있다. 다만 규칙이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자의 &lt;b&gt;첫 번째 문장&lt;/b&gt;으로만 &lt;code&gt;this(...)&lt;/code&gt;를 호출할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;this(...)&lt;/code&gt;를 사용하면, 해당 생성자 안에 중복된 초기화 코드를 피하고, &lt;b&gt;공통 로직을 한 생성자에 몰아넣을 수&lt;/b&gt; 있어 유지보수가 좋아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Employee {
    private static int nextId;
    private int id;
    private String name;
    private double salary;

    // 가장 일반적인 생성자
    public Employee(String n, double s) {
        name = n;
        salary = s;
        id = nextId;
        nextId++;
    }

    // 다른 생성자: 매개변수 하나만 받음
    public Employee(double s) {
        // 먼저, (String, double) 형태의 다른 생성자를 부른다
        this(&quot;Employee #&quot; + nextId, s);
        // 여기서 nextId++는 이미 다른 생성자 안에서 처리됨
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;code&gt;Employee(double s)&lt;/code&gt; 생성자는 &lt;code&gt;Employee(String n, double s)&lt;/code&gt; 생성자로 넘김으로써 &lt;b&gt;초기화 로직을 공유&lt;/b&gt;한다.&lt;br /&gt;이렇게 하면 코드 중복을 줄이고, 다양한 파라미터 조합에 유연하게 대응할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.7 &lt;b&gt;초기화 블럭&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 필드를 초기화하는 방법은 크게 세 가지가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;생성자&lt;/b&gt;에서 필드를 직접 초기화한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필드 선언부&lt;/b&gt;에서 명시적으로 초기화한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초기화 블럭(&lt;code&gt;initialization block&lt;/code&gt;)&lt;/b&gt;을 사용한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 3번 초기화 블럭은 &lt;b&gt;클래스 정의 내부&lt;/b&gt;에서 임의의 코드 블럭을 기술해두면, &lt;b&gt;객체가 생성될 때&lt;/b&gt; 자동으로 해당 블럭이 실행되는 방식이다. 예를 들어:&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Employee {
    private static int nextId;
    private int id;
    private String name;
    private double salary;

    // 초기화 블럭
    {
        id = nextId;
        nextId++;
    }

    public Employee(String n, double s) {
        name = n;
        salary = s;
    }

    public Employee() {
        // 다른 생성자처럼
        name = &quot;&quot;;
        salary = 0;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예시에서 &lt;b&gt;초기화 블럭&lt;/b&gt; &lt;code&gt;{ ... }&lt;/code&gt; 안의 코드는 &lt;b&gt;객체 생성 시점&lt;/b&gt;에 무조건 실행된다. 따라서 어떤 생성자를 호출하든 &lt;code&gt;id = nextId; nextId++;&lt;/code&gt;는 실행되어 &lt;code&gt;id&lt;/code&gt; 값을 고유하게 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 순서&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;명시적 필드 초기화&lt;/b&gt; &amp;rarr; 2. &lt;b&gt;초기화 블럭&lt;/b&gt; &amp;rarr; 3. &lt;b&gt;생성자&lt;/b&gt;&lt;br /&gt;(단, 생성자의 첫 줄에서 &lt;code&gt;this(...)&lt;/code&gt;로 다른 생성자를 호출한다면 해당 호출에 따라 흐름이 조금 달라지지만, 결국엔 위 순서를 거쳐 각 부분이 한번씩은 수행된다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 보통 &lt;b&gt;생성자 안에 초기화 코드를 직접 쓰는 경우&lt;/b&gt;가 많다. 그러나 여러 생성자에 동일하게 적용해야 할 코드가 있을 경우, 초기화 블럭을 써서 &lt;i&gt;중복 방지&lt;/i&gt;를 할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.6.8 &lt;b&gt;객체 소멸과 &lt;code&gt;finalize&lt;/code&gt; 메소드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++ 같은 언어에는 &lt;b&gt;소멸자(destructor)&lt;/b&gt; 개념이 있어, 객체가 더 이상 필요 없을 때 메모리를 회수하고 정리 로직을 수행한다. 자바(&lt;code&gt;Java&lt;/code&gt;)에서는 &lt;b&gt;가비지 컬렉터(garbage collector)&lt;/b&gt;가 자동으로 메모리를 관리하기 때문에, &lt;b&gt;소멸자&lt;/b&gt;가 따로 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거에는 &lt;code&gt;finalize()&lt;/code&gt;라는 메서드를 통해 객체가 &amp;ldquo;정말로 소멸될 때&amp;rdquo; 호출되도록 지원했었지만, &lt;b&gt;현재는 거의 사용되지 않으며&lt;/b&gt; 자바 최신 버전에서도 &lt;i&gt;권장되지 않는다&lt;/i&gt;. 필요하면 직접 자원을 해제하는 &lt;code&gt;close()&lt;/code&gt; 메서드를 두고, 객체 사용이 끝나는 시점에서 명시적으로 호출하는 방식을 더 선호한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 설명&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;자동 리소스 관리&lt;/b&gt;: &lt;code&gt;try-with-resources&lt;/code&gt; 구문 등을 사용하면 &lt;code&gt;AutoCloseable&lt;/code&gt; 인터페이스를 구현한 객체는 스코프를 벗어날 때 &lt;code&gt;close()&lt;/code&gt;가 자동 호출되어 편리하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GC(가비지 컬렉션)&lt;/b&gt;: 자바는 사용하는 메모리를 계속 추적하다가 필요 없다고 판단되면, 자동으로 회수한다. 따라서 개발자가 직접 메모리를 해제할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론 및 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;오버로딩&lt;/b&gt;을 통해 생성자를 다양하게 정의하여 여러 초기화 방식을 제공할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본값 초기화&lt;/b&gt;는 편리하지만, 필요 시 &lt;b&gt;명시적 초기화&lt;/b&gt;나 &lt;b&gt;생성자&lt;/b&gt;에서 로직을 정의해야 예기치 못한 오류를 방지할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매개변수 없는 생성자&lt;/b&gt;는 인자가 없을 때의 기본 상태를 정의하는 좋은 수단이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명시적 필드 초기화&lt;/b&gt;와 &lt;b&gt;초기화 블럭&lt;/b&gt;을 통해 생성자가 여러 개여도 공통 초기화 로직을 간편하게 처리할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다른 생성자 호출(&lt;code&gt;this(...)&lt;/code&gt;)&lt;/b&gt;을 활용하면, 코드 중복을 줄이고 일관된 초기화 방식을 유지할 수 있다.&lt;/li&gt;
&lt;li&gt;자바에서는 &lt;b&gt;소멸자&lt;/b&gt; 대신, 가비지 컬렉션과 &lt;code&gt;close()&lt;/code&gt;와 같은 &lt;b&gt;명시적 자원 해제&lt;/b&gt; 방식을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/18&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 4.7 레코드&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484882085&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.7 레코드&quot; data-og-description=&quot;4.7 레코드(Records)때때로 객체 지향 프로그래밍이 제공하는 데이터 은닉(캡슐화)이 오히려 방해가 될 때가 있다. 예를 들어, 평면에서 좌표를 나타내기 위한 Point 클래스를 생각해보자. 보통은 다&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/18&quot; data-og-url=&quot;https://choosla.tistory.com/18&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jTekP/hyYm2FDAfQ/VqwbBbuQmFikJ3cecicixk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hmlvV/hyYnesAJaV/WKcYbirSvkdXmFg14sqyOK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/18&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/18&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jTekP/hyYm2FDAfQ/VqwbBbuQmFikJ3cecicixk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hmlvV/hyYnesAJaV/WKcYbirSvkdXmFg14sqyOK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.7 레코드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.7 레코드(Records)때때로 객체 지향 프로그래밍이 제공하는 데이터 은닉(캡슐화)이 오히려 방해가 될 때가 있다. 예를 들어, 평면에서 좌표를 나타내기 위한 Point 클래스를 생각해보자. 보통은 다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>객체생성</category>
      <category>생성자</category>
      <category>오버로딩</category>
      <category>자바</category>
      <category>초기화블록</category>
      <category>코어자바</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/17</guid>
      <comments>https://choosla.tistory.com/17#entry17comment</comments>
      <pubDate>Sat, 8 Mar 2025 20:26:02 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.5 메소드 매개변수</title>
      <link>https://choosla.tistory.com/16</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.4 정적 필드와 메소드&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484717350&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.4 정적 필드와 메소드&quot; data-og-description=&quot;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&amp;nbsp;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기2025.03.08 - [Core Java/Chapter 4] - 코&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/15&quot; data-og-url=&quot;https://choosla.tistory.com/15&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XMxzn/hyYq0MX4RV/KUWKlgi9jW2SmhsCkuGJbK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gkhDq/hyYm7G1yzo/MsvZxhVVXEjJbUzafCbsf0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/15&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XMxzn/hyYq0MX4RV/KUWKlgi9jW2SmhsCkuGJbK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gkhDq/hyYm7G1yzo/MsvZxhVVXEjJbUzafCbsf0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.4 정적 필드와 메소드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&amp;nbsp;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기2025.03.08 - [Core Java/Chapter 4] - 코&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 자바의 메소드 파라미터 전달 방식 (Call by Value vs Reference) ]&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.5 메소드 매개변수 (Method Parameters)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바와 같은 프로그래밍 언어에서 메소드(또는 함수)의 매개변수가 호출될 때 어떻게 전달되는지 살펴보자. 이것을 이해하기 위해서는 &lt;b&gt;call by value&lt;/b&gt;와 &lt;b&gt;call by reference&lt;/b&gt;라는 두 가지 컴퓨터 과학 용어를 먼저 알아야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;call by value&lt;/b&gt;: 호출자(caller)가 제공하는 값 자체를 메소드에게 전달하는 방식이다. 즉, 메소드는 전달받은 값의 복사본을 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;call by reference&lt;/b&gt;: 호출자가 제공하는 변수의 &amp;lsquo;주소값&amp;rsquo;을 메소드에게 전달하는 방식이다. 즉, 메소드는 원본 변수(메모리 주소)에 직접 접근하여 그 값을 수정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;call by value&lt;/code&gt;로 전달된 변수는 복사본이 넘어가기 때문에 원본에 영향을 줄 수 없고, &lt;code&gt;call by reference&lt;/code&gt; 방식이라면 메소드 내부에서 원본 변수를 직접 수정할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바의 메소드 매개변수 전달 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 언어는 &lt;b&gt;항상 &lt;code&gt;call by value&lt;/code&gt;&lt;/b&gt; 방식을 사용한다. 메소드는 매개변수로 넘어온 값을 복사해서 사용하기 때문에, 원본 변수 자체를 메소드가 수정할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 아래 코드를 보자.&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;double percent = 10;
harry.raiseSalary(percent);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;code&gt;raiseSalary&lt;/code&gt; 메소드를 호출해도, 메소드가 어떻게 구현되어 있든 상관없이 &lt;code&gt;percent&lt;/code&gt; 변수 자체는 여전히 10인 상태를 유지한다. 왜냐하면 자바에서는 &lt;code&gt;call by value&lt;/code&gt; 방식을 사용하기 때문에, &lt;code&gt;raiseSalary&lt;/code&gt; 메소드가 받은 것은 &lt;code&gt;percent&lt;/code&gt; 값의 복사본(10)일 뿐이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;기본 타입에 대한 예시&lt;/h4&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public static void tripleValue(double x) // 작동하지 않는다.
{
    x = x * 3;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 메소드는 &lt;code&gt;x&lt;/code&gt; 값을 세 배로 만들지만, 매개변수 &lt;code&gt;x&lt;/code&gt;는 호출 시 전달된 원본의 복사본이므로 원본 변수에는 전혀 영향을 주지 않는다. 실제 호출 예시는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;double percent = 10;
tripleValue(percent);&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메소드가 실행되면 &lt;code&gt;x&lt;/code&gt;는 &lt;code&gt;percent&lt;/code&gt; 값(10)의 복사본으로 초기화됨.&lt;/li&gt;
&lt;li&gt;메소드 내부에서 &lt;code&gt;x&lt;/code&gt;가 30이 되지만, 이는 복사본에만 해당.&lt;/li&gt;
&lt;li&gt;메소드가 종료되면 &lt;code&gt;x&lt;/code&gt;는 사라지고, &lt;code&gt;percent&lt;/code&gt;는 여전히 10.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;code&gt;percent&lt;/code&gt; 값 자체는 변화하지 않는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체 참조의 경우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 메소드 파라미터는 크게 두 가지 유형으로 나눌 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;기본 타입&lt;/b&gt; (숫자, &lt;code&gt;boolean&lt;/code&gt; 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체 참조&lt;/b&gt; (클래스 타입 등)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 살펴보았듯이, 기본 타입 매개변수의 원본 값을 변경할 수는 없다. 하지만 &lt;b&gt;객체 참조&lt;/b&gt;의 경우, 객체가 저장된 주소값(참조)을 복사해서 넘기므로, 그 참조가 가리키는 &lt;b&gt;객체 자체&lt;/b&gt;의 상태를 수정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;code&gt;Employee&lt;/code&gt; 객체의 급여를 세 배로 인상하는 메소드를 작성해 보자.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public static void tripleSalary(Employee x) {
    x.raiseSalary(200); // 급여를 200% 인상 -&amp;gt; 결과적으로 3배가 됨
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 호출한다고 가정하면,&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Employee harry = new Employee(...);
tripleSalary(harry);&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;는 &lt;code&gt;harry&lt;/code&gt;가 가지고 있는 객체 참조(주소)의 복사본으로 초기화됨.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x.raiseSalary(200)&lt;/code&gt;를 호출하면, &lt;code&gt;x&lt;/code&gt;와 &lt;code&gt;harry&lt;/code&gt;가 동일한 &lt;code&gt;Employee&lt;/code&gt; 객체를 참조하고 있으므로 해당 객체의 급여가 3배로 인상됨.&lt;/li&gt;
&lt;li&gt;메소드가 종료되면 &lt;code&gt;x&lt;/code&gt;는 사라지지만, &lt;code&gt;harry&lt;/code&gt;가 참조하는 객체는 이미 수정된 상태를 유지.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIEDyd/btsMFgnWmdc/fbHhfDxokcIecje6k3Wh70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIEDyd/btsMFgnWmdc/fbHhfDxokcIecje6k3Wh70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIEDyd/btsMFgnWmdc/fbHhfDxokcIecje6k3Wh70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIEDyd%2FbtsMFgnWmdc%2FfbHhfDxokcIecje6k3Wh70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;427&quot; height=&quot;500&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;객체의 상태&lt;/b&gt;는 수정 가능하지만, 원본 변수(&lt;code&gt;harry&lt;/code&gt;)가 다른 객체를 가리키도록 만드는 것은 불가능하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바는 &lt;code&gt;call by reference&lt;/code&gt;를 지원하지 않는다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바가 객체 참조를 매개변수로 넘길 때, 이를 &amp;ldquo;자바는 &lt;code&gt;call by reference&lt;/code&gt;를 사용한다&amp;rdquo;고 오해하기 쉽다. 그러나 자바는 &lt;b&gt;언제나 &lt;code&gt;call by value&lt;/code&gt;&lt;/b&gt; 방식이다. 다만, &lt;b&gt;값&lt;/b&gt;으로 넘어가는 것이 객체의 &lt;b&gt;주소&lt;/b&gt;이기 때문에, 객체 내부 상태가 수정되는 효과가 나타날 뿐이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;code&gt;swap&lt;/code&gt; 메소드 예시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예시는 두 &lt;code&gt;Employee&lt;/code&gt; 객체를 서로 교환(swap)하는 메소드를 작성해 보려는 상황이다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;public static void swap(Employee x, Employee y) {
    Employee tmp = x;
    x = y;
    y = tmp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 메소드를 다음과 같이 호출한다고 해보자.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;var a = new Employee(&quot;Alice&quot;, ...);
var b = new Employee(&quot;Bob&quot;, ...);
swap(a, b);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o8fFp/btsMEoN5HnU/7tAKGUzigrWp4dXGIMnq61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o8fFp/btsMEoN5HnU/7tAKGUzigrWp4dXGIMnq61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o8fFp/btsMEoN5HnU/7tAKGUzigrWp4dXGIMnq61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo8fFp%2FbtsMEoN5HnU%2F7tAKGUzigrWp4dXGIMnq61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;631&quot; height=&quot;395&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 자바가 진짜 &lt;code&gt;call by reference&lt;/code&gt;를 사용했다면 &lt;code&gt;a&lt;/code&gt;와 &lt;code&gt;b&lt;/code&gt;의 값이 바뀌어야 한다. 하지만 실제로는 &lt;b&gt;바뀌지 않는다&lt;/b&gt;.&lt;br /&gt;이는 &lt;code&gt;x&lt;/code&gt;와 &lt;code&gt;y&lt;/code&gt;가 &lt;code&gt;a&lt;/code&gt;와 &lt;code&gt;b&lt;/code&gt;의 객체 참조를 &lt;b&gt;복사&lt;/b&gt;해 온 것이기 때문이다. &lt;code&gt;swap&lt;/code&gt; 메소드 내부에서는 &lt;code&gt;x&lt;/code&gt;와 &lt;code&gt;y&lt;/code&gt;가 가리키는 객체 참조를 교환할 뿐, 원본 변수 &lt;code&gt;a&lt;/code&gt;와 &lt;code&gt;b&lt;/code&gt;는 아무런 영향을 받지 않는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리: 자바에서 메소드 매개변수로 할 수 있는 것과 없는 것&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;할 수 없는 것(기본 타입 변경):&lt;/b&gt; 기본 타입(숫자, &lt;code&gt;boolean&lt;/code&gt; 등) 매개변수를 변경해도 원본 변수에 영향을 줄 수 없다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;할 수 있는 것(객체 상태 변경):&lt;/b&gt; 객체 매개변수라면, 객체의 내부 상태를 변경할 수 있다(같은 객체를 참조하므로).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;할 수 없는 것(참조 변경):&lt;/b&gt; 메소드 내부에서 파라미터를 다른 객체로 가리키도록 변경해도, 원본 변수는 그대로다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 자바에서는 매개변수로 &lt;b&gt;값&lt;/b&gt;을 넘긴다. 기본 타입이면 값(예: 10) 자체가 복사되고, 객체 타입이면 객체의 주소값이 복사되어 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 4.6 객체 생성&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484780921&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.6 객체 생성&quot; data-og-description=&quot;4.6 객체 생성(Object Construction)객체(object)가 생성될 때, 자바(Java)에서는 다양한 방법으로 필드 초기화와 생성자 호출이 이루어진다. 어떤 경우든 객체가 만들어질 때 내부 상태가 어떻게 결정되는&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/17&quot; data-og-url=&quot;https://choosla.tistory.com/17&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rftFU/hyYm9kxGmu/ugHPobYiKDLTJkX0BQ0sQ1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4cpZZ/hyYm1z1anW/eFFfRyqZvRGcK0u8pDYn2K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/17&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rftFU/hyYm9kxGmu/ugHPobYiKDLTJkX0BQ0sQ1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/b4cpZZ/hyYm1z1anW/eFFfRyqZvRGcK0u8pDYn2K/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.6 객체 생성&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.6 객체 생성(Object Construction)객체(object)가 생성될 때, 자바(Java)에서는 다양한 방법으로 필드 초기화와 생성자 호출이 이루어진다. 어떤 경우든 객체가 만들어질 때 내부 상태가 어떻게 결정되는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>callbyreference</category>
      <category>callbyvalue</category>
      <category>메서드파라미터</category>
      <category>자바</category>
      <category>코딩공부</category>
      <category>코어자바</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/16</guid>
      <comments>https://choosla.tistory.com/16#entry16comment</comments>
      <pubDate>Sat, 8 Mar 2025 20:05:41 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.4 정적 필드와 메소드</title>
      <link>https://choosla.tistory.com/15</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484527685&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&quot; data-og-description=&quot;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.2 표준 라이브러리 클래스 사용하기&amp;nbsp;4.2 표준 라이브러리 클래스 사용하기4.2 표준 라이브러리 클래스 사용하기(Using Predefined Cla&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/14&quot; data-og-url=&quot;https://choosla.tistory.com/14&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oJMvF/hyYqaPONgI/fOgwiKmGsRpSqAOwka899K/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/LYG8u/hyYq0zljwc/c6zl0LliOnf3Sg3UkmwqK1/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/ggGs0/hyYqQ4EOpx/uKhrKovHkxZRnEz1hwsBcK/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/14&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oJMvF/hyYqaPONgI/fOgwiKmGsRpSqAOwka899K/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/LYG8u/hyYq0zljwc/c6zl0LliOnf3Sg3UkmwqK1/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/ggGs0/hyYqQ4EOpx/uKhrKovHkxZRnEz1hwsBcK/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.2 표준 라이브러리 클래스 사용하기&amp;nbsp;4.2 표준 라이브러리 클래스 사용하기4.2 표준 라이브러리 클래스 사용하기(Using Predefined Cla&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 정적 필드와 메서드(Static): Math 예제부터 main 메서드까지 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.4 정적 필드와 메소드(Static Fields and Methods)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Employee&lt;/code&gt; 클래스에서 보듯이, 자바 프로그램의 진입점인 &lt;b&gt;main 메소드&lt;/b&gt;는 &lt;code&gt;static&lt;/code&gt; 수정자로 선언된다. 이 장에서는 &lt;code&gt;static&lt;/code&gt; 수정자가 붙은 필드와 메소드에 대해 자세히 알아본다. &lt;code&gt;static&lt;/code&gt; 구성요소는 객체에 속하지 않고 클래스 자체에 속하므로, 해당 클래스의 모든 인스턴스가 공유하는 단 하나의 복사본만 존재한다는 점이 핵심이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4.1 정적(Static) 필드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 필드(&lt;code&gt;static&lt;/code&gt; field)는 클래스에 소속되며, 해당 클래스의 모든 객체가 공유하는 단일 변수를 의미한다. 예를 들어, 각 &lt;code&gt;Employee&lt;/code&gt; 객체는 고유의 &lt;code&gt;id&lt;/code&gt; 값을 가져야 하지만, 새로운 &lt;code&gt;id&lt;/code&gt;를 생성하기 위한 기준 값은 모든 객체가 공유하는 &lt;code&gt;static&lt;/code&gt; 필드로 관리할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;// Employee 클래스 예제
class Employee {
    // 모든 Employee 객체가 공유하는 정적 필드 (초기값 1)
    private static int nextId = 1;

    // 각 Employee 객체마다 개별적으로 존재하는 인스턴스 필드
    private int id;

    // 생성자에서 새로운 id를 할당하고, 다음 id 값을 증가시킴
    public Employee() {
        id = nextId;
        nextId++;  // 다음 Employee 객체를 위해 nextId를 증가시킴
    }

    // id 값을 반환하는 메소드
    public int getId() {
        return id;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제에서 모든 &lt;code&gt;Employee&lt;/code&gt; 객체는 자신만의 &lt;code&gt;id&lt;/code&gt; 인스턴스 필드를 가지지만, &lt;code&gt;nextId&lt;/code&gt;는 단 하나만 존재하여 새로운 객체가 생성될 때마다 고유한 &lt;code&gt;id&lt;/code&gt; 값을 제공한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4.2 정적 상수(Static Constants)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 변수 중에서도 상수는 변경될 수 없는 값을 의미하며, 자주 사용된다. 대표적인 예가 &lt;code&gt;Math&lt;/code&gt; 클래스의 PI 상수이다. 상수를 선언할 때는 한 번 초기화된 이후에는 값이 변경되지 않도록 &lt;code&gt;final&lt;/code&gt; 키워드를 함께 사용한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Math {
    // Math 클래스 내에서 유일하게 존재하는 PI 상수 (모든 객체가 공유)
    public static final double PI = 3.141592653589793;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 예로, &lt;code&gt;System&lt;/code&gt; 클래스의 &lt;code&gt;out&lt;/code&gt; 필드는 정적 상수로 선언되어 있다. 이처럼 &lt;code&gt;public&lt;/code&gt; 상수(&lt;code&gt;final&lt;/code&gt; 필드)는 외부에서 접근은 가능하지만 재할당이 불가능하기 때문에 안전하게 사용할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4.3 정적 메소드 (Static Methods)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 메소드는 객체에 종속되지 않고 클래스에 소속된 메소드이다. 따라서, 객체를 생성하지 않고도 호출할 수 있으며, 메소드 내에서는 &lt;code&gt;this&lt;/code&gt; 키워드를 사용할 수 없다. 예를 들어, &lt;code&gt;Math&lt;/code&gt; 클래스의 &lt;code&gt;pow&lt;/code&gt; 메소드는 &lt;code&gt;static&lt;/code&gt; 메소드로, &lt;code&gt;Math&lt;/code&gt; 객체를 생성할 필요 없이 바로 호출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;code&gt;Employee&lt;/code&gt; 클래스에서도 &lt;code&gt;static&lt;/code&gt; 메소드를 활용할 수 있다. 다만, &lt;code&gt;static&lt;/code&gt; 메소드는 인스턴스 필드에는 접근할 수 없고 오직 &lt;code&gt;static&lt;/code&gt; 필드에만 접근할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;class Employee {
    private static int nextId = 1;
    private int id;

    public Employee() {
        id = nextId;
        nextId++;
    }

    // 정적 메소드로, nextId 값을 증가시키고 반환함
    public static int advanceId() {
        int r = nextId;  // static 필드 nextId에 접근
        nextId++;
        return r;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 정적 메소드는 다음 두 가지 경우에 주로 사용된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;객체 상태에 의존하지 않는 경우:&lt;/b&gt; 메소드의 모든 파라미터가 명시적으로 제공되어 객체의 상태에 접근할 필요가 없을 때 (예: &lt;code&gt;Math.pow&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클래스의 정적 필드에만 접근할 필요가 있을 때:&lt;/b&gt; 객체 생성 없이 클래스에 소속된 필드만을 사용해야 할 때 (예: &lt;code&gt;Employee.advanceId&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4.4 Factory 메소드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;static&lt;/code&gt; 메소드는 또한 Factory 메소드로 사용된다. Factory 메소드는 객체 생성과 관련된 로직을 캡슐화하여, 생성자 대신 메소드를 통해 다양한 방식의 객체를 반환할 수 있도록 한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// NumberFormat 클래스를 통한 객체 생성 예제
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentInstance();

double x = 0.1;
System.out.println(currencyFormatter.format(x));  // 예: $0.10 출력
System.out.println(percentFormatter.format(x));     // 예: 10% 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Factory 메소드를 사용하는 이유는 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;생성자의 한계 극복:&lt;/b&gt; 생성자의 이름은 항상 클래스 이름과 같기 때문에, 서로 다른 기능을 하는 생성자를 구분하기 어렵다. 그러나 Factory 메소드는 각기 다른 이름을 사용할 수 있어, 생성되는 객체의 역할을 명확하게 표현할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반환 타입의 다양성:&lt;/b&gt; 생성자를 사용하면 반환되는 객체의 타입이 항상 고정되지만, Factory 메소드는 상속 관계에 있는 다른 타입의 객체를 반환할 수 있다. 예를 들어, &lt;code&gt;NumberFormat&lt;/code&gt; 클래스의 Factory 메소드는 내부적으로 &lt;code&gt;DecimalFormat&lt;/code&gt; 객체를 반환할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4.5 main 메소드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 자바 프로그램의 시작점은 &lt;b&gt;main 메소드&lt;/b&gt;이다. &lt;code&gt;main&lt;/code&gt; 메소드는 &lt;code&gt;static&lt;/code&gt; 메소드로 선언되어 있으며, 객체 생성 없이 호출되므로 프로그램 실행 시 가장 먼저 실행되는 메소드이다. 따라서, &lt;code&gt;main&lt;/code&gt; 메소드 내부에서는 다른 객체들을 생성하거나 프로그램의 전반적인 흐름을 제어하는 역할을 수행한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Application {
    // 프로그램의 진입점인 main 메소드 (static 메소드)
    public static void main(String[] args) {
        // 객체 생성 및 프로그램 실행 로직 시작
        // 예: Employee 객체 생성
        Employee emp = new Employee();
        System.out.println(&quot;새로운 직원의 id: &quot; + emp.getId());

        // 필요한 추가 로직 작성
        // ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;main&lt;/code&gt; 메소드는 프로그램 실행 초기에 어떠한 객체도 생성되지 않은 상태에서 호출되므로, &lt;code&gt;static&lt;/code&gt; 메소드의 특성을 잘 활용하여 초기 설정이나 리소스 할당 등을 수행한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 &lt;code&gt;static&lt;/code&gt; 필드와 메소드, 그리고 Factory 메소드와 &lt;code&gt;main&lt;/code&gt; 메소드에 대한 개념은 객체 지향 프로그래밍에서 클래스와 객체 간의 관계를 보다 명확하게 이해하는 데 매우 중요한 역할을 한다. 티스토리 블로그에 이 내용을 게시할 때는 각 섹션별로 제목과 코드 예제를 함께 제시하여 독자들이 이론과 실습을 병행하면서 학습할 수 있도록 구성하면 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용은 노션의 원본 텍스트의 모든 핵심 사항을 그대로 유지하면서도 문맥이 자연스럽게 이어지도록 다듬은 것이다. 추가 설명을 통해 독자들이 &lt;code&gt;static&lt;/code&gt; 관련 개념을 보다 명확하게 이해할 수 있도록 구성하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 4.5 메소드 매개변수&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484668710&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.5 메소드 매개변수&quot; data-og-description=&quot;4.5 메소드 매개변수 (Method Parameters)자바와 같은 프로그래밍 언어에서 메소드(또는 함수)의 매개변수가 호출될 때 어떻게 전달되는지 살펴보자. 이것을 이해하기 위해서는 call by value와 call by refer&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/16&quot; data-og-url=&quot;https://choosla.tistory.com/16&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bAuckt/hyYmYQNRan/keQvQsnNa5Iv9fDForuuVk/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/tsvvI/hyYmNBJU5v/zotUvB1MJxN4SmaeTRpMS0/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/EtuM5/hyYmU8JeUZ/JJHLxFPkf2yx3d1pJRIk90/img.png?width=631&amp;amp;height=395&amp;amp;face=0_0_631_395&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/16&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bAuckt/hyYmYQNRan/keQvQsnNa5Iv9fDForuuVk/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/tsvvI/hyYmNBJU5v/zotUvB1MJxN4SmaeTRpMS0/img.png?width=427&amp;amp;height=500&amp;amp;face=0_0_427_500,https://scrap.kakaocdn.net/dn/EtuM5/hyYmU8JeUZ/JJHLxFPkf2yx3d1pJRIk90/img.png?width=631&amp;amp;height=395&amp;amp;face=0_0_631_395');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.5 메소드 매개변수&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.5 메소드 매개변수 (Method Parameters)자바와 같은 프로그래밍 언어에서 메소드(또는 함수)의 매개변수가 호출될 때 어떻게 전달되는지 살펴보자. 이것을 이해하기 위해서는 call by value와 call by refer&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>static</category>
      <category>자바</category>
      <category>정적메서드</category>
      <category>정적필드</category>
      <category>코어자바</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/15</guid>
      <comments>https://choosla.tistory.com/15#entry15comment</comments>
      <pubDate>Sat, 8 Mar 2025 19:41:12 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기</title>
      <link>https://choosla.tistory.com/14</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.2 표준 라이브러리 클래스 사용하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484288747&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.2 표준 라이브러리 클래스 사용하기&quot; data-og-description=&quot;4.2 표준 라이브러리 클래스 사용하기(Using Predefined Classes)자바에서는 미리 정의된 표준 라이브러리 클래스(Predefined Classes)를 제공하며, 이를 통해 개발자는 직접 구현하지 않아도 다양한 기능을 &quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/13&quot; data-og-url=&quot;https://choosla.tistory.com/13&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b214PY/hyYqTNQwQ5/xaaHMdoDGUkjWkPvwLDgk1/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/fd6o3/hyYqRCviNG/xgzm9lJZLLKa3SNDK5PAGk/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/dIGMPc/hyYmNV2q4Q/uZUkgpsOYR0FkUfcFuIkd0/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/13&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b214PY/hyYqTNQwQ5/xaaHMdoDGUkjWkPvwLDgk1/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/fd6o3/hyYqRCviNG/xgzm9lJZLLKa3SNDK5PAGk/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/dIGMPc/hyYmNV2q4Q/uZUkgpsOYR0FkUfcFuIkd0/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.2 표준 라이브러리 클래스 사용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.2 표준 라이브러리 클래스 사용하기(Using Predefined Classes)자바에서는 미리 정의된 표준 라이브러리 클래스(Predefined Classes)를 제공하며, 이를 통해 개발자는 직접 구현하지 않아도 다양한 기능을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ Employee 예제로 배우는 나만의 클래스 설계 방법 ]&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.3 자신만의 클래스 정의하기(Defining Your Own Classes)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 복잡한 프로그램을 만들기 위해서는 중추가 되는 클래스와 같은 요소들을 설계하는 방법을 알아야 한다. 이러한 클래스들은 대개 &lt;code&gt;main&lt;/code&gt; 메소드가 없으며, 자체적인 인스턴스 필드와 메소드를 가진다. 프로그램을 완성할 때 여러 클래스를 조합하고 그 중 한 클래스에 &lt;code&gt;main&lt;/code&gt; 메소드를 두어 전체 실행 흐름을 제어한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.1 Employee 클래스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 가장 기본적인 형태는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class 클래스이름 {
    필드1;
    필드2;
    ...
    생성자1;
    생성자2;
    ...
    메소드1;
    메소드2;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 형식에 맞춰 회사에서 사용되는 급여 시스템에 대한 가장 단순한 버전의 &lt;code&gt;Employee&lt;/code&gt; 클래스를 작성해보자.&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;class Employee {
    // 인스턴스 필드
    private String name;
    private double salary;
    private LocalDate hireDay;

    // 생성자
    public Employee(String n, double s, int year, int month, int day) {
        name = n;
        salary = s;
        hireDay = LocalDate.of(year, month, day);
    }

    // 메소드
    public String getName() {
        return name;
    }

    // 더 많은 메소드들
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램에서는 &lt;code&gt;Employee&lt;/code&gt; 객체로 채워진 배열을 다음과 같이 생성할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;Employee[] staff = new Employee[3];

staff[0] = new Employee(&quot;A&quot;, ... );
staff[1] = new Employee(&quot;B&quot;, ... );
staff[2] = new Employee(&quot;C&quot;, ... );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 for-each 문을 사용하여 각 사원의 이름을 출력할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;for (Employee e : staff) {
    System.out.println(e.getName() + &quot; 사원님&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;(컴파일에 관한 추가 정보는 나중에 다루기로 한다.)&lt;/i&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.3 Employee 클래스 분석하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스를 분석하기 전에 &lt;code&gt;Employee&lt;/code&gt; 클래스의 전체 코드는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.time.*;

// 이 프로그램은 Employee(직원) 클래스를 테스트하는 코드이다.
public class EmployeeTest {
    public static void main(String[] args) {
        // 직원 정보를 저장할 배열 생성 (3명의 직원)
        Employee[] staff = new Employee[3];

        // 직원 배열에 Employee 객체를 생성하여 추가
        staff[0] = new Employee(&quot;Carl Cracker&quot;, 75000, 1987, 12, 15);
        staff[1] = new Employee(&quot;Harry Hacker&quot;, 50000, 1989, 10, 1);
        staff[2] = new Employee(&quot;Tony Tester&quot;, 40000, 1990, 3, 15);

        // 모든 직원의 급여를 5% 인상
        for (Employee e : staff) {
            e.raiseSalary(5);
        }

        // 직원 정보 출력
        for (Employee e : staff) {
            System.out.println(&quot;이름=&quot; + e.getName() +
                               &quot;, 급여=&quot; + e.getSalary() +
                               &quot;, 입사일=&quot; + e.getHireDay());
        }
    }
}

// Employee 클래스: 직원 정보를 저장하고 관리
class Employee {
    private String name;       // 직원 이름
    private double salary;     // 급여
    private LocalDate hireDay; // 입사일

    // 생성자 - 직원 정보 초기화
    public Employee(String n, double s, int year, int month, int day) {
        name = n;
        salary = s;
        hireDay = LocalDate.of(year, month, day);
    }

    // 직원 이름 반환
    public String getName() {
        return name;
    }

    // 직원 급여 반환
    public double getSalary() {
        return salary;
    }

    // 직원 입사일 반환
    public LocalDate getHireDay() {
        return hireDay;
    }

    // 급여를 특정 퍼센트만큼 인상
    public void raiseSalary(double byPercent) {
        double raise = salary * byPercent / 100;
        salary += raise;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, &lt;code&gt;Employee&lt;/code&gt; 클래스는 하나의 생성자와 네 개의 메소드로 구성되어 있다.&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public Employee(String n, double s, int year, int month, int day)
public String getName()
public double getSalary()
public LocalDate getHireDay()
public void raiseSalary(double byPercent)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 메소드에는 &lt;code&gt;public&lt;/code&gt; 키워드가 붙어 있어, 어떤 클래스에서든 호출이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;code&gt;Employee&lt;/code&gt; 객체의 내부 데이터는 다음과 같은 세 개의 인스턴스 필드에 저장된다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;private String name;
private double salary;
private LocalDate hireDay;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;private&lt;/code&gt; 키워드는 오직 &lt;code&gt;Employee&lt;/code&gt; 클래스 내부의 메소드만 이 필드들에 접근할 수 있음을 의미한다. 외부에서는 읽거나 쓸 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의:&lt;/b&gt; 인스턴스 필드를 &lt;code&gt;public&lt;/code&gt;으로 선언하는 것은 캡슐화를 완전히 깨뜨릴 수 있으므로 강력히 권장하지 않는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.4 생성자에 대해서&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Employee&lt;/code&gt; 클래스의 생성자를 보면 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public Employee(String n, double s, int year, int month, int day) {
    name = n;
    salary = s;
    hireDay = LocalDate.of(year, month, day);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드에서 보듯이, 생성자의 이름은 클래스 이름과 동일하며, 객체가 생성될 때 인스턴스 필드를 초기화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 다음과 같이 &lt;code&gt;Employee&lt;/code&gt; 객체를 생성할 경우&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;new Employee(&quot;A&quot;, 100000, 1999, 1, 21)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자는 아래와 같이 인스턴스 필드를 초기화한다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;name    = &quot;A&quot;
salary  = 100000
hireDay = LocalDate.of(1999, 1, 21)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자와 다른 메소드의 중요한 차이점은, 생성자는 반드시 &lt;code&gt;new&lt;/code&gt; 연산자와 함께 호출되어야 하며, 이미 존재하는 객체의 필드를 초기화하는 용도로는 사용할 수 없다는 점이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;A.Employee(&quot;B&quot;, 250000, 2000, 12, 31) // 컴파일 에러 발생!&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.5 Var 변수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 언어들처럼 특정 타입을 명시하지 않고 저장할 수 있는 로컬 변수인 &lt;code&gt;var&lt;/code&gt; 변수가 Java 10부터 지원된다. &lt;code&gt;var&lt;/code&gt; 변수는 초기 주어진 값에 따라 타입이 결정된다.&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;Employee harry = new Employee(&quot;Harry&quot;, 50000, 1989, 10, 1);

var harry = new Employee(&quot;Harry&quot;, 50000, 1989, 10, 1);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 타입 이름인 &lt;code&gt;Employee&lt;/code&gt;의 반복 사용을 줄이기 위해 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, Java API의 추가적인 지식 없이 오른쪽에 나타나는 타입만으로 유추할 수 있는 경우에 사용하는 것이 좋으며, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;long&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt; 등의 숫자 타입에는 가독성을 위해 사용하지 않는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;code&gt;var&lt;/code&gt; 키워드는 메소드 내부의 로컬 변수에만 사용할 수 있고, 메소드의 파라미터나 필드에는 사용할 수 없다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.6 null 참조 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;code&gt;null&lt;/code&gt; 값에 대해 메소드를 실행하면 &lt;code&gt;NullPointerException&lt;/code&gt;이 발생한다.&lt;/p&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;LocalDate rightNow = null;
String s = rightNow.toString(); // NullPointerException 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &amp;ldquo;배열 범위 초과(index out of bounds)&amp;rdquo;와 같이 매우 심각한 에러로, 예외를 적절히 처리하지 않으면 프로그램이 종료된다. 일반적으로 프로그램은 이러한 종류의 예외를 직접 처리하기보다는, 처음부터 예외가 발생하지 않도록 설계하는 것에 의존한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스를 설계할 때, 어떤 필드가 &lt;code&gt;null&lt;/code&gt;이 될 수 있는지를 명확히 하는 것이 중요하다. 예를 들어, &lt;code&gt;name&lt;/code&gt;이나 &lt;code&gt;hireDay&lt;/code&gt; 필드가 &lt;code&gt;null&lt;/code&gt;이 되는 것을 원하지 않는다면, &lt;code&gt;Objects&lt;/code&gt; 클래스에서 제공하는 메소드를 활용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public Employee(String n, double s, int year, int month, int day) {
    name = Objects.requireNonNullElse(n, &quot;unknown&quot;);
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 보다 강경하게 &lt;code&gt;null&lt;/code&gt; 인수를 거부할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public Employee(String n, double s, int year, int month, int day) {
    name = Objects.requireNonNull(n, &quot;이름은 null이 될 수 없습니다.&quot;);
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;null&lt;/code&gt; 값으로 &lt;code&gt;Employee&lt;/code&gt; 객체가 생성되면 &lt;code&gt;NullPointerException&lt;/code&gt;이 발생하며, 이는 예외 리포트에서 문제의 설명과 발생 위치를 명확히 알 수 있게 해준다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.7 묵시적(Implicit)과 명시적(Explicit) 파라미터&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메소드는 객체 내에서 동작하며 인스턴스 필드에 접근한다. 예를 들어,&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;public void raiseSalary(double byPercent) {
    double raise = salary * byPercent / 100;
    salary += raise;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 메소드가 실행될 때, &lt;code&gt;salary&lt;/code&gt; 인스턴스 필드의 값이 변경된다.&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;number007.raiseSalary(5);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 &lt;code&gt;number007&lt;/code&gt; 객체의 &lt;code&gt;salary&lt;/code&gt; 필드 값을 5% 증가시킨다. 보다 자세히 표현하면,&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;double raise = number007.salary * 5 / 100;
number007.salary += raise;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;code&gt;raiseSalary&lt;/code&gt; 메소드는 두 개의 파라미터를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 첫 번째 파라미터는 묵시적 파라미터로, 메소드 이름 앞에 암시적으로 존재하는 &lt;code&gt;Employee&lt;/code&gt; 객체(여기서는 &lt;code&gt;number007&lt;/code&gt;)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 두 번째 파라미터는 메소드 선언 시 괄호 안에 명시적으로 선언된 숫자 값이다. 이것이 명시적 파라미터이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 메소드에서 &lt;code&gt;this&lt;/code&gt; 키워드는 묵시적 파라미터를 가리키며, 필요시 다음과 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public void raiseSalary(double byPercent) {
    double raise = this.salary * byPercent / 100;
    this.salary += raise;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 프로그래머들은 인스턴스 필드와 로컬 변수를 명확히 구분하기 위해 이러한 스타일을 선호한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.8 캡슐화의 장점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 &lt;code&gt;getName()&lt;/code&gt;, &lt;code&gt;getSalary()&lt;/code&gt;, &lt;code&gt;getHireDay()&lt;/code&gt; 메소드에 대한 예시이다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public String getName() {
    return name;
}
public double getSalary() {
    return salary;
}
public LocalDate getHireDay() {
    return hireDay;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들 메소드는 인스턴스 필드의 값을 단순히 반환하며, 필드 접근자(accessor)라고도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 단순히 필드를 &lt;code&gt;public&lt;/code&gt;으로 선언하는 것이 쉬워 보일 수 있으나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; &lt;code&gt;name&lt;/code&gt; 필드는 읽기 전용으로, 생성 시 정해진 이후에는 변경되지 않아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; &lt;code&gt;salary&lt;/code&gt; 필드는 읽기 전용은 아니지만, 오직 &lt;code&gt;raiseSalary&lt;/code&gt; 메소드를 통해서만 변경되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;code&gt;public&lt;/code&gt; 필드로 선언된다면, 외부의 다른 코드가 임의로 접근하여 수정할 수 있으므로, 문제 발생 시 원인을 파악하기 어려워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때로는 인스턴스 필드에 대해 getter(접근자)와 setter(변경자) 메소드를 제공하는 것이 필요하다. 즉,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; &lt;code&gt;private&lt;/code&gt; 인스턴스 필드&lt;br /&gt;&amp;bull; &lt;code&gt;public&lt;/code&gt; 접근자 메소드&lt;br /&gt;&amp;bull; &lt;code&gt;public&lt;/code&gt; 변경자 메소드&lt;br /&gt;를 제공하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 단순히 &lt;code&gt;public&lt;/code&gt; 인스턴스 필드를 제공하는 것보다 번거롭지만, 클래스 내부 구현의 변경이나 오류 검사를 용이하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의:&lt;/b&gt; 접근자 메소드가 변경 가능한 객체를 반환하는 경우 주의가 필요하다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;class Employee {
    private Date hireDay;
    ...
    public Date getHireDay() {
        return hireDay; // 변경 가능 &amp;rarr; 외부에서 hireDay를 변경할 수 있음 (BAD)
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Date&lt;/code&gt; 클래스는 &lt;code&gt;setTime&lt;/code&gt; 등의 변경자 메소드를 가지고 있으므로, 이를 그대로 반환하면 외부에서 객체의 상태를 변경할 수 있게 되어 캡슐화가 깨진다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Employee harry = ...;
Date d = harry.getHireDay();
double tenYearsInMilliseconds = 10 * 365.25 * 24 * 60 * 60 * 1000;
d.setTime(d.getTime() - (long) tenYearsInMilliseconds);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서는 &lt;code&gt;harry.hireDay&lt;/code&gt;와 &lt;code&gt;d&lt;/code&gt;가 동일한 객체를 참조하게 되어, &lt;code&gt;d&lt;/code&gt;의 상태 변화가 &lt;code&gt;harry.hireDay&lt;/code&gt;에도 영향을 준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buppOn/btsMDSvaX05/k4khqKc8kgcWQAPKLKdiU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buppOn/btsMDSvaX05/k4khqKc8kgcWQAPKLKdiU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buppOn/btsMDSvaX05/k4khqKc8kgcWQAPKLKdiU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuppOn%2FbtsMDSvaX05%2Fk4khqKc8kgcWQAPKLKdiU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;643&quot; height=&quot;359&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경 가능한 객체를 반환할 때는, 새로운 객체 복사본을 반환하도록 &lt;code&gt;clone&lt;/code&gt; 메소드를 사용하는 것이 좋다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;class Employee {
    ...
    public Date getHireDay() {
        return (Date) hireDay.clone();
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.9 클래스 기반 접근 권한&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메소드가 실행될 때, 해당 메소드는 자신이 속한 클래스의 &lt;code&gt;private&lt;/code&gt; 데이터에 접근할 수 있다. 일부 사람들은 같은 클래스에서 생성된 모든 객체들의 &lt;code&gt;private&lt;/code&gt; 데이터에 접근할 수 있다는 사실에 놀란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 두 개의 &lt;code&gt;Employee&lt;/code&gt; 객체를 다음과 같이 비교할 때,&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;class Employee {
    ...
    public boolean equals(Employee other) {
        return name.equals(other.name);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;if (harry.equals(boss)) ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 메소드는 당연히 &lt;code&gt;harry&lt;/code&gt;의 &lt;code&gt;private&lt;/code&gt; 필드에 접근하지만, 동시에 &lt;code&gt;boss&lt;/code&gt;의 &lt;code&gt;private&lt;/code&gt; 필드에도 접근한다. 이는 두 객체 모두 &lt;code&gt;Employee&lt;/code&gt; 타입이기 때문에 가능하며, &lt;code&gt;Employee&lt;/code&gt; 클래스의 메소드는 어떠한 &lt;code&gt;Employee&lt;/code&gt; 객체에 대해서도 &lt;code&gt;private&lt;/code&gt; 필드에 접근할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.10 Private 메소드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스를 구현할 때, 인스턴스 필드와 같이 외부에 노출되는 &lt;code&gt;public&lt;/code&gt; 데이터는 위험하므로 모두 &lt;code&gt;private&lt;/code&gt;으로 지정하는 것이 좋다. 그러나 메소드의 경우 대부분은 &lt;code&gt;public&lt;/code&gt;이지만, 특정 상황에서만 사용되는 도우미(helper) 메소드나 내부 계산 코드는 &lt;code&gt;public&lt;/code&gt; 인터페이스에 포함될 필요가 없다. 이러한 메소드는 클래스의 내부 구현과 밀접하게 연관되어 있고, 특정 호출 순서나 프로토콜을 필요로 할 수 있으므로 &lt;code&gt;private&lt;/code&gt;으로 구현하는 것이 최선이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메소드를 &lt;code&gt;private&lt;/code&gt;으로 선언하면, 구현하는 과정에서 해당 메소드를 외부에서 사용할 필요가 없어지며, 나중에 내부 데이터 표현 방식이 변경되더라도 영향을 받지 않고 쉽게 수정하거나 제거할 수 있다. 만약 메소드가 &lt;code&gt;public&lt;/code&gt;이면, 다른 코드에서 이를 사용하게 되어 쉽게 제거하기 어려워진다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;// 할인액 계산 (private 메소드)
private double disc(double price, double rate) {
    return price * rate / 100;
}

// 최종 가격 계산 (public 메소드)
public double finalPrice(double price, double rate) {
    return price - disc(price, rate);
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.3.11 Final 인스턴스 필드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 필드를 &lt;code&gt;final&lt;/code&gt;로 지정할 수 있다. &lt;code&gt;final&lt;/code&gt; 필드는 객체가 생성될 때 반드시 초기화되어야 하며, 모든 생성자의 종료 시점에는 값이 할당되어 있어야 한다. 한 번 설정되면 나중에 값을 변경할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;code&gt;Employee&lt;/code&gt; 클래스의 &lt;code&gt;name&lt;/code&gt; 필드는 객체 생성 후 변경되지 않으므로 &lt;code&gt;final&lt;/code&gt;로 선언된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Employee {
    private final String name;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;final&lt;/code&gt; 한정자는 기본 타입이나 불변 클래스의 필드에 특히 유용하다. (객체의 상태가 변경되지 않으면 해당 클래스는 불변하며, &lt;code&gt;String&lt;/code&gt; 클래스가 그 대표적인 예이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 변경 가능한 클래스의 경우 &lt;code&gt;final&lt;/code&gt; 한정자는 변수에 저장된 객체 참조가 다른 객체를 참조하지 않도록 보장할 뿐, 객체 내부의 상태는 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어,&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;private final StringBuilder evaluations;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 &lt;code&gt;Employee&lt;/code&gt;의 생성자에서 다음과 같이 초기화된다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;evaluations = new StringBuilder();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;code&gt;final&lt;/code&gt; 키워드는 &lt;code&gt;evaluations&lt;/code&gt; 변수가 다른 &lt;code&gt;StringBuilder&lt;/code&gt; 객체를 참조하지 않음을 보장한다. 당연히 &lt;code&gt;StringBuilder&lt;/code&gt; 객체 자체는 변경 가능하다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public void giveGoldStar() {
    evaluations.append(LocalDate.now() + &quot; : Gold Star\n&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.4 정적 필드와 메소드&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484646772&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.4 정적 필드와 메소드&quot; data-og-description=&quot;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&amp;nbsp;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기2025.03.08 - [Core Java/Chapter 4] - 코&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/15&quot; data-og-url=&quot;https://choosla.tistory.com/15&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XMxzn/hyYq0MX4RV/KUWKlgi9jW2SmhsCkuGJbK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gkhDq/hyYm7G1yzo/MsvZxhVVXEjJbUzafCbsf0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/15&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XMxzn/hyYq0MX4RV/KUWKlgi9jW2SmhsCkuGJbK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gkhDq/hyYm7G1yzo/MsvZxhVVXEjJbUzafCbsf0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.4 정적 필드와 메소드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&amp;nbsp;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기2025.03.08 - [Core Java/Chapter 4] - 코&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>OOP</category>
      <category>객체지향프로그래밍</category>
      <category>자바</category>
      <category>코어자바</category>
      <category>클래스</category>
      <category>클래스설계</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/14</guid>
      <comments>https://choosla.tistory.com/14#entry14comment</comments>
      <pubDate>Sat, 8 Mar 2025 17:25:05 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.2 표준 라이브러리 클래스 사용하기</title>
      <link>https://choosla.tistory.com/13</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.1 객체(Object)와 객체 지향 프로그래밍&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484268195&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.1 객체(Object)와 객체 지향 프로그래밍&quot; data-og-description=&quot;[객체 지향 프로그래밍 입문: 객체의 특징과 클래스 구분]객체 지향 프로그래밍(Object-oriented Programming, 이하 OOP) 개요객체 지향 프로그래밍(OOP)은 절차 지향적 프로그래밍 기법을 대체하는 새로운&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/12&quot; data-og-url=&quot;https://choosla.tistory.com/12&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/LAXdj/hyYqPEFTcU/rrTba4AMkdlUI0OSkNJMVk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gdhqZ/hyYndAsHyM/agR5gacQI8azokeGtix671/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/12&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/LAXdj/hyYqPEFTcU/rrTba4AMkdlUI0OSkNJMVk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gdhqZ/hyYndAsHyM/agR5gacQI8azokeGtix671/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.1 객체(Object)와 객체 지향 프로그래밍&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[객체 지향 프로그래밍 입문: 객체의 특징과 클래스 구분]객체 지향 프로그래밍(Object-oriented Programming, 이하 OOP) 개요객체 지향 프로그래밍(OOP)은 절차 지향적 프로그래밍 기법을 대체하는 새로운&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[ 자바 표준 라이브러리 기초 : &lt;b&gt;Date와 LocalDate 활용하기 ]&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.2 표준 라이브러리 클래스 사용하기(Using Predefined Classes)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서는 미리 정의된 &lt;b&gt;표준 라이브러리 클래스(Predefined Classes)&lt;/b&gt;를 제공하며, 이를 통해 개발자는 직접 구현하지 않아도 다양한 기능을 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, &lt;code&gt;Math&lt;/code&gt; 클래스와 같은 일부 클래스는 &lt;b&gt;내부 구현을 전혀 알 필요 없이 사용할 수 있도록 캡슐화(Encapsulation)되어 있으며&lt;/b&gt;, &lt;b&gt;객체를 생성하지 않고(static) 함수적으로만 사용할 수 있도록 설계&lt;/b&gt;되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 클래스들은 &lt;b&gt;초기화 없이 바로 사용 가능&lt;/b&gt;하며, 필요한 기능만을 제공하는 방식으로 캡슐화되어 있어 더욱 효율적으로 활용할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.2.1 객체와 객체 변수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체로 작업하기 위해서는 &lt;b&gt;객체를 설계하고 초기 상태를 특정해야 한다.&lt;/b&gt;&lt;br /&gt;자바에서는 &lt;b&gt;생성자(Constructor)&lt;/b&gt;를 사용하여 클래스를 인스턴스화하며, 이는 객체를 생성하고 초기화하는 특별한 메서드이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체 생성과 생성자의 역할&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 &lt;b&gt;객체를 생성하는 방법&lt;/b&gt;은 &lt;code&gt;new&lt;/code&gt; 키워드를 사용하여 생성자를 호출하는 것이다.&lt;br /&gt;생성자는 항상 클래스의 이름과 같으며, 객체를 초기화하는 역할을 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Date 클래스 예제&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.Date;

public class Main {
    public static void main(String[] args) {
        Date today = new Date();
        System.out.println(today);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력 결과 (실행 시점에 따라 다름)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Sat Mar 09 12:34:56 KST 2025&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;code&gt;new Date();&lt;/code&gt;를 호출하면 새로운 &lt;code&gt;Date&lt;/code&gt; 객체가 생성되며, 현재 날짜와 시간으로 초기화된다.&lt;br /&gt;즉, &lt;b&gt;생성자는 객체를 생성하고 초기화하는 특별한 메서드&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체 변수와 참조 변수의 차이&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체와 객체 변수를 이해할 때 중요한 점은 &lt;b&gt;객체 변수는 객체를 포함하는 것이 아니라, 객체가 위치한 메모리 주소를 저장하는 변수&lt;/b&gt;라는 것이다.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;Date startTime; // 아무런 객체도 참조하지 않음
startTime = new Date(); // 객체를 생성하고 참조&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;code&gt;startTime&lt;/code&gt; 변수는 &lt;code&gt;Date&lt;/code&gt; 타입의 객체를 참조할 수 있는 변수지만, 객체를 생성하기 전까지는 &lt;b&gt;어떠한 객체도 참조하지 않는다.&lt;/b&gt;&lt;br /&gt;&lt;code&gt;new Date();&lt;/code&gt;를 호출하면 &lt;b&gt;Heap 메모리에 새로운 객체가 생성&lt;/b&gt;되고, &lt;code&gt;startTime&lt;/code&gt;은 그 객체를 참조하게 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체 변수와 null 참조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 변수는 특정한 객체를 참조하지 않을 수도 있다. 이때 객체 변수의 값은 &lt;code&gt;null&lt;/code&gt;이 될 수 있으며, 이를 &lt;b&gt;null 참조(null reference)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;Date startTime = null;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 변수가 &lt;code&gt;null&lt;/code&gt;인 상태에서 메서드를 호출하면 &lt;b&gt;&lt;code&gt;NullPointerException&lt;/code&gt;이 발생&lt;/b&gt;할 수 있으므로, 이를 방지하기 위해 &lt;code&gt;null&lt;/code&gt; 체크가 필요하다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;if (startTime != null) {
    System.out.println(startTime);
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체 참조의 공유&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 변수는 &lt;b&gt;객체의 참조를 저장하는 변수&lt;/b&gt;이므로, 두 개의 객체 변수가 같은 객체를 참조할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;Date rightNow = new Date();
Date startTime = rightNow; // 두 변수가 같은 객체를 참조&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우, &lt;code&gt;rightNow&lt;/code&gt;와 &lt;code&gt;startTime&lt;/code&gt;은 &lt;b&gt;동일한 객체를 가리킨다&lt;/b&gt;.&lt;br /&gt;즉, &lt;code&gt;startTime&lt;/code&gt;을 변경하면 &lt;code&gt;rightNow&lt;/code&gt;에도 영향을 미치게 된다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;startTime.setTime(0);
System.out.println(rightNow); // rightNow도 변경된 값이 출력됨&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cx7iNv/btsMDYbcyUs/d4Q8RwRc8gpD7Jf5Tvgs81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cx7iNv/btsMDYbcyUs/d4Q8RwRc8gpD7Jf5Tvgs81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cx7iNv/btsMDYbcyUs/d4Q8RwRc8gpD7Jf5Tvgs81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcx7iNv%2FbtsMDYbcyUs%2Fd4Q8RwRc8gpD7Jf5Tvgs81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;519&quot; height=&quot;249&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체와 객체 변수 사이의 차이점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체와 객체 변수를 이해할 때 중요한 점은 &lt;b&gt;객체 변수는 객체 자체가 아니라 객체의 참조를 저장&lt;/b&gt;한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 객체 변수를 선언했을 때&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;Date startTime;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시점에서 &lt;code&gt;startTime&lt;/code&gt;은 &lt;b&gt;객체 변수가 선언되었을 뿐, 아직 객체를 참조하고 있지 않다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 객체를 생성하여 참조를 할당했을 때&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;startTime = new Date();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;startTime&lt;/code&gt;은 새로운 &lt;code&gt;Date&lt;/code&gt; 객체를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 객체를 다른 변수에 할당했을 때&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Date anotherTime = startTime;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;anotherTime&lt;/code&gt;과 &lt;code&gt;startTime&lt;/code&gt;은 &lt;b&gt;동일한 객체를 참조&lt;/b&gt;하게 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;메모리 구조에서의 객체 참조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 &lt;code&gt;new&lt;/code&gt; 키워드를 사용하여 객체를 생성하면, &lt;b&gt;Heap 메모리에 새로운 객체가 할당&lt;/b&gt;된다.&lt;br /&gt;객체 변수는 이 객체를 직접 저장하는 것이 아니라 &lt;b&gt;객체의 주소(reference)&lt;/b&gt;를 저장한다.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;Date startTime = new Date();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드가 실행되면 다음과 같은 과정이 이루어진다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;new Date();&lt;/code&gt;를 실행하면 &lt;b&gt;Heap 메모리&lt;/b&gt;에 새로운 &lt;code&gt;Date&lt;/code&gt; 객체가 생성된다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;startTime&lt;/code&gt; 변수는 생성된 &lt;code&gt;Date&lt;/code&gt; 객체의 &lt;b&gt;메모리 주소를 저장&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식은 객체의 효율적인 관리 및 재사용을 가능하게 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체를 참조하는 두 가지 방법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 변수는 새로운 객체를 생성하여 참조할 수도 있지만, 기존에 존재하는 객체를 참조할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 새로운 객체 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;Date startTime = new Date();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 기존 객체를 참조&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;Date rightNow = new Date();
Date startTime = rightNow;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 &lt;code&gt;rightNow&lt;/code&gt;와 &lt;code&gt;startTime&lt;/code&gt;은 &lt;b&gt;동일한 객체를 가리키며&lt;/b&gt;, 한쪽에서 변경이 발생하면 다른 쪽에도 영향을 미친다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체와 객체 변수의 차이점 요약&lt;/b&gt;&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개념&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;객체(Object)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;메모리에 생성된 실제 데이터(인스턴스)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;객체 변수(Object Variable)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;객체를 참조하는 변수(객체의 메모리 주소를 저장)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;객체 변수의 초기 상태&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt; 값을 가질 수 있으며, 참조할 객체가 없을 경우 &lt;code&gt;NullPointerException&lt;/code&gt;이 발생할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;객체 참조의 공유&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;여러 개의 객체 변수가 하나의 객체를 참조할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.2.2 LocalDate 클래스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 다룬 &lt;code&gt;Date&lt;/code&gt; 클래스는 표준 Java 라이브러리의 일부로, 특정한 시간 지점을 나타내는 데 사용된다. 하지만 &lt;code&gt;Date&lt;/code&gt; 클래스는 &lt;b&gt;1970년 1월 1일 00:00:00 UTC&lt;/b&gt;를 기준으로 시간 값을 저장하기 때문에, 일반적인 달력 표기법과 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 &lt;b&gt;Java 8&lt;/b&gt;부터는 &lt;code&gt;java.time&lt;/code&gt; 패키지에 &lt;code&gt;LocalDate&lt;/code&gt; 클래스가 추가되었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Date&lt;/code&gt; 클래스는 특정 시점을 &lt;b&gt;시간 단위&lt;/b&gt;까지 포함하여 표현한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LocalDate&lt;/code&gt; 클래스는 &lt;b&gt;연도, 월, 일&lt;/b&gt;을 일반적인 달력 표기법으로 다룬다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;LocalDate 객체 생성 방법&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;현재 날짜를 가져오기&lt;/b&gt;&lt;code&gt;LocalDate.now()&lt;/code&gt; 메소드는 시스템의 현재 날짜를 가져온다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;LocalDate today = LocalDate.now();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특정 날짜를 직접 지정하기&lt;/b&gt;&lt;code&gt;LocalDate.of(year, month, day)&lt;/code&gt;를 사용하면 특정 날짜를 직접 설정할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;LocalDate newYearsEve = LocalDate.of(1999, 12, 31);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체를 변수에 저장하기&lt;/b&gt;생성된 &lt;code&gt;LocalDate&lt;/code&gt; 객체를 변수에 저장하여 여러 번 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;LocalDate birthday = LocalDate.of(2000, 5, 20);&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;LocalDate에서 연, 월, 일 가져오기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 &lt;code&gt;LocalDate&lt;/code&gt; 객체에서 연도, 월, 일을 가져올 수 있다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;int year = newYearsEve.getYear();      // 1999
int month = newYearsEve.getMonthValue(); // 12
int day = newYearsEve.getDayOfMonth(); // 31&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 메소드들은 &lt;b&gt;캡슐화된 인스턴스 필드&lt;/b&gt;에서 값을 가져오므로, &lt;code&gt;LocalDate&lt;/code&gt; 클래스 내부의 구현 방식을 알 필요 없이 쉽게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캡슐화의 핵심&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 내부의 데이터 표현 방식이 변경되더라도, 제공하는 메소드(&lt;code&gt;getYear()&lt;/code&gt;, &lt;code&gt;getMonthValue()&lt;/code&gt;, &lt;code&gt;getDayOfMonth()&lt;/code&gt;)는 동일하게 유지된다.&lt;/li&gt;
&lt;li&gt;사용자는 내부 구현을 알 필요 없이 제공된 메소드를 활용하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.2.3 변경자(Mutator)와 접근자(Accessor) 메소드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 제공하는 &lt;code&gt;LocalDate&lt;/code&gt; 객체는 &lt;b&gt;불변 객체(immutable object)&lt;/b&gt; 이다. 즉, 한 번 생성된 &lt;code&gt;LocalDate&lt;/code&gt; 객체는 변경할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 특정 날짜에 1000일을 추가하는 코드를 작성해 보자.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;LocalDate aThousandDaysLater = newYearsEve.plusDays(1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 실행하면 &lt;code&gt;newYearsEve&lt;/code&gt; 객체는 변경되지 않고, &lt;b&gt;새로운 &lt;code&gt;LocalDate&lt;/code&gt; 객체&lt;/b&gt;가 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 달리, Java의 초기 버전에서 사용되던 &lt;code&gt;GregorianCalendar&lt;/code&gt; 클래스는 &lt;b&gt;mutable(변경 가능한) 객체&lt;/b&gt;였다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;GregorianCalendar someDay = new GregorianCalendar(1999, 11, 31);
// GregorianCalendar는 0부터 월을 시작하기 때문에 11은 12월을 의미&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;GregorianCalendar&lt;/code&gt;의 &lt;code&gt;add()&lt;/code&gt; 메소드는 기존 객체를 직접 변경하는 &lt;b&gt;변경자(Mutator) 메소드&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;someDay.add(Calendar.DAY_OF_MONTH, 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서는 기존 &lt;code&gt;someDay&lt;/code&gt; 객체 자체가 변경된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, &lt;code&gt;LocalDate.plusDays(1000)&lt;/code&gt; 메소드는 새로운 객체를 반환하는 &lt;b&gt;접근자(Accessor) 메소드&lt;/b&gt;이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;접근자(Accessor)와 변경자(Mutator)의 차이&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;접근자 메소드&lt;/b&gt; (&lt;code&gt;getYear()&lt;/code&gt;, &lt;code&gt;getMonthValue()&lt;/code&gt;, &lt;code&gt;getDayOfMonth()&lt;/code&gt;): 객체를 수정하지 않고 데이터를 조회하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경자 메소드&lt;/b&gt; (&lt;code&gt;add()&lt;/code&gt; in &lt;code&gt;GregorianCalendar&lt;/code&gt;): 객체의 상태를 직접 변경한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LocalDate&lt;/code&gt;는 변경자를 제공하지 않고, 연산 후 새로운 객체를 반환하는 방식을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.2.4 LocalDate를 활용한 달력 출력 예제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 위에서 배운 &lt;code&gt;LocalDate&lt;/code&gt; 클래스를 활용하여 이번 달의 달력을 프롬프트에서 출력하는 프로그램의 예제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로그램은 현재 날짜를 가져와서 이번 달의 시작일과 요일을 계산한 후, 달력을 출력하는 방식으로 작동한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;달력 프로그램의 핵심 단계&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;현재 날짜를 가져온다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;LocalDate date = LocalDate.now();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;현재 달과 일을 저장한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;int month = date.getMonthValue();
int today = date.getDayOfMonth();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;현재 날짜를 해당 달의 1일로 설정하고, 해당 날짜의 요일을 가져온다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;date = date.minusDays(today - 1); // 이번 달의 시작일로 설정
DayOfWeek weekday = date.getDayOfWeek();
int value = weekday.getValue(); // 1 = 월요일, ... , 7 = 일요일&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;달력 출력 준비: 주의 첫 번째 줄을 맞추기 위해 공백을 출력한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;System.out.println(&quot;Mon Tue Wed Thu Fri Sat Sun&quot;);
for (int i = 1; i &amp;lt; value; i++)
    System.out.print(&quot;    &quot;); // 들여쓰기&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;날짜를 반복하면서 출력한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-java&quot;&gt;while (date.getMonthValue() == month) {
    System.out.printf(&quot;%3d&quot;, date.getDayOfMonth());
    if (date.getDayOfMonth() == today)
        System.out.print(&quot;*&quot;); // 오늘 날짜 강조 표시
    else
        System.out.print(&quot;   &quot;);

    date = date.plusDays(1);
    if (date.getDayOfWeek().getValue() == 1) // 한 주가 끝나면 줄 바꿈
        System.out.println();
}&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀 코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;import java.time.*;

public class CalendarTest {
    public static void main(String[] args) {
        LocalDate date = LocalDate.now();
        int month = date.getMonthValue();
        int today = date.getDayOfMonth();

        date = date.minusDays(today - 1); // 이번 달의 시작일로 설정
        DayOfWeek weekday = date.getDayOfWeek();
        int value = weekday.getValue(); // 1 = 월요일, ... , 7 = 일요일

        System.out.println(&quot;Mon Tue Wed Thu Fri Sat Sun&quot;);

        for (int i = 1; i &amp;lt; value; i++)
            System.out.print(&quot;    &quot;); // 첫 주의 시작 요일 맞춤

        while (date.getMonthValue() == month) {
            System.out.printf(&quot;%3d&quot;, date.getDayOfMonth());
            if (date.getDayOfMonth() == today)
                System.out.print(&quot;*&quot;); // 오늘 날짜 표시
            else
                System.out.print(&quot;   &quot;);

            date = date.plusDays(1);

            if (date.getDayOfWeek().getValue() == 1) // 새로운 주 시작 시 줄 바꿈
                System.out.println();
        }

        if (date.getDayOfWeek().getValue() != 1) // 마지막 줄 개행 정리
            System.out.println();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741484683443&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&quot; data-og-description=&quot;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.2 표준 라이브러리 클래스 사용하기&amp;nbsp;4.2 표준 라이브러리 클래스 사용하기4.2 표준 라이브러리 클래스 사용하기(Using Predefined Cla&quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/14&quot; data-og-url=&quot;https://choosla.tistory.com/14&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oJMvF/hyYqaPONgI/fOgwiKmGsRpSqAOwka899K/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/LYG8u/hyYq0zljwc/c6zl0LliOnf3Sg3UkmwqK1/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/ggGs0/hyYqQ4EOpx/uKhrKovHkxZRnEz1hwsBcK/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/14&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oJMvF/hyYqaPONgI/fOgwiKmGsRpSqAOwka899K/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/LYG8u/hyYq0zljwc/c6zl0LliOnf3Sg3UkmwqK1/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359,https://scrap.kakaocdn.net/dn/ggGs0/hyYqQ4EOpx/uKhrKovHkxZRnEz1hwsBcK/img.png?width=643&amp;amp;height=359&amp;amp;face=0_0_643_359');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.3 자신만의 클래스 정의하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.2 표준 라이브러리 클래스 사용하기&amp;nbsp;4.2 표준 라이브러리 클래스 사용하기4.2 표준 라이브러리 클래스 사용하기(Using Predefined Cla&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>date</category>
      <category>LocalDate</category>
      <category>자바</category>
      <category>코어자바</category>
      <category>표준라이브러리</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/13</guid>
      <comments>https://choosla.tistory.com/13#entry13comment</comments>
      <pubDate>Sat, 8 Mar 2025 01:11:58 +0900</pubDate>
    </item>
    <item>
      <title>코어자바(Core Java) 12판 Chapter 4 리뷰 : 4.1 객체(Object)와 객체 지향 프로그래밍</title>
      <link>https://choosla.tistory.com/12</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[객체 지향 프로그래밍 입문: 객체의 특징과 클래스 구분]&lt;/b&gt;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;객체 지향 프로그래밍(Object-oriented Programming, 이하 OOP) 개요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 프로그래밍(OOP)은 절차 지향적 프로그래밍 기법을 대체하는 &lt;b&gt;새로운 패러다임&lt;/b&gt;으로, 현재 소프트웨어 개발에서 가장 널리 사용되는 개념이다. OOP의 핵심은 &lt;b&gt;객체(Object)&lt;/b&gt;이며, 각각의 객체는 사용자에게 공개된 특정 기능과 내부적으로 감춰진 구현을 가지고 있다. 개발자는 원하는 기능을 수행하는 객체를 불러와 &lt;b&gt;내부 구현을 알 필요 없이&lt;/b&gt; 해당 객체를 활용하여 프로그램을 개발할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 &lt;b&gt;절차 지향 프로그래밍(Procedural Programming)&lt;/b&gt;에서는 먼저 문제 해결을 위한 &lt;b&gt;절차(Algorithm)&lt;/b&gt;를 정의하고, 그 후 데이터를 저장하는 방식을 결정한다. 대표적인 예로 &lt;b&gt;파스칼 언어(Pascal Language)&lt;/b&gt;가 있다. 그러나 OOP에서는 이와 반대로 &lt;b&gt;데이터를 먼저 정의한 후, 데이터를 조작하는 알고리즘을 구성하는 방식&lt;/b&gt;을 따른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절차 지향 프로그래밍은 작은 문제를 해결하는 데 효과적이지만, &lt;b&gt;객체(Object)는 보다 복잡한 문제를 해결하는 데 적합&lt;/b&gt;하다. OOP에서는 객체를 중심으로 프로그램을 구성하며, 객체 간의 관계를 정의하고 협업할 수 있도록 설계한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.1.1 클래스(Class)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;클래스란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스(Class)는 &lt;b&gt;객체를 생성하는 틀(Template) 또는 청사진(Blueprint)&lt;/b&gt; 역할을 한다. 쉽게 말해, 클래스는 일종의 &lt;b&gt;쿠키 커터(Cookie Cutter, 쿠키 틀)&lt;/b&gt;와 같으며, 객체는 클래스에 의해 특정한 형태로 생성된다. 따라서 동일한 클래스를 기반으로 여러 개의 객체를 생성할 수 있으며, 이를 &lt;b&gt;클래스의 인스턴스(Instance)를 생성&lt;/b&gt;한다고 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;캡슐화(Encapsulation)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캡슐화(Encapsulation)&lt;/b&gt;는 OOP의 핵심 개념 중 하나로, &lt;b&gt;데이터와 기능(메서드)을 하나의 패키지로 묶어 외부에서 직접 접근할 수 없도록 보호하는 기법&lt;/b&gt;이다. 캡슐화를 통해 객체의 내부 구현을 감추고, &lt;b&gt;객체의 상태(State)는 외부에서 직접 변경할 수 없도록 제한&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 내부 데이터는 &lt;b&gt;인스턴스 필드(Instance Field, 멤버 변수)&lt;/b&gt;라고 하며, &lt;b&gt;데이터를 처리하는 행동은 메서드(Method)&lt;/b&gt;라고 한다. 하나의 클래스를 기반으로 여러 개의 객체를 생성할 수 있으며, 각 객체는 &lt;b&gt;고유한 상태(State)&lt;/b&gt;를 가지며, 실행되는 동안 상태가 변할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;캡슐화의 중요성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캡슐화를 올바르게 구현하려면 &lt;b&gt;외부에서 직접적으로 인스턴스 필드에 접근할 수 있도록 허용해서는 안 된다.&lt;/b&gt; 프로그램은 반드시 &lt;b&gt;객체의 메서드를 통해서만 데이터에 접근하고 조작해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 &lt;b&gt;클래스 내부의 데이터 구조가 변경되더라도, 외부에서는 동일한 방식으로 데이터를 접근할 수 있다.&lt;/b&gt; 즉, 프로그램의 안정성을 유지하면서도 내부 구현을 유연하게 변경할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.1.2 객체(Object)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 프로그래밍을 하기 위해서는, 객체의 &lt;b&gt;세 가지 핵심 특성&lt;/b&gt;을 이해해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체의 3가지 특성&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;행동(Behavior)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체가 수행할 수 있는 동작, 즉 &lt;b&gt;어떤 메서드를 적용할 수 있는지&lt;/b&gt;를 의미한다.&lt;/li&gt;
&lt;li&gt;예를 들어, 자동차(Car) 객체는 &lt;code&gt;start()&lt;/code&gt;, &lt;code&gt;accelerate()&lt;/code&gt; 등의 동작을 가질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태(State)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체가 가지고 있는 데이터(속성, 변수)로, &lt;b&gt;현재 상태를 나타낸다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;예를 들어, 자동차(Car) 객체의 &lt;code&gt;speed&lt;/code&gt; 값은 가속할 때마다 변한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정체성(Identity)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일한 클래스로 생성된 객체라 하더라도, &lt;b&gt;각 객체는 고유한 존재로 구별된다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;예를 들어, 동일한 &lt;code&gt;Car&lt;/code&gt; 클래스를 기반으로 여러 자동차 객체를 생성하더라도, 각각의 자동차는 서로 다른 개체로 구분된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체의 행동(Behavior)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 수행할 수 있는 &lt;b&gt;동작(Behavior)&lt;/b&gt;을 의미하며, 일반적으로 &lt;b&gt;메서드(Method)&lt;/b&gt;로 정의된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 객체가 &lt;b&gt;어떤 작업을 수행할 수 있는지&lt;/b&gt;를 결정한다.&lt;/li&gt;
&lt;li&gt;객체의 &lt;b&gt;상태(State)를 변화시킬 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Car {
    void start() {
        System.out.println(&quot;자동차에 시동을 겁니다.&quot;);
    }

    void accelerate() {
        System.out.println(&quot;자동차가 가속합니다.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체의 상태(State)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 가지고 있는 &lt;b&gt;데이터(속성, 변수)&lt;/b&gt;로, 객체의 현재 상태를 나타낸다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 행동(메서드)에 따라 상태가 변할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Car {
    int speed = 0;

    void accelerate() {
        speed += 10;
        System.out.println(&quot;현재 속도: &quot; + speed + &quot;km/h&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체의 정체성(Identity)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 클래스로부터 생성된 객체라 하더라도, 각각의 객체는 &lt;b&gt;고유한 정체성을&lt;/b&gt; 가지며, 서로 다른 객체로 구별된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일한 클래스를 기반으로 생성된 객체들이 &lt;b&gt;서로 다름을 보장&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        Car car1 = new Car();
        Car car2 = new Car();

        System.out.println(car1 == car2); // false (서로 다른 객체)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체의 상태와 행동의 상호작용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 &lt;b&gt;상태(State)와 행동(Behavior)&lt;/b&gt;은 서로 영향을 미칠 수 있다.&lt;br /&gt;예를 들어, &lt;b&gt;주문(Order) 객체&lt;/b&gt;의 상태가 &lt;code&gt;&quot;배송 중&quot;&lt;/code&gt;이나 &lt;code&gt;&quot;결제 완료&quot;&lt;/code&gt;라면 더 이상 상품을 추가하거나 삭제할 수 없다. 즉, 객체의 &lt;b&gt;상태에 따라 행동이 제한될 수도 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Order {
    private String status = &quot;비어 있음&quot;;

    void addItem() {
        if (status.equals(&quot;배송 중&quot;) || status.equals(&quot;결제 완료&quot;)) {
            System.out.println(&quot;상품을 추가할 수 없습니다.&quot;);
        } else {
            System.out.println(&quot;상품을 추가하였습니다.&quot;);
        }
    }

    void setStatus(String status) {
        this.status = status;
    }
}

public class Main {
    public static void main(String[] args) {
        Order order = new Order();
        order.addItem(); // 상품을 추가할 수 있습니다.

        order.setStatus(&quot;배송 중&quot;);
        order.addItem(); // 상품을 추가할 수 없습니다.
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.1.3 클래스를 구별하는 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 프로그래밍에서는 프로그램을 구성하는 다양한 개체들을 &lt;b&gt;객체(Object)&lt;/b&gt;로 모델링한다. 하지만 무작정 객체를 나열하는 것이 아니라 &lt;b&gt;적절한 기준에 따라 클래스로 구별&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;절차 지향 프로그래밍과 객체 지향 프로그래밍의 차이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 &lt;b&gt;절차 지향 프로그래밍(Procedural Programming)&lt;/b&gt;에서는 프로그램의 실행 흐름이 &lt;b&gt;TOP(최상위 지점)&lt;/b&gt;에서 시작된다.&lt;br /&gt;예를 들어, C 언어에서는 항상 &lt;code&gt;main()&lt;/code&gt; 함수에서 프로그램이 시작되며, 순차적으로 코드가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 &lt;b&gt;객체 지향 프로그래밍(OOP)&lt;/b&gt;에서는 실행 흐름이 특정한 &quot;TOP&quot;에서 시작되지 않는다.&lt;br /&gt;어떤 객체든 프로그램의 실행을 시작할 수 있으며, 실행의 흐름은 객체들 간의 &lt;b&gt;메서드 호출 및 메시지 전달&lt;/b&gt;을 통해 동적으로 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;OOP는 데이터를 중심으로 프로그램을 구성&lt;/b&gt;하며, 데이터를 표현하는 &lt;b&gt;클래스를 먼저 정의한 후&lt;/b&gt; 그 클래스에 적절한 &lt;b&gt;메서드를 추가하는 방식&lt;/b&gt;을 따른다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;클래스를 구별하는 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스를 정의하는 가장 간단한 방법은 &lt;b&gt;문제에서 &quot;명사&quot;를 찾는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, &lt;b&gt;온라인 쇼핑 시스템&lt;/b&gt;을 설계한다고 가정하자.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;명사 &amp;rarr; 클래스&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Item&lt;/code&gt; (상품)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Order&lt;/code&gt; (주문)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ShippingAddress&lt;/code&gt; (배송지)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Payment&lt;/code&gt; (결제)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Account&lt;/code&gt; (계정)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 클래스의 동작을 정의하기 위해 &lt;b&gt;동사를 찾아 메서드로 구현&lt;/b&gt;한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Item 객체는 Order에 &quot;추가&quot;될 수 있다.&lt;/b&gt; &amp;rarr; &lt;code&gt;addItem()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Order 객체는 &quot;배송 중&quot; 상태가 될 수 있다.&lt;/b&gt; &amp;rarr; &lt;code&gt;shipOrder()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Payment 객체는 Order를 &quot;승인&quot;할 수 있다.&lt;/b&gt; &amp;rarr; &lt;code&gt;approvePayment()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;b&gt;객체와 클래스의 구별은 &quot;명사-동사&quot; 방식으로 쉽게 식별할 수 있다&lt;/b&gt;.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드에서 &lt;code&gt;Order&lt;/code&gt; 클래스는 &lt;code&gt;Item&lt;/code&gt; 객체를 관리한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.List;

class Item {
    private String name;

    public Item(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Order {
    private List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;&amp;gt;();

    void addItem(Item item) {
        items.add(item);
        System.out.println(item.getName() + &quot;이(가) 주문에 추가되었습니다.&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Order order = new Order();
        Item item1 = new Item(&quot;노트북&quot;);
        Item item2 = new Item(&quot;스마트폰&quot;);

        order.addItem(item1);
        order.addItem(item2);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력 결과&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;노트북이 주문에 추가되었습니다.
스마트폰이 주문에 추가되었습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;이처럼 &lt;b&gt;클래스를 구별하는 방법을 올바르게 적용하면, 명확하고 확장 가능한 설계를 할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.1.4 클래스 간의 관계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 프로그래밍에서는 클래스들 간의 관계를 정의하는 것이 중요하다.&lt;br /&gt;클래스 간의 관계는 크게 &lt;b&gt;세 가지 유형&lt;/b&gt;으로 구분된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;의존(Dependence) - &quot;uses-a&quot; 관계&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;집합(Aggregation) - &quot;has-a&quot; 관계&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상속(Inheritance) - &quot;is-a&quot; 관계&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1) 의존(Dependence) - &quot;uses-a&quot; 관계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 클래스가 다른 클래스의 메서드를 호출할 때 발생하는 관계이다.&lt;br /&gt;예를 들어, &lt;code&gt;Order&lt;/code&gt; 클래스는 &lt;code&gt;Account&lt;/code&gt; 클래스를 사용하여 결제 정보를 확인해야 한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Account {
    void charge() {
        System.out.println(&quot;결제가 처리되었습니다.&quot;);
    }
}

class Order {
    void processPayment(Account account) {
        account.charge();
    }
}

public class Main {
    public static void main(String[] args) {
        Account account = new Account();
        Order order = new Order();
        order.processPayment(account);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력 결과&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;결제가 처리되었습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;code&gt;Item&lt;/code&gt; 클래스는 &lt;code&gt;Account&lt;/code&gt; 클래스와 의존 관계가 없다. 이는 &lt;code&gt;Item&lt;/code&gt;이 주문 시 고객 정보를 직접 필요로 하지 않기 때문이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2) 집합(Aggregation) - &quot;has-a&quot; 관계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 클래스가 다른 클래스를 &lt;b&gt;포함(소유)&lt;/b&gt;할 때 발생하는 관계이다.&lt;br /&gt;예를 들어, &lt;code&gt;Order&lt;/code&gt; 클래스는 여러 개의 &lt;code&gt;Item&lt;/code&gt;을 포함할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.List;

class Item {
    private String name;

    public Item(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Order {
    private List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;&amp;gt;();

    void addItem(Item item) {
        items.add(item);
        System.out.println(item.getName() + &quot;이(가) 주문에 추가되었습니다.&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Order order = new Order();
        Item item1 = new Item(&quot;책&quot;);
        Item item2 = new Item(&quot;키보드&quot;);

        order.addItem(item1);
        order.addItem(item2);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력 결과&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;책이 주문에 추가되었습니다.
키보드가 주문에 추가되었습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3) 상속(Inheritance) - &quot;is-a&quot; 관계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 클래스가 다른 클래스를 &lt;b&gt;확장(extend)&lt;/b&gt;할 때 발생하는 관계이다.&lt;br /&gt;예를 들어, &lt;code&gt;RushOrder&lt;/code&gt; 클래스는 &lt;code&gt;Order&lt;/code&gt; 클래스를 상속받을 수 있다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Order {
    void process() {
        System.out.println(&quot;주문을 처리합니다.&quot;);
    }
}

class RushOrder extends Order {
    @Override
    void process() {
        System.out.println(&quot;빠른 배송 주문을 처리합니다.&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Order normalOrder = new Order();
        Order rushOrder = new RushOrder();

        normalOrder.process();
        rushOrder.process();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력 결과&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;주문을 처리합니다.
빠른 배송 주문을 처리합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;b&gt;클래스 간의 관계를 적절히 활용하면 객체 간의 구조를 더욱 명확하게 설계할 수 있다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.03.08 - [Core Java/Chapter 4] - 4.2 표준 라이브러리 클래스 사용하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741483836971&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;4.2 표준 라이브러리 클래스 사용하기&quot; data-og-description=&quot;4.2 표준 라이브러리 클래스 사용하기(Using Predefined Classes)자바에서는 미리 정의된 표준 라이브러리 클래스(Predefined Classes)를 제공하며, 이를 통해 개발자는 직접 구현하지 않아도 다양한 기능을 &quot; data-og-host=&quot;choosla.tistory.com&quot; data-og-source-url=&quot;https://choosla.tistory.com/13&quot; data-og-url=&quot;https://choosla.tistory.com/13&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b214PY/hyYqTNQwQ5/xaaHMdoDGUkjWkPvwLDgk1/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/fd6o3/hyYqRCviNG/xgzm9lJZLLKa3SNDK5PAGk/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/dIGMPc/hyYmNV2q4Q/uZUkgpsOYR0FkUfcFuIkd0/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249&quot;&gt;&lt;a href=&quot;https://choosla.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choosla.tistory.com/13&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b214PY/hyYqTNQwQ5/xaaHMdoDGUkjWkPvwLDgk1/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/fd6o3/hyYqRCviNG/xgzm9lJZLLKa3SNDK5PAGk/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249,https://scrap.kakaocdn.net/dn/dIGMPc/hyYmNV2q4Q/uZUkgpsOYR0FkUfcFuIkd0/img.png?width=519&amp;amp;height=249&amp;amp;face=0_0_519_249');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;4.2 표준 라이브러리 클래스 사용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;4.2 표준 라이브러리 클래스 사용하기(Using Predefined Classes)자바에서는 미리 정의된 표준 라이브러리 클래스(Predefined Classes)를 제공하며, 이를 통해 개발자는 직접 구현하지 않아도 다양한 기능을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choosla.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Core Java/Chapter 4</category>
      <category>Core Java</category>
      <category>OOP</category>
      <category>객체</category>
      <category>객체 지향</category>
      <category>자바 기초</category>
      <category>코어자바</category>
      <category>클래스</category>
      <category>클랫스설계</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/12</guid>
      <comments>https://choosla.tistory.com/12#entry12comment</comments>
      <pubDate>Sat, 8 Mar 2025 00:52:43 +0900</pubDate>
    </item>
    <item>
      <title>동적 계획법(Dynamic Programming) 이해하기</title>
      <link>https://choosla.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;동적 계획법을 이해하기 전에 필수로 재귀와 분할 정복을 이해하고 시작하길 바란다. 해당 기법들의 이해없이 바로 동적 계획법을 이해하기란 쉽지 않다.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;동적 계획법이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 작은 부분 문제로 나누고, 그 부분 문제의 결과를 &lt;b&gt;저장&lt;/b&gt;해 다시 사용함으로써 전체 문제를 효율적으로 해결하는 기법이다. 이 방법은 특히 &lt;b&gt;중복되는 부분 문제&lt;/b&gt;를 가진 문제를 해결하는 데 유용하며, 재귀적으로 표현되는 문제를 최적화된 방식으로 풀 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 중복되는 부분 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적 계획법은 큰 의미에서 문제를 작은 부분 문제로 나누고, 그 부분 문제를 합쳐 원래 문제를 해결한다는 관점에서 '분할 정복'과 같은 접근 방식을 가지고 있다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;하지만 두개 사이에는 &lt;b&gt;차이&lt;/b&gt;가 존재하는 데, 바로 &lt;b&gt;어떤 부분 문제가 여러번 계산되는 것을 저장을 통하여 피한다는 것&lt;/b&gt;이다. 아래 예시를 통해서 확인해보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시 : 피보나치 수열&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수열은 수학적으로 다음과 같이 정의된다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;emsp; - F(0) = 0&lt;br /&gt;&amp;emsp; - F(1) = 1&lt;br /&gt;&amp;emsp; - F(n) = F(n-1) + F(n-2) (n &amp;ge; 2)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;재귀로 풀어낸 피보나치 수열&lt;/h4&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int fibo(int n) {
    if (n == 0 || n == 1) return n; // 기본 경우: F(0) = 0, F(1) = 1
    return fibo(n - 1) + fibo(n - 2); // 재귀 호출로 계산
}

int main() {
    int n = 10;
    cout &amp;lt;&amp;lt; &quot;피보나치 수열 결과 (완전 탐색, n = 10): &quot; &amp;lt;&amp;lt; fibo(n) &amp;lt;&amp;lt; endl;
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 재귀를 활용한 완전 탐색을 이용한 피보나치 수열을 구하는 문제이다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이 함수는 재귀로 인하여 간단 명료하게 풀리지만 호출되는 함수를 생각해보면 중복되는 함수 호출이 많아 진다는 것을 알 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이러한 &lt;b&gt;비효율적인 호출이 n이 커질 수록 기하급수적으로 많아지며 문제 풀이에 문제가 생긴다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cENuj3/btsJrIOSZXx/eoXWmkMvGuGnXL2tu0GVXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cENuj3/btsJrIOSZXx/eoXWmkMvGuGnXL2tu0GVXK/img.png&quot; data-alt=&quot;n=5인 피보나치수열&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cENuj3/btsJrIOSZXx/eoXWmkMvGuGnXL2tu0GVXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcENuj3%2FbtsJrIOSZXx%2FeoXWmkMvGuGnXL2tu0GVXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;521&quot; height=&quot;361&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;n=5인 피보나치수열&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 그림은 n=5일 때의 호출 스택을 그림으로 표현한 것이다. n이 매우 적은 수지만 이미 많은 중복호출을 보인다는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnBGu5/btsJslyLim9/Cw0PAkEZz3k3r5Cm0lhd10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnBGu5/btsJslyLim9/Cw0PAkEZz3k3r5Cm0lhd10/img.png&quot; data-alt=&quot;중복되는 함수들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnBGu5/btsJslyLim9/Cw0PAkEZz3k3r5Cm0lhd10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnBGu5%2FbtsJslyLim9%2FCw0PAkEZz3k3r5Cm0lhd10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;521&quot; height=&quot;361&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중복되는 함수들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;fibo(1)&lt;/code&gt;와 &lt;code&gt;fibo(0)&lt;/code&gt;는 기저 사례(base case)이기 때문에 제외한다고해도 &lt;code&gt;n=5&lt;/code&gt;밖에 되지 않는데도 &lt;code&gt;fibo(3)&lt;/code&gt;과 &lt;code&gt;fibo(2)&lt;/code&gt;가 중복되어 호출되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 &lt;b&gt;중복 호출을 막기 위해서 사용하는 것이 다이나믹 프로그래밍(DP)&lt;/b&gt;이며, &lt;b&gt;&lt;code&gt;fibo(3)&lt;/code&gt;과 &lt;code&gt;fibo(2)&lt;/code&gt;를 미리 저장&lt;/b&gt;을 하여 다음에 그 함수가 호출되었을 때 &lt;b&gt;저장한 값을 불러들이기만 한다면&lt;/b&gt; 더욱 효율적인 프로그램이 될 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dL7fMm/btsJsiPKvyW/hOvMYsaNG4uFAeKWxtUNsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dL7fMm/btsJsiPKvyW/hOvMYsaNG4uFAeKWxtUNsK/img.png&quot; data-alt=&quot;DP 알고리즘을 사용했을 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dL7fMm/btsJsiPKvyW/hOvMYsaNG4uFAeKWxtUNsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdL7fMm%2FbtsJsiPKvyW%2FhOvMYsaNG4uFAeKWxtUNsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1031&quot; height=&quot;361&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DP 알고리즘을 사용했을 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fibo(3)과 fibo(2)의 중복 호출을 해결했더니 되게 간결한 호출 스택을 보이는 것을 볼 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;방금 위의 방식과 같이 &lt;b&gt;각 문제의 답을 메모리에 저장하는 것을 메모이제이션(memoization)&lt;/b&gt;이라고 한다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;동적 계획법에서 사용하는 메모이제이션(meoization)을 사용하는 방법에 대해서 설명하겠다. 일단 아래의 코드를 확인하자.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 중복 해결&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;메모이제이션(memoization)으로 풀어낸 피보나치 수열&lt;/h4&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

int cache[101]; // 최대 100까지의 값을 저장할 수 있는 배열

int fib_dp(int n) {
    if (n == 0 || n == 1) return n; // 기본 경우: F(0) = 0, F(1) = 1

    int&amp;amp; ret = cache[n];
    if (ret != -1) return ret; // 이미 계산된 값이 있으면 반환
    return ret = fib_dp(n - 1) + fib_dp(n - 2); // 값을 계산하고 저장
}

int main() {
    int n = 10;

    // cache 배열을 -1로 초기화
    for (int i = 0; i &amp;lt;= 100; i++) {
        cache[i] = -1;
    }

    cout &amp;lt;&amp;lt; &quot;피보나치 수열 결과 (DP, n = 10): &quot; &amp;lt;&amp;lt; fib_dp(n) &amp;lt;&amp;lt; endl;
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n이 최대 100까지 입력될 수 있다고 가정했을 때, DP를 사용한 피보나치수열에 대한 코드이다. 위에서 재귀를 이용한 피보나치에 대해 추가된 사항과 함께 이 함수를 설명해보겠다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. &lt;b&gt;캐시 배열(cache[101])&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int cache[101]; // 최대 100까지의 값을 저장할 수 있는 배열&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크기가 101인 정수 배열 &lt;code&gt;cache&lt;/code&gt;를 선언한다. 이 배열은 피보나치 수열의 결과를 저장하는 데 사용되며, 최대 &lt;code&gt;n=100&lt;/code&gt;까지 계산할 수 있도록 크기를 설정했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. &lt;b&gt;캐시 배열 초기화&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// cache 배열을 -1로 초기화
for (int i = 0; i &amp;lt;= 100; i++) {
    cache[i] = -1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기에는 모든 배열 값을 &lt;code&gt;-1&lt;/code&gt;로 설정하여 아직 계산되지 않았음을 나타낸다. 이를 통해 이미 계산된 값을 구별할 수 있다. 또한 memset을 이용해서 배열을 초기화할 수 있으니 한번 시도해 보길 바란다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. &lt;b&gt;기저 사례(base case) 처리&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;if (n == 0 || n == 1) return n; // 기본 경우: F(0) = 0, F(1) = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수열의 가장 기본적인 값 &lt;code&gt;F(0)&lt;/code&gt;과 &lt;code&gt;F(1)&lt;/code&gt;은 각각 0과 1로 정의된다. 따라서 &lt;code&gt;n == 0&lt;/code&gt;이거나 &lt;code&gt;n == 1&lt;/code&gt;일 때는 해당 값을 바로 반환한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. &lt;b&gt;이미 계산된 값 처리&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;if (cache[n] != -1) return ret; // 이미 계산된 값이 있으면 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;if (cache[n] != -1)&lt;/code&gt;에서, 만약 &lt;code&gt;cache[n]&lt;/code&gt;에 이미 값이 저장되어 있다면, 그 값을 반환한다. 이렇게 하면 중복 계산을 방지할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. &lt;b&gt;재귀 호출과 값 저장&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;return ret = fib_dp(n - 1) + fib_dp(n - 2); // 값을 계산하고 저장&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 계산되지 않은 경우, &lt;code&gt;fib_dp(n-1)&lt;/code&gt;과 &lt;code&gt;fib_dp(n-2)&lt;/code&gt;를 재귀적으로 호출하여 값을 계산한 후, 그 결과를 &lt;code&gt;cache[n]&lt;/code&gt;에 저장한다. 이렇게 함으로써 동일한 값이 다시 필요할 때 바로 반환할 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3 메모이제이션(memoization) 구현 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적 계획법을 구현한다는 건 이 메모이제이션을 구현한다는 것과 같다. 그런 만큼 한 가지의 패턴을 정해두고 항상 같은 형태로 구현하는 것이 좋다. 한 가지 패턴을 정하고 구현한다면 작성하기도, 버그를 찾기도 쉬워지기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 항상 기저 사례(base case)를 제일 먼저 처리한다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력이 범위를 벗어난 경우 등을 기저 사례로 처리하면 유용하다. 기저 사례를 먼저 확인하지 않고 &lt;code&gt;cache[]&lt;/code&gt;에 접근하면 범위를 벗어나는 등의 오류를 피할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 함수의 반환값을 고려해서 cache를 초기화해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;피보나치 수열의 반환값은 항상 &amp;gt; -1 이기 때문에 &lt;code&gt;-1&lt;/code&gt;로 초기화한다. &lt;code&gt;cache[]&lt;/code&gt;의 해당 위치에 적혀있는 값이 &lt;code&gt;-1&lt;/code&gt;이라면 계산된 반환값이 없다는 것을 의미한다. 만약에 함수가 &lt;code&gt;-1&lt;/code&gt;을 반환할 수도 있다면 &lt;code&gt;-1&lt;/code&gt;로 초기화하는 방법은 적합하지 않다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. cache에 접근할 때, 참조형(reference)을 활용한다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조형 &lt;code&gt;ret&lt;/code&gt;의 값을 바꾸면 &lt;code&gt;cache[n]&lt;/code&gt;의 값도 변하기 때문에 답을 저장할 때도 매번 귀찮게 &lt;code&gt;cache[n]&lt;/code&gt;을 적을 필요가 없다. 특히 다차원 배열일 때 매우 유용하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 최적 부분 구조(Optimal Substructure)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적 계획법을 사용할 수 있는가에 대해서 판단하기 위해서는 최적 부분 구조가 성립하는지도 확인해야 한다.&lt;br /&gt;최적 부분 구조를 간단하게 설명하자면 재귀 호출을 통해서 큰 문제에서 작은 문제로 분할될 때, &lt;b&gt;작아진 문제로만 판단하여 최적의 답을 낼 수 있는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예시를 들어서 설명하자면, &lt;code&gt;서울&lt;/code&gt;에서 &lt;code&gt;부산&lt;/code&gt;까지 가는 최단 경로를 들 수 있다. 이 최단 경로가 &lt;code&gt;대전&lt;/code&gt;을 지난다고 할때, &lt;code&gt;(서울, 대전)&lt;/code&gt; 과 &lt;code&gt;(대전, 부산)&lt;/code&gt;으로 나눈다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ky1yo/btsJqZK6YwM/gplqRKdSgQAmzflpZdG2d1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ky1yo/btsJqZK6YwM/gplqRKdSgQAmzflpZdG2d1/img.png&quot; data-alt=&quot;최적 부분 구조의 예&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ky1yo/btsJqZK6YwM/gplqRKdSgQAmzflpZdG2d1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fky1yo%2FbtsJqZK6YwM%2FgplqRKdSgQAmzflpZdG2d1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;401&quot; height=&quot;151&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최적 부분 구조의 예&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에서 서울에서 부산으로 가는 최단 경로를 찾는다고 하면 &lt;code&gt;(서울, 대전)&lt;/code&gt;과 &lt;code&gt;(대전, 부산)&lt;/code&gt; 각각의 최단 경로인 &lt;code&gt;10&lt;/code&gt;과 &lt;code&gt;5&lt;/code&gt;를 선택하면 찾을 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이렇게 &lt;b&gt;각 부분의 최선의 선택이 전체의 최선의 선택으로 이어지기 때문에 최적 부분 구조를 갖는다고 할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;작은 문제의 최적의 선택만으로는 전체 문제의 최적의 선택을 구할 수 없다면 해당 문제에는 최적 부분 구조가 존재하지 않는다&lt;/b&gt;고 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YiMfb/btsJsPfSlid/Iwv9k47K1eJtHBXcUYDJJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YiMfb/btsJsPfSlid/Iwv9k47K1eJtHBXcUYDJJk/img.png&quot; data-alt=&quot;최적 부분 구조가 될 수 없는 예&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YiMfb/btsJsPfSlid/Iwv9k47K1eJtHBXcUYDJJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYiMfb%2FbtsJsPfSlid%2FIwv9k47K1eJtHBXcUYDJJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;401&quot; height=&quot;151&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최적 부분 구조가 될 수 없는 예&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 그림에서 돈의 합이 &lt;code&gt;2만원&lt;/code&gt; 이하의 경로를 찾는다고 하면, &lt;code&gt;(대전, 부산)&lt;/code&gt;으로 가는 경로 중에 &lt;code&gt;(2시간, 2만원)&lt;/code&gt;으로 가는 경로밖에 선택하지 못 한다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;따라서 이 문제는 작은 문제&lt;code&gt;(대전, 부산)&lt;/code&gt;에서 최선의 선택인 (1시간, 2만원)을 골른다면 돈의 합이 &lt;code&gt;3만원&lt;/code&gt;이 되기 때문에 전체 문제인 &lt;code&gt;(서울, 부산)&lt;/code&gt;을 풀 수 없다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 예시 : 최장 증가 부분 수열(LIS)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최장 증가 부분 수열(LIS)란?&lt;/b&gt; 원소가 n개인 배열의 일부 원소를 골라내서 만든 부분 수열 중, 각 원소가 이전 원소보다 크다는 조건을 만족하고, 그 길이가 최대인 부분 수열을 최장 증가 부분 수열이다. 즉, 배열에서 증가하는 수열이 가장 긴 것을 고르면 된다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;예를 들어,&lt;br /&gt;&lt;code&gt;S = { 1, 3, 4, 2, 4 }&lt;/code&gt; 라고 하면 '1 2 4'는 S의 증가 부분 수열이지만, '1 4 4'는 그렇지 않다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;완전 탐색부터 시작하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자를 하나씩으로 조각을 낸 뒤, 한 조각에서 숫자 하나씩을 선택하는 완전 탐색 알고리즘을 만들어 보자.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bja6HK/btsJtgxmEKF/QCuocbHDjQxpQkvMBy5xd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bja6HK/btsJtgxmEKF/QCuocbHDjQxpQkvMBy5xd1/img.png&quot; data-alt=&quot;수열의 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bja6HK/btsJtgxmEKF/QCuocbHDjQxpQkvMBy5xd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbja6HK%2FbtsJtgxmEKF%2FQCuocbHDjQxpQkvMBy5xd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;78&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수열의 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;위와 같은 수열이 있다고 가정한다. 수열의 &lt;code&gt;A[1]&lt;/code&gt;에서 LIS를 만든다고 하면 어떻게 해야할까? 그러면 &lt;code&gt;A[1]&lt;/code&gt;의 값인 &lt;code&gt;2&lt;/code&gt;보다 큰 것을 고르고 재귀 호출을 시키게 되면 이것이 반복되면서 LIS를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;&lt;code&gt;A[j]&lt;/code&gt; 에서의 LIS는 &lt;code&gt;A[j+1 ... n]&lt;/code&gt; 에서 만들어진 LIS와 &lt;code&gt;A[j]&lt;/code&gt;를 합치면 &lt;code&gt;A[j]&lt;/code&gt;의 LIS가 만들어진다는 것&lt;/b&gt;이다. 만약에 이것이 이해가 안된다면 재귀를 완전히 이해하지 못한 것이다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-09-05 오후 4.34.55.png&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b52yRx/btsJsibTXDE/bAkUkbCrQvGzChTRYh11a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b52yRx/btsJsibTXDE/bAkUkbCrQvGzChTRYh11a1/img.png&quot; data-alt=&quot;A[1]일 때, 골라야하는 숫자들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b52yRx/btsJsibTXDE/bAkUkbCrQvGzChTRYh11a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb52yRx%2FbtsJsibTXDE%2FbAkUkbCrQvGzChTRYh11a1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;84&quot; data-filename=&quot;스크린샷 2024-09-05 오후 4.34.55.png&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;A[1]일 때, 골라야하는 숫자들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;파란색 칸의 숫자들을 재귀해서 만들어지는 수열 중 가장 긴 것을 선택해서 &lt;code&gt;A[1]&lt;/code&gt;에 붙이면 &lt;code&gt;A[1]&lt;/code&gt;에서 시작하는 LIS가 만들어지는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;완전 탐색으로 풀어낸 LIS&lt;/h4&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int lis(const vector&amp;lt;int&amp;gt;&amp;amp; A) {
    // 기저 사례: A가 텅 비어 있을 때
    if (A.empty()) return 0;

    int ret = 0;
    for(int i = 0; i &amp;lt; A.size(); ++i) {
        vector&amp;lt;int&amp;gt; B;
        for(int j = i+1; j &amp;lt; A.size(); ++j)
            if(A[i] &amp;lt; A[j])
                B.push_back(A[j]);
        ret = max(ret, 1 + lis(B));
    }
    return ret;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  코드 설명&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기저 사례 (Base Case)&lt;/b&gt;:&lt;/h4&gt;
&lt;pre class=&quot;lisp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;   if (A.empty()) return 0;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트 A가 비어 있으면 0을 반환한다. 더 이상 탐색할 수 있는 값이 없음을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;반환값 초기화&lt;/b&gt;:&lt;/h4&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;   int ret = 0;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과값을 저장할 변수를 0으로 초기화한다. 이 변수는 최대 증가 부분 수열의 길이를 저장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;리스트 순회&lt;/b&gt;:&lt;/h4&gt;
&lt;pre class=&quot;matlab&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;   for(int i = 0; i &amp;lt; A.size(); ++i)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트 A를 처음부터 끝까지 탐색한다. 각 인덱스 i를 기준으로 그 이후의 값을 탐색한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부분 수열을 만들기 위한 리스트 B 생성&lt;/b&gt;:&lt;/h4&gt;
&lt;pre class=&quot;matlab&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;   vector&amp;lt;int&amp;gt; B;
   for(int j = i+1; j &amp;lt; A.size(); ++j)
       if(A[i] &amp;lt; A[j])
           B.push_back(A[j]);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 인덱스 i 이후의 값들을 탐색하며, A[i]보다 큰 값을 찾아 리스트 B에 추가한다. 이는 증가하는 부분 수열을 찾기 위한 과정이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;재귀 호출 및 결과 갱신&lt;/b&gt;:&lt;/h4&gt;
&lt;pre class=&quot;lisp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;   ret = max(ret, 1 + lis(B));&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;B에 대해 다시 lis() 함수를 재귀적으로 호출하고, 그 결과에 1을 더해 ret 값을 갱신한다. 이는 현재 요소를 포함한 LIS의 길이를 계산하는 과정이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;6.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최종 결과 반환&lt;/b&gt;:&lt;/h4&gt;
&lt;pre class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;   return ret;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최종적으로 LIS의 최대 길이를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;최적 부분 구조(Optimal Substructure)로 풀어보기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드를 메모이제이션을 바로 적용하기에는 입력 방식이 배열이기 때문에 cache에 저장시키기 까다롭다. 이 입력을 최적 부분 구조를 쓸 수 있게 바꾸어 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 앞서 &lt;b&gt;&lt;code&gt;(서울, 부산)&lt;/code&gt;의 최단 경로를 찾을 때, &lt;code&gt;(서울, 대전)&lt;/code&gt; 과 &lt;code&gt;(대전, 부산)&lt;/code&gt;에서 각각 최단 거리를 찾으면 &lt;code&gt;(서울, 부산)&lt;/code&gt;의 최단 거리를 구할 수 있다는 사실&lt;/b&gt;을 알 수 있었다. 이 말은 &lt;b&gt;&lt;code&gt;(서울, 대전)&lt;/code&gt;의 최단 거리는 &lt;code&gt;(대전, 부산)&lt;/code&gt;의 최단 거리를 구하는 것과 서로 독립적&lt;/b&gt;이라는 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제에도 이 논리를 적용할 수 있다. &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;code&gt;A[j]&lt;/code&gt;&lt;/span&gt;와 &lt;code&gt;lis(A[j+1 ... n])&lt;/code&gt; &amp;nbsp;서로 &lt;span style=&quot;color: #ee2323;&quot;&gt;독립적&lt;/span&gt;이며, 각각의 최대치를 찾기만 한다면 수열 &lt;code&gt;A&lt;/code&gt;의 LIS를 구할 수 있다. 즉, lis(A[0 .. j]) 의 값은 lis(A[j+1 ... n]) 을 구하는 데 필요하지 않다. 각 부분 문제마다 최대 길이만 찾으면 되는 것이다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;최적 부분 구조를 이용한 LIS&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstring&amp;gt; // memset 사용을 위한 헤더 파일
#include &amp;lt;algorithm&amp;gt;
using namespace std;

int n; // 수열의 길이
int cache[100], A[100]; // 캐시와 수열 배열

// A[start]에서 시작하는 증가 부분 수열 중 최대 길이를 반환하는 함수
int lis(int start) {
    int&amp;amp; ret = cache[start]; // 캐시 배열을 참조형으로 접근

    if (ret != -1) return ret; // 이미 계산된 값이 있으면 반환

    ret = 1; // A[start]는 반드시 포함되므로 길이 1로 시작

    for (int next = start + 1; next &amp;lt; n; ++next) {
        if (A[start] &amp;lt; A[next]) // 증가하는 부분 수열인지 확인
            ret = max(ret, lis(next) + 1); // 최대 길이 갱신
    }

    return ret; // 계산된 길이 반환
}

int main() {
    // 입력 예시: n=6, 수열 A = {5, 6, 7, 1, 2, 8}
    n = 6;
    A[0] = 5; A[1] = 6; A[2] = 7; A[3] = 1; A[4] = 2; A[5] = 8;

    // 캐시 배열을 -1로 초기화 (아직 계산되지 않은 상태)
    memset(cache, -1, sizeof(cache));

    int maxLen = 0; // 최대 증가 부분 수열의 길이를 저장하는 변수

    // 모든 시작점에서 LIS 길이를 계산하여 최댓값을 찾는다.
    for (int begin = 0; begin &amp;lt; n; ++begin)
        maxLen = max(maxLen, lis(begin));

    // 결과 출력
    cout &amp;lt;&amp;lt; &quot;최대 증가 부분 수열의 길이: &quot; &amp;lt;&amp;lt; maxLen &amp;lt;&amp;lt; endl;

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 설명&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 캐시와 입력 배열 선언&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;   int n;
   int cache[100], S[100];&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt;은 수열의 길이를 저장하는 변수다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cache[]&lt;/code&gt; 배열은 이미 계산된 값을 저장하는 캐시 배열이다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S[]&lt;/code&gt; 배열은 입력 수열을 저장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 참조형을 사용한 캐시 접근&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;   int&amp;amp; ret = cache[start];&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐시의 &lt;code&gt;start&lt;/code&gt; 인덱스 값을 참조형 &lt;code&gt;ret&lt;/code&gt;으로 설정한다.&lt;/li&gt;
&lt;li&gt;이를 통해 값을 저장할 때 &lt;code&gt;cache[start]&lt;/code&gt; 대신 &lt;code&gt;ret&lt;/code&gt;에 직접 값을 저장하거나 불러올 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 이미 계산된 값 처리&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;   if (ret != -1) return ret;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;cache[start]&lt;/code&gt;에 값이 이미 저장된 경우, 즉 &lt;code&gt;-1&lt;/code&gt;이 아닌 경우 해당 값을 반환한다. 이렇게 중복 계산을 방지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 기저 사례 처리&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;   ret = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 수열에서 &lt;code&gt;S[start]&lt;/code&gt;는 존재하기 때문에 최소 길이는 &lt;code&gt;1&lt;/code&gt;로 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 다음 요소 탐색을 위한 반복문&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;   for(int next = start+1; next &amp;lt; n; ++next)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt; 이후의 인덱스를 탐색하여 증가하는 부분 수열을 찾기 위한 반복문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 수열의 증가 여부 검사 및 재귀 호출&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;   if(S[start] &amp;lt; S[next])
       ret = max(ret, lis2(next) + 1);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;S[start]&lt;/code&gt;보다 큰 값을 가진 &lt;code&gt;S[next]&lt;/code&gt;를 찾은 경우, 재귀적으로 &lt;code&gt;lis2(next)&lt;/code&gt;를 호출하여 최대 길이를 갱신한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. 최종 결과 반환&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;   return ret;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;재귀 호출이 끝난 후, 계산된 LIS의 길이를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 최적화 문제 동적 계획법 구현 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모이제이션의 구현패턴과 같이 일정한 패턴을 가지고 최적화 문제를 구현하는 것이 좋다. 물론 이 패턴이 모든 문제에 활용할 수 있는 것은 아니지만, 익숙해지기 위해 어떤 식으로 생각해야할 지 대략적인 지침은 될 것 이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;모든 답을 만들어 보고 그 중 &lt;b&gt;최적해의 점수를 반환하는 완전 탐색 알고리즘&lt;/b&gt;을 만든다.&lt;/li&gt;
&lt;li&gt;전체 답의 점수를 반환하는 것이 아닌, 앞으로 남은 선택들에 해당하는 잠수만을 반환하도록 부분 문제 정의를 바꾼다.&lt;/li&gt;
&lt;li&gt;재귀 호출의 입력에 이전의 선택에 관련된 정보가 있다면 꼭 필요한 것만 남기고 줄인다. 최적 부분 구조가 성립한다면 이전 선택에 관련된 정보를 완전히 없앨 수 있다. 여기서 우리의 목표는 최대한 최적 부분 구조가 가능한 구조로 만드는 것이다.&lt;/li&gt;
&lt;li&gt;입력이 배열이거나 문자열인 경우에 가능하다면 적절한 변환을 통해 메모이제이션을 하도록 한다.&lt;/li&gt;
&lt;li&gt;메모이제이션을 적용한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀 ▶️ 메모이제이션 ▶️ 완전 탐색 ▶️ 최적화 부분 문제 순으로 동적 계획법이 어떻게 활용되는지 확인했다. 동적 계획법은 복잡한 문제를 효율적으로 해결하는 매우 강력한 도구다. 이 글에서는 동적 계획법의 개념과 이를 적용한 문제들에 대해 설명하였다. 이항 계수, LCS, LIS와 같은 문제들은 모두 동적 계획법을 사용해 빠르게 해결할 수 있으며, 이를 통해 반복되는 계산을 줄이고 성능을 크게 향상시킬 수 있다.&lt;/p&gt;</description>
      <category>알고리즘/개념</category>
      <category>dp</category>
      <category>memoization</category>
      <category>Optimal Substructure</category>
      <category>다이나믹 프로그래밍</category>
      <category>동적계획법</category>
      <category>메모이제이션</category>
      <category>알고리즘</category>
      <category>최적 부분 구조</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/11</guid>
      <comments>https://choosla.tistory.com/11#entry11comment</comments>
      <pubDate>Thu, 5 Sep 2024 15:57:21 +0900</pubDate>
    </item>
    <item>
      <title>[백준 2339] 석판 자르기 (C++)</title>
      <link>https://choosla.tistory.com/10</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 2339번 문제는 주어진 석판에서 불순물과 보석을 포함한 부분을 자르는 방법의 수를 구하는 문제이다. 불순물(1)과 보석(2)이 섞여있는 석판을 잘라서 불순물이 없는 보석만을 포함하는 영역을 만들려고 한다. 단, 자르는 과정에서 불순물을 반드시 포함해야 하고, 자른 이후 영역에는 하나의 보석만 남아 있어야 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 접근&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제를 읽어보면 우리가 해결해야할 문제가 석판이 잘라질 때마다 두개로 나뉘어 작은 문제가 되는 것을 반복하는 것을 볼 수 있다. 문제가 작아지면서 반복 된다는 것은 재귀를 사용해야 한다는 것을 알 수 있으며, 두개로 나뉘어 진다는 것은 분할 정복에 해당하는 문제라는 것을 유추할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 풀이&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적인 풀이방법은 &lt;b&gt;현 상태의 석판이 자를 수 있는 모든 경우&lt;/b&gt; 이다. 이 말은 재귀적으로 문제를 풀 때, 기저 사례와 문제 분할을 아우러 설명한다.&lt;br /&gt;예시를 들어 설명을 하겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n5Ycf/btsJnXketBF/itJ5mvS8U7GKAgQhmFpCAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n5Ycf/btsJnXketBF/itJ5mvS8U7GKAgQhmFpCAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n5Ycf/btsJnXketBF/itJ5mvS8U7GKAgQhmFpCAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn5Ycf%2FbtsJnXketBF%2FitJ5mvS8U7GKAgQhmFpCAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;402&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1010&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 예제 입력1을 그림으로 표현한 것이다. 우리는 이 석판을 한번 잘라서 두개로 나눈다 했을 때, 어떻게 잘라야할까?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/enciz6/btsJmltheo6/pdLMqpB7CdeJVHwY6eAV00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/enciz6/btsJmltheo6/pdLMqpB7CdeJVHwY6eAV00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/enciz6/btsJmltheo6/pdLMqpB7CdeJVHwY6eAV00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fenciz6%2FbtsJmltheo6%2FpdLMqpB7CdeJVHwY6eAV00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;401&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;문제를 손으로 직접 풀어보면 이렇게 자르면서 시작해야 정답이 나오는 것을 알 수 있다. 하지만 컴퓨터로는 이것을 알고 자를 수가 없다. 즉, 우리는 &lt;b&gt;현재 석판 상태에 대해서 자를 수 있는 모든 경우를 잘라서 다음 하위문제로 된 재귀에서 판단&lt;/b&gt;해야 한다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;1012&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pwks0/btsJmffJG7C/J6sz58Ff0kzsHcaKbggQn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pwks0/btsJmffJG7C/J6sz58Ff0kzsHcaKbggQn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pwks0/btsJmffJG7C/J6sz58Ff0kzsHcaKbggQn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpwks0%2FbtsJmffJG7C%2FJ6sz58Ff0kzsHcaKbggQn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;401&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;1012&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;다음은 우리가 현재 석판에서 보석을 건들지 않고 불순물을 자를 수 있는 모든 경우의 수를 표시한 것이다. 위의 그림과 같이 현재 상태의 석판에서 자를 수 있는 모든 경우의 수를 자른다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이렇게 자르다가 현재 석판이 불순물이 0개 이고, 보석이 1개 남았다면 1을 리턴하는 것이다. &lt;b&gt;하지만 만약에 잘못 자르게 된다면 어떻게 해야할까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;b&gt;잘못 자르게 되면 해당 석판에 보석이 하나도 없게 되는 경우&lt;/b&gt;일 것이다. 하지만 이런 기저 사례를 짜게 된다고 치면 결국 보석이 하나도 남지 않게 될 때까지 재귀를 호출해야하며 이것은 재귀 호출의 대부분의 시간을 차지하는 호출 부분에서 많은 해저드를 발생하게 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 불필요한 호출을 줄이기 위해 우리는 보석이 1개가 되기전에 이것이 &lt;b&gt;잘못 잘렸다는 것을 미리 판단&lt;/b&gt; 할 수 있을까? 그에 대해 간단한 아이디어로 가능하다. &lt;b&gt;현재 석판에서 보석들이 각 조각에 반드시 하나가 존재하게 하려면 (보석의 개수 - 1) == ( 불순물의 개수 )&lt;/b&gt; 가 되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 사실을 가지고 해당 문제의 알고리즘을 정리해본다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;알고리즘 설명&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기저 사례 (Base Cases)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;자르기 불가능한 경우&lt;/b&gt;: (보석의 개수-1) != (불순물의 개수)인 경우, 0을 반환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보석이 하나만 남은 경우&lt;/b&gt;: 해당 영역에 보석이 하나만 존재하고 불순물이 없다면, 1을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 재귀적 분할 (Recursive Case)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가로로 자르기&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이전에 세로로 잘랐다면, 가로로 자르기&lt;/li&gt;
&lt;li&gt;각 불순물의 y 좌표(가로)를 확인하고, 해당 좌표에 보석이 없으면 그 지점을 기준으로 가로로 자른다&lt;/li&gt;
&lt;li&gt;자른 두 조각에 대해 재귀적으로 &lt;code&gt;func&lt;/code&gt;를 호출&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세로로 자르기&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이전에 가로로 잘랐다면, 세로로 자르기&lt;/li&gt;
&lt;li&gt;각 불순물의 x 좌표(세로)를 확인하고, 해당 좌표에 보석이 없으면 그 지점을 기준으로 세로로 자른다&lt;/li&gt;
&lt;li&gt;자른 두 조각에 대해 재귀적으로 &lt;code&gt;func&lt;/code&gt;를 호출&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초기 상태&lt;/b&gt;: 가로, 세로 모두 자른다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 최종 결과 합산&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각각의 자르기 방법에서 얻어진 결과들을 모두 합산하여 최종적으로 가능한 경우의 수를 도출&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &quot;bits/stdc++.h&quot;

using namespace std;

int seq[20][20];

// 주어진 석판 영역을 가로 또는 세로로 자를 수 있는 방법의 수를 재귀적으로 계산하는 함수
// y1, y2: 현재 영역의 시작과 끝 y좌표
// x1, x2: 현재 영역의 시작과 끝 x좌표
// d: 이전에 자른 방향 (0: 가로, 1: 세로, -1: 처음 자르기)
int func(int y1, int y2, int x1, int x2, int d)
{
    int star = 0;  // 현재 영역의 별(2)의 개수
    int dust = 0;  // 현재 영역의 불순물(1)의 개수

    vector&amp;lt;int&amp;gt; yStarCoordi;  // 별의 y좌표를 저장하는 벡터
    vector&amp;lt;int&amp;gt; xStarCoordi;  // 별의 x좌표를 저장하는 벡터

    vector&amp;lt;int&amp;gt; yDustCoordi;  // 불순물의 y좌표를 저장하는 벡터
    vector&amp;lt;int&amp;gt; xDustCoordi;  // 불순물의 x좌표를 저장하는 벡터

    // 현재 영역에서 별과 불순물의 좌표를 기록하고 개수를 센다
    for (int i = y1; i &amp;lt; y2; i++)
    {
        for (int j = x1; j &amp;lt; x2; j++)
        {
            if (seq[i][j] == 2)
            {
                yStarCoordi.push_back(i);
                xStarCoordi.push_back(j);
                star++;
            }

            if (seq[i][j] == 1)
            {
                yDustCoordi.push_back(i);
                xDustCoordi.push_back(j);
                dust++;
            }
        }
    }

    // 기저 사례 1: 나눌 수 없는 경우, 0을 반환
    if ((star - 1) - dust != 0)
        return 0;

    // 기저 사례 2: 이미 완성된 경우, 1을 반환
    if (dust == 0 &amp;amp;&amp;amp; star == 1)
        return 1;

    int ret = 0;  // 가능한 자르기 방법의 수를 저장하는 변수

    // 이전에 가로로 자르지 않았다면, 가로로 자르기를 시도
    if (d != 0)
    {
        for (int i = 0; i &amp;lt; yDustCoordi.size(); i++)
        {
            int isStar = 0;
            for (int j = 0; j &amp;lt; yStarCoordi.size(); j++)
            {
                if (yDustCoordi[i] == yStarCoordi[j])
                {
                    isStar = 1;
                    break;
                }
            }
            // 같은 y좌표에 별이 없다면 가로로 자르고, 결과를 재귀적으로 계산
            if (!isStar)
            {
                ret += func(y1, yDustCoordi[i], x1, x2, 0) * func(yDustCoordi[i] + 1, y2, x1, x2, 0);
            }
        }
    }

    // 이전에 세로로 자르지 않았다면, 세로로 자르기를 시도
    if (d != 1)
    {
        for (int i = 0; i &amp;lt; xDustCoordi.size(); i++)
        {
            int isStar = 0;
            for (int j = 0; j &amp;lt; xStarCoordi.size(); j++)
            {
                if (xDustCoordi[i] == xStarCoordi[j])
                {
                    isStar = 1;
                    break;
                }
            }
            // 같은 x좌표에 별이 없다면 세로로 자르고, 결과를 재귀적으로 계산
            if (!isStar)
            {
                ret += func(y1, y2, x1, xDustCoordi[i], 1) * func(y1, y2, xDustCoordi[i] + 1, x2, 1);
            }
        }
    }

    return ret;  // 현재 영역에서 가능한 자르기 방법의 수를 반환
}

int main(int argc, char const *argv[])
{
    ios::sync_with_stdio(0);  // 입출력 속도 향상
    cin.tie(0);  // 입력과 출력을 비동기적으로 처리하지 않음

    int n;  // 석판의 크기 (n x n)
    cin &amp;gt;&amp;gt; n;

    // 석판의 상태를 입력받아 배열에 저장
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (int j = 0; j &amp;lt; n; j++)
        {
            cin &amp;gt;&amp;gt; seq[i][j];
        }
    }

    // 전체 석판에 대해 자르기 함수를 호출하여 가능한 방법의 수 계산
    int ret = func(0, n, 0, n, -1);

    // 결과가 0이면 자르기 불가능하므로 -1을 출력, 그렇지 않으면 가능한 방법의 수 출력
    if (ret == 0)
    {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; endl;
    }
    else
    {
        cout &amp;lt;&amp;lt; ret &amp;lt;&amp;lt; endl;
    }
    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/백준</category>
      <category>C++</category>
      <category>CPP</category>
      <category>백준</category>
      <category>분할정복</category>
      <category>알고리즘</category>
      <category>재귀</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/10</guid>
      <comments>https://choosla.tistory.com/10#entry10comment</comments>
      <pubDate>Sat, 31 Aug 2024 12:59:16 +0900</pubDate>
    </item>
    <item>
      <title>[백준 1030] 프렉탈 평면 (C++)</title>
      <link>https://choosla.tistory.com/9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 평범한 재귀와 분할 정복으로 풀어볼려고 했지만 열심히 풀어본 결과 단순히 반복문으로도 풀리는 경우의 문제였다. 물론 재귀적 사고와 분할 정복의 개념을 반복문으로 풀어 쓴 것이다. 반복문으로도 충분히 재귀와 같은 효과를 낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적인 풀이는 &lt;b&gt;범위 R1, R2, C1, C2에 대해서 각 픽셀당 검정색 칸인가 판별&lt;/b&gt;하는 알고리즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째, 제일 중요하게 생각한 것은 &lt;b&gt;큰 문제부터 시작하여 작은 문제로 푸는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본문의 예시에서는 s=1 일 때 부터의 예시를 들어서 설명하고 있지만 재귀와 분할정복을 활용하기 위해서는 큰 문제로 부터 시작하여 작은 문제로 줄여가면서 판단해야 한다. 또한 이 문제는 단순히 재귀를 활용하면 경우의 수가 실행시간을 넘어서기 때문에 분할 정복 기법도 사용하여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째로 집중해서 생각한 것은 &lt;b&gt;검정색 칸의 범위&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 가로 세로가 같은 정사각형 모양이니 편하게 가로, 세로 중 하나에 집중해서 생각했다. 일정한 &lt;b&gt;'비율'&lt;/b&gt;을 가지고 검정색 칸이 커지기 때문이다. 문제를 보면 검정색의 길이는 ( 현재 변의 길이 ) * ( K / N ) 로 줄어든 다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 그림으로 더 자세히 이해해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Uke7m/btsJggrQjiF/tAxcnU3JjX3vYa78Yk7rD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Uke7m/btsJggrQjiF/tAxcnU3JjX3vYa78Yk7rD1/img.png&quot; data-alt=&quot;문제 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Uke7m/btsJggrQjiF/tAxcnU3JjX3vYa78Yk7rD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUke7m%2FbtsJggrQjiF%2FtAxcnU3JjX3vYa78Yk7rD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;246&quot; height=&quot;253&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;문제 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N=3, K=1, s=2 일 때의 예시 그림을 보여주고 있다. 즉 하얀색 블럭이 3칸이고 검정색 블럭이 1칸이었을 때, s=2이 된다면 이런 그림이 된다는 것이다. 이 구조를 보면 어떠한 패턴으로 그림이 확장되는지 볼 수 있다. 위의 그림은 두 개로 분리하여 생각할 수 있는데 아래 그림과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdgecu/btsJhaRQWhs/lxakDm1vd4moD8wlCkJbgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdgecu/btsJhaRQWhs/lxakDm1vd4moD8wlCkJbgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdgecu/btsJhaRQWhs/lxakDm1vd4moD8wlCkJbgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdgecu%2FbtsJhaRQWhs%2FlxakDm1vd4moD8wlCkJbgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;353&quot; height=&quot;227&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;1028&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Db4dP/btsJfSEI3HN/2DaHkmqH92AFstFaKqoSs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Db4dP/btsJfSEI3HN/2DaHkmqH92AFstFaKqoSs1/img.png&quot; data-alt=&quot;s=2 일때, s=2 모양 안에 s=1 모양이 있다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Db4dP/btsJfSEI3HN/2DaHkmqH92AFstFaKqoSs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDb4dP%2FbtsJfSEI3HN%2F2DaHkmqH92AFstFaKqoSs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;257&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;1028&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;s=2 일때, s=2 모양 안에 s=1 모양이 있다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽의 큰 사각형에 오른쪽 사각형이 8개가 들어가 있는 것을 볼 수 있다. 이것을 보면 큰 사각형이든 작은 사각형이든 이 문제의 검정색 부분은 일정한 비율을 가지고 있는 것을 알 수 있다. 즉, 맨 처음에 말했듯이 ( 현재 변의 길이 ) * ( K / N ) 으로 나타낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 번째로 집중해서 생각한 것은 &lt;b&gt;s가 줄어들 때 좌표의 변동&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 큰 문제에서 작은 문제로 가는 것을 생각해야 하기 때문에, 어떠한 x,y 좌표가 주어졌을 떄 &lt;b&gt;s가 줄어듦에 따라 x,y가 어떻게 변화하는지에 대해 생각&lt;/b&gt;을 해야한다. 두 번째에서 설명했듯이 검은색 칸(K)과 같이 전체 크기(N)도 일정하게 줄어드는 것을 생각해 낼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;1032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/464VT/btsJhY5pYql/kv2xkbbugHUMBSUuYCqqRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/464VT/btsJhY5pYql/kv2xkbbugHUMBSUuYCqqRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/464VT/btsJhY5pYql/kv2xkbbugHUMBSUuYCqqRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F464VT%2FbtsJhY5pYql%2Fkv2xkbbugHUMBSUuYCqqRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;309&quot; height=&quot;306&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;1032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;R1, R2, C1, C2 범위 중 위 빨간색 점이 검정인지 판단한다고 생각해보자. s=2일 때, 해당 점은 검정색이 아니니 우리는 s=1로 문제를 분할하여 생각해야 한다. 그럼 빨간색 점의 x,y를 그대로 매개변수로 넘겨서 재귀를 시켜야 하는가? 라고 생각하기엔 여러모로 복잡하게 풀려야 할 것이다. 하지만 s=2에서 그림을 보자면 중앙의 3x3 검은색 칸 주위로 3x3짜리 s=1일 때의 블럭들이 있는 것이 보인다. 즉, &lt;b&gt;좌표를 축소시켜 하위레벨로 해당 좌표를 넘겨야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uUYq4/btsJiibohbQ/dTNMUyG5kH31pZ3ziyHOM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uUYq4/btsJiibohbQ/dTNMUyG5kH31pZ3ziyHOM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uUYq4/btsJiibohbQ/dTNMUyG5kH31pZ3ziyHOM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuUYq4%2FbtsJiibohbQ%2FdTNMUyG5kH31pZ3ziyHOM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;188&quot; height=&quot;191&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 위의 그림과 같이 우리는 해당 x,y 값을 s=1으로 재귀호출 할 때, 각각의 작은 블럭들의 왼쪽 맨위가 x=0, y=0이 되는 절대좌표로 매개변수 값으로 넘겨야 한다. 해당 좌표를 구하는 방법은 &lt;b&gt;s-1의 변의 길이를 구한다음 현재 좌표에 '나머지 연산'&lt;/b&gt;을 하면 구해진다. s-1일 때의 x,y의 좌표는 ( x or y ) % { ( 현재 변의 길이 ) / n } 이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A0Eaf/btsJhPHxxfR/QAVyuEFpma7kcI2dAWZ4N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A0Eaf/btsJhPHxxfR/QAVyuEFpma7kcI2dAWZ4N1/img.png&quot; data-alt=&quot;하위 레벨로 갈 때, x,y 좌표의 축소&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A0Eaf/btsJhPHxxfR/QAVyuEFpma7kcI2dAWZ4N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA0Eaf%2FbtsJhPHxxfR%2FQAVyuEFpma7kcI2dAWZ4N1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;453&quot; height=&quot;357&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하위 레벨로 갈 때, x,y 좌표의 축소&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 알고리즘을 간단히 설명하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복 : s = 0이 될 때까지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 현재 프렉탈 모형의 변 길이를 구한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 현재 프렉탈 모형의 검정색 부분 변 길이를 구한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 2번의 길이를 통해 검정색의 시작 좌표와 끝 좌표를 구한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 현재 s에서 좌표 x,y가 검정색인지 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. x,y 좌표를 축소 시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. s = s-1&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &quot;bits/stdc++.h&quot;

using namespace std;

bool func(int y, int x, int s, int n, int k)
{
    while (s &amp;gt; 0)
    {
        int whiteLength = pow(n, s);                      // 현재 스케일의 전체 크기
        int blackLength = whiteLength / n * k;            // 현재 스케일의 검은색 부분 크기
        int blackStart = (whiteLength - blackLength) / 2; // 검은색 시작 좌표
        int blackEnd = blackStart + blackLength;          // 검은색 끝 좌표

        // 현재 레벨의 검은색 영역에 포함되는지 체크
        if (y &amp;gt;= blackStart &amp;amp;&amp;amp; y &amp;lt; blackEnd &amp;amp;&amp;amp; x &amp;gt;= blackStart &amp;amp;&amp;amp; x &amp;lt; blackEnd)
        {
            return true;
        }

        // 좌표를 축소시켜 하위 레벨로 이동
        y %= whiteLength / n;
        x %= whiteLength / n;

        s--;
    }
    return false;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int s, n, k, r1, r2, c1, c2;
    cin &amp;gt;&amp;gt; s &amp;gt;&amp;gt; n &amp;gt;&amp;gt; k &amp;gt;&amp;gt; r1 &amp;gt;&amp;gt; r2 &amp;gt;&amp;gt; c1 &amp;gt;&amp;gt; c2;

    for (int i = r1; i &amp;lt;= r2; i++)
    {
        for (int j = c1; j &amp;lt;= c2; j++)
        {
            if (func(i, j, s, n, k))
            {
                cout &amp;lt;&amp;lt; &quot;1&quot;;
            }
            else
            {
                cout &amp;lt;&amp;lt; &quot;0&quot;;
            }
        }
        cout &amp;lt;&amp;lt; &quot;\n&quot;;
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/백준</category>
      <category>C++</category>
      <category>CPP</category>
      <category>백준</category>
      <category>분할정복</category>
      <category>알고리즘</category>
      <category>재귀</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/9</guid>
      <comments>https://choosla.tistory.com/9#entry9comment</comments>
      <pubDate>Wed, 28 Aug 2024 11:43:32 +0900</pubDate>
    </item>
    <item>
      <title>candidate function not viable: expects an lvalue for nth argument</title>
      <link>https://choosla.tistory.com/8</link>
      <description>&lt;h2&gt;오류 메시지&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckn4ri/btsI8XrUHCI/tS7NxMvbmnO8nSOVPLdLOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckn4ri/btsI8XrUHCI/tS7NxMvbmnO8nSOVPLdLOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckn4ri/btsI8XrUHCI/tS7NxMvbmnO8nSOVPLdLOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckn4ri%2FbtsI8XrUHCI%2FtS7NxMvbmnO8nSOVPLdLOk%2Fimg.png&quot; width=&quot;100%&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;문제가 되었던 코드 예시&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;void func(string s,iterator&amp;amp; it){
    char head = *(it++);
    cout &amp;lt;&amp;lt; head &amp;lt;&amp;lt; endl;
}

int main(int argc, char const *argv[]){
    string s;
    cin &amp;gt;&amp;gt; s;
    func(s, s.begin());

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;iterator(반복자)를 이용해 string 클래스로 선언된 문자열을 순회하기 위해 해당 코드를 작성하고 실행을 했을 때, 위의 오류 메시지가 떴다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;candidate function not viable: expects an lvalue for 2st argument&lt;/h3&gt;
&lt;hr&gt;
&lt;p&gt;현재 터미널에서 &amp;#39;적합한 함수 후보가 없음 : 첫 번째 인자로 lvalue가 필요합니다.&amp;#39; 라고 말하고 있다. 그렇다면 lvalue는 대체 무엇일까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lvalue : 메모리의 주소를 가지며, 참조 가능한 객체(&amp;amp;)를 나타낸다. 변수, 배열요소, 역참조 포인터 등을 말한다.&lt;/li&gt;
&lt;li&gt;rvalue : 일반적으로 임시 값으로, 메모리에 저장되지 않거나 참조할 수 없는 값이다. 예를 들어, 리터럴 상수, 임시 객체, 함수 반환값 등을 말한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위의 설명을 보면 현재 컴파일러는 lvalue를 원하지만 main()에서 func를 호출할 때 전달한 매개변수 값으로는 &lt;strong&gt;s.begin()&lt;/strong&gt; 이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;s.begin()&lt;/strong&gt;가 틀린 중요한 이유는 rvalue에 해당하는 임시 객체를 반환한다는 것이다. &lt;/p&gt;
&lt;h2&gt;해결&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;void func(string s,iterator&amp;amp; it){
    char head = *(it++);
    cout &amp;lt;&amp;lt; head &amp;lt;&amp;lt; endl;
}

int main(int argc, char const *argv[]){
    string s;
    cin &amp;gt;&amp;gt; s;
    string::it = s.begin();
    func(s, it);

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;단순하게 임시값(rvalue)으로 된 s.begin()을 참조 가능한 객체인 string::iterator()로 저장시켜서 매개변수로 넘기면 해결된다. &lt;/p&gt;</description>
      <category>디버깅</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/8</guid>
      <comments>https://choosla.tistory.com/8#entry8comment</comments>
      <pubDate>Mon, 19 Aug 2024 23:37:01 +0900</pubDate>
    </item>
    <item>
      <title>알고리즘 분석</title>
      <link>https://choosla.tistory.com/5</link>
      <description>&lt;p&gt;&lt;strong&gt;알고리즘&lt;/strong&gt;은 어떠한 작업을 수행하는 &lt;strong&gt;절차의 집합&lt;/strong&gt;을 의미한다.&lt;/p&gt;
&lt;p&gt;알고리즘에는 크게 두 가지 속성이 존재한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;정확성&lt;/strong&gt;(correctness) 알고리즘은 정확해야 한다. 주어진 입력을 모두 처리하고 올바르게 출력해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;효율성&lt;/strong&gt;(effciency) 알고리즘은 효율적으로 해결해야 한다. 효율성은 두 가지 변수로 측정하게 된다. 첫째, &lt;strong&gt;시간복잡도&lt;/strong&gt;(time complexity)는 알고리즘이 얼마나 빠르게 결과를 출력하는지 측정합니다. 둘째, &lt;strong&gt;공간 복잡도&lt;/strong&gt;(space complexity)는 원하는 결과를 얻기 위해 알고리즘이 메모리를 얼마나 사용하는지 측정한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;즉, 알고리즘은 &lt;strong&gt;정확성&lt;/strong&gt;과 &lt;strong&gt;효율성&lt;/strong&gt;이 중요하다.&lt;/p&gt;
&lt;h2&gt;1.1 점근적 분석&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;점근적 분석(asymptotic analysis)은 데이터 집합이나 프로그래밍 언어와 관계없이 알고리즘 자체의 효율성을 비교하는 데 사용합니다. 일반적으로 알고리즘의 &lt;strong&gt;증가 차수&lt;/strong&gt;(order of growth)에 관심이 있고 알고리즘을 실행하는 데 걸리는 정확한 시간에는 관심이 없습니다. 이때 관심을 가지는 그 시간을 &lt;strong&gt;점근적 실행 시간&lt;/strong&gt;(asymptotic running time)이라고 합니다.&lt;/p&gt;
&lt;h3&gt;1.1.1 빅오 표기법&lt;/h3&gt;
&lt;p&gt;모든 \(n \geq n_{0}\) 에 대해 조건 \(f(n) \leq cg(n)\)을 만족하는 두 양의 상수 \(c\)와 \(n_{0}\)이 있다면 \(f(n)\)은 \(g(n)\)의 &lt;strong&gt;빅오&lt;/strong&gt;(big-O) 또는 \(f(n)=O(g(n))\)이다.&lt;/p&gt;
&lt;p&gt;\(cg(n)\)은 모든 \(n \geq n_{0}\)에 대해 \(f(n)\)의 &lt;strong&gt;상한&lt;/strong&gt;(upper bound)이다. 이때 함수 \(f(n)\)의 증가 속도는 \(cg(n)\)보다 느립니다. 입력 크기 \(n\)이 충분히 크면 항상 \(cg(n)\)이 \(f(n)\)보다 크다.&lt;/p&gt;
&lt;p&gt;말은 어렵게 되어 있지만 결국 점근적 분석을 수식으로 다시 표현해서 말한 것이다. 방금 설명한 증가 차수를 \(f(n)\)이라고 할 수 있고, 나머지 다른 요인들은 상수취급을 한다는 뜻이다.&lt;/p&gt;
&lt;p&gt;제일 유명한 표기법으로는 빅오 표기법이 있지만, &lt;strong&gt;하한&lt;/strong&gt;(lower bound)로 표기하는 &lt;strong&gt;오메가 표기법&lt;/strong&gt;과 빅오와 오메가를 함께 사용하여 &lt;strong&gt;점근적 근접 한계값&lt;/strong&gt;(asymptotically tight bound)도 존재한다.&lt;/p&gt;
&lt;h2&gt;1.2 알고리즘 복잡도 분석&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;최악의 복잡도&lt;/strong&gt;(worst case complexity) : 입력 크기 n에 대한 문제를 풀 때 최악의 성능을 내는 복잡도이다. 알고리즘 실행 시간의 상한을 계산한다. 가장 많이 사용하는 분석&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;평균적인 복잡도&lt;/strong&gt;(average case complexity) : 평균적인 성능을 내는 복잡도이다. 가능한 모든 입력에 대한 실행 시간을 계산해 그 평균을 취하는 것. 평균을 계산하는 것이 어렵고 복잡하여 잘 사용하지 않음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;최선의 복잡도&lt;/strong&gt;(base case complexity) : 최선의 성능을 내는 복잡도. 이것도 잘 사용하지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1.2.1 시간 복잡도&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;이름&lt;/th&gt;
&lt;th&gt;표기법&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;상수(contant) 시간&lt;/td&gt;
&lt;td&gt;\(O(1)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;로그(loggarithmic) 시간&lt;/td&gt;
&lt;td&gt;\(O(logn)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선행(linear) 시간&lt;/td&gt;
&lt;td&gt;\(O(n)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N 로그 N(N Log N) 시간&lt;/td&gt;
&lt;td&gt;\(O(nlogn)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이차(quadratic) 시간&lt;/td&gt;
&lt;td&gt;\(O(n^2)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;다항(polynomial) 시간&lt;/td&gt;
&lt;td&gt;\(O(n^c)\), c는 1보다 큰 상수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지수(exponential) 시간&lt;/td&gt;
&lt;td&gt;\(O(c^m)\), c는 1보다 큰 상수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;계승(factorial) 또는 n의 n승(N-power-N) 시간&lt;/td&gt;
&lt;td&gt;\(O(n!)\) 또는 \(O(n^n)\)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;상수 시간 O(1)&lt;/h4&gt;
&lt;p&gt;입력 크기와 상관없이 결과를 고정된(상수) 시간에 계산한다면 알고리즘이 &lt;strong&gt;상수 시간&lt;/strong&gt;(contant time)에 실행된다고 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;배열의 n번째 원소에 접근하기&lt;/li&gt;
&lt;li&gt;스택에 넣고 빼기&lt;/li&gt;
&lt;li&gt;큐에 삽입하고 삭제하기&lt;/li&gt;
&lt;li&gt;해시 테이블의 원소에 접근하기&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;선형시간 O(n)&lt;/h4&gt;
&lt;p&gt;알고리즘의 실행 시간이 입력 크기에 정비례하면 알고리즘이 &lt;strong&gt;선형 시간&lt;/strong&gt;(linear time)에 실행된다고 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;배열에서 원소 검색, 최솟값 찾기 등의 연산&lt;/li&gt;
&lt;li&gt;연결 리스트에서 순회(traversal), 최솟값 찾기, 최댓값 찾기 등의 연산&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;로그 시간 O(logn)&lt;/h4&gt;
&lt;p&gt;알고리즘의 실행 시간이 입력 크기의 로그에 비례하면 알고리즘이 &lt;strong&gt;로그 시간&lt;/strong&gt;(logarithmic time)에 실행된다고 한다. 이때 알고리즘의 각 단계에서 입려그이 상당 부분(절반)을 방문하지 않고 지나간다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이진 검색(binary search) 알고리즘&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;N 로그 N 시간 O(nlogn)&lt;/h4&gt;
&lt;p&gt;알고리즘의 실행 시간이 입력 크기와 입력 크기의 로그 곱에 비례하면 알고리즘이 &lt;strong&gt;N 로그 N 시간&lt;/strong&gt;(N Log N time)에 실행된다. 이런 알고리즘은 입력을 절반(또는 일부 비율)으로 나눌떄 마다 각 부분을 도릭접으로 처리한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;병합 정렬(merge sort)&lt;/li&gt;
&lt;li&gt;퀵 정렬(quick sort) - 평균적인 성능에 한해서&lt;/li&gt;
&lt;li&gt;힙 정렬(heap sort)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;이차 시간 O(n^2)&lt;/h4&gt;
&lt;p&gt;알고리즘의 실행 시간이 입력 크기의 제곱에 비례하면 알고리즘이 &lt;strong&gt;이차 시간&lt;/strong&gt;(quadratic time)에 실행된다고 한다. 이런 아록리즘은 각 원소(element)를 다른 모든 원소와 비교한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;버블 정렬(bubble sort)&lt;/li&gt;
&lt;li&gt;선택 정렬(selection sort)&lt;/li&gt;
&lt;li&gt;삽입 정렬(insertion sort)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.2.2 알고리즘의 함수 실행 시간 도출&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;상수&lt;/strong&gt; 각 구문을 실행하는 데 상수 시간이 걸리며, 시간복잡도는 O(1) 이다.&lt;br&gt;&lt;strong&gt;반복문&lt;/strong&gt; 반복문의 실행 시간은 반복문 내 구문의 실행 시간과 반복 횟수의 곱이다. 시간 복잡도는 O(n) 이다.&lt;br&gt;&lt;strong&gt;중첩 반복문&lt;/strong&gt; 중접 반복문의 실행 시간은 모든 반복문의 크기의 곱과 반복문 내 구문의 실행 시간을 곱한 것이다. 반복문의 수를 c라고 할때 시간 복잡도는 \(O(n^c)\)이다. 반복문이 2개라면 시간 복잡도는 \(O(n^2)\)이 된다.&lt;br&gt;&lt;strong&gt;연속 구문&lt;/strong&gt; 연속된 구문의 실행 시간을 모두 더하면 된다.&lt;br&gt;&lt;strong&gt;if-else구문&lt;/strong&gt; if나 else 중 실행 시간이 더 많이 걸리는 블록을 선택하고 나머지 블록은 무시한다.&lt;br&gt;&lt;strong&gt;로그 구문&lt;/strong&gt; 각 반복마다 입력 크기가 일정(상수 인자만큼)하게 감소한다. 시간 복잡도는 \(O(logn)\)이다.&lt;/p&gt;
&lt;h2&gt;1.3 시간 복잡도 예제&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;int fun1(int n) {
    int m = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        m += 1;
    }

    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간 복잡도는 \(O(n)\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun2(int n) {
    int i, j, m = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (int j = 0; j &amp;lt; n; j++)
        {
            m += 1;
        }
    }

    return m;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간복잡도는 \(O(n^2)\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun3(int n) {
    int i, j, m = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (int j = 0; j &amp;lt; i; j++)
        {
            m += 1;
        }
    }

    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간 복잡도는 \(O(n + (n-1) + (n-2) + ... + 1) == O(n(n+1)/2) == O(n^2)\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun4(int n) {
    int i, m = 0;
    i = 1;
    while(i &amp;lt; n) {
        m += 1;
        i = i * 2;
    }
    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간복잡도는 곱하기 2를 함으로 문제의 크기를 절반으로 줄여나가기 때문에 \(log(n)\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun5(int n) {
    int i, m = 0;
    i = n;
    while (i &amp;gt; 0) {
        m += 1;
        i = i / 2;
    }

    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간잡도는 전체 n개의 문제의 크기에서 /2 를 함으로 절반으로 줄여나가기 때문에 앞선 것과 같이 \(log(n)\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun6(int n) {
    int i, j, m = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (int j = 0; j &amp;lt; n; j++)
        {
            m += 1;
        }
    }
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (int k = 0; k &amp;lt; n; k++)
        {
            m += 1;
        }
    }
    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간복잡도는 두개의 시간 복잡도를 더함으로 \(O(n^2) + O(n^2) = O(n^2)\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun7(int n) {
    int i, j, m = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (int j = 0; j &amp;lt; sqrt(n); j++)
        {
            m += 1;
        }
    }
    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간복잡도는 \(O(n * \sqrt{n}) = O(n^{3/2})\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun8(int n) {
    int i, j, m = 0;
    for (int i = n; i &amp;gt; 0; i /= 2)
    {
        for (int j = 0; j &amp;lt; i; j++)
        {
            m += 1;
        }
    }
    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;시간복잡도는 반복문을 잘 보면 처음에는 n 만큼 반복하다가 다음에는 n/2 + n/4 + ... + 순으로 반복되기 때문에 log(n)보다는 실행시간이 크다고 볼 수 있기 때문에 \(O(n)\)이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun9(int n) {
    int i, j, m = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (j = i; j &amp;gt; 0; j--)
        {
            m += 1;
        }
    }
    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;등차수열이기 때문에 시간복잡도는 \(O(n^2)\) 이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun10(int n) {
    int i, j = 0, m = 0;
    for (int i = 0; i &amp;lt; n; i++)
    {
        for (; j &amp;lt; n; j++)
        {
            m += 1;
        }
    }
    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;반복문의 안을 잘보면 j를 초기화 시키지 않았기 때문에 시간복잡도는 \(O(n)\)이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int fun11(int n) {
    int i, j, m = 0;
    for (int i = 1; i &amp;lt;= n; i *= 2)
    {
        for (int j = 0; j &amp;lt;= i; j++)
        {
            m += 1;
        }
    }
    return m;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;해당 반복문은 1, 2, 4, ..., n 번 반복하기 때문에 \(O(n)\)이다.&lt;/p&gt;</description>
      <category>알고리즘/실전대비 C알고리즘 인터뷰</category>
      <category>알고리즘</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/5</guid>
      <comments>https://choosla.tistory.com/5#entry5comment</comments>
      <pubDate>Fri, 9 Jun 2023 00:53:01 +0900</pubDate>
    </item>
    <item>
      <title>[백준 2961] 도영이가 만든 맛있는 음식(JAVA)</title>
      <link>https://choosla.tistory.com/3</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 백준 문제에서 알고리즘 분류로 '브루트포스 알고리즘'과 '비트마스킹'이라는 것이 힌트로 나와있길래 &lt;b&gt;비트마스킹&lt;/b&gt;을 사용하여 문제를 해결하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BitArrayBuilder 라는 클래스를 따로 만들어주어서 생성자로 비트 열의 사이즈를 정하도록 되어있는데, 도영이의 재료 N개를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'마스킹' 이라하면 여러 군데 특히 포토샵을 조금 써보신 분들이라면 익숙하실 탠데, &lt;b&gt;마스킹(Masking) 기법&lt;/b&gt;은 어떤 배열을 대상으로 하여 배열 내 모든 값들 중 특정한 조건을 만족하는 것들만 선별하는 기법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 어떻게 사용했었냐면, &lt;b&gt;비트가 1에 위치한 것들만 추출하여 계산하여 최솟값을 찾는 방법을 택했다&lt;/b&gt;. 4비트라고 했을 때, 우리는 0000~1111까지 서로 겹치지 않는 방법으로 모든 것을 확인할 수 있다. 0000, 0001, 0010, .... , 1111&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이트 예제3) N = 4 일 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비트가 1000 이라면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S B | 비트마스크&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 7 | 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2 6 | 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 8 | 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4 9 | 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 7 만 뽑혔으니 서로 빼서 최솟값으로 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비트가 1010 이라면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S B | 비트마스크&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 7 | 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2 6 | 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 8 | 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4 9 | 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 7 과 3 8이 뽑혔으니 1과 3은 곱하고(S) 7과 8은 더해서(B) 서로 뺀 다음 방금 전의 최솟값과 비교&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 0000부터 1111까지 계산한 다음 최솟값을 출력하면 정답이다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Main {

    public static void main(String[] args) throws IOException {

        //필요한 변수들
        int size = 0;
        ArrayList&amp;lt;Integer&amp;gt; S = new ArrayList&amp;lt;Integer&amp;gt;();
        ArrayList&amp;lt;Integer&amp;gt; B = new ArrayList&amp;lt;Integer&amp;gt;();
        int min = Integer.MAX_VALUE;

        //사용자 값 입력받기
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        size = Integer.parseInt(reader.readLine());
        for (int i = 0; i &amp;lt; size; i++) {
            String tmp = reader.readLine();
            String[] strTmp = tmp.split(&quot; &quot;);

            S.add(Integer.parseInt(strTmp[0]));
            B.add(Integer.parseInt(strTmp[1]));
        }


        // 여기서 부터 알고리즘 시작
        BitArrayBuilder bitArrayBuilder = new BitArrayBuilder(size);

        for (int i = 1; i &amp;lt;= bitArrayBuilder.getMaxValue(); i++) {
            ArrayList&amp;lt;Byte&amp;gt; tmp = bitArrayBuilder.getBitArray(i);

            int mulS = 1;
            int mulB = 0;

            for (int j = 0; j &amp;lt; tmp.size(); j++) {
                if(tmp.get(j)!=0){
                    mulS *= S.get(j);
                    mulB += B.get(j);
                }
            }

            int result = Math.abs((mulS - mulB));
            if(min &amp;gt; result){
                min = result;
            }
        }

        System.out.println(min);

    }
}

class BitArrayBuilder{
    int size;

    BitArrayBuilder(int size){
       this.size = size;
    }

    public void setSize(int size){
        this.size = size;
    }

    public int getSize(){
        return this.size;
    }
    ArrayList&amp;lt;Byte&amp;gt; getBitArray(int value){

        if(value&amp;gt;getMaxValue()){
            System.out.println(&quot;허용범위 초과!&quot;);
            return null;
        }

        ArrayList&amp;lt;Byte&amp;gt; tmp = new ArrayList&amp;lt;Byte&amp;gt;();
        for (int i = 0; i &amp;lt; this.size; i++) {
            tmp.add(Byte.parseByte(&quot;0&quot;));
        }

        int val = value;

        int i = 0;
        while(val!=0){
            int remain = val % 2;
            val = val / 2;

            if(remain == 0){
                tmp.set(i, Byte.parseByte(&quot;0&quot;));
            }else{
                tmp.set(i, Byte.parseByte(&quot;1&quot;));
            }

            i++;
        }
        return tmp;
    }

    int getMaxValue(){
        int sum = 1;
        for (int i = 1; i &amp;lt; this.size; i++) {
            int tmp = 1;
            for (int j =0; j&amp;lt;i ; j++){
                tmp = tmp * 2;
            }
            sum += tmp;
        }

        return sum;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/백준</category>
      <category>java</category>
      <category>백준</category>
      <category>백준 2961</category>
      <category>백준 2961 java</category>
      <category>백준 알고리즘</category>
      <category>비트 마스크</category>
      <author>세균없는세균맨</author>
      <guid isPermaLink="true">https://choosla.tistory.com/3</guid>
      <comments>https://choosla.tistory.com/3#entry3comment</comments>
      <pubDate>Tue, 9 Aug 2022 02:43:06 +0900</pubDate>
    </item>
  </channel>
</rss>