<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Hyun's Wonderwall</title>
    <link>https://hereishyun.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 13 Jun 2026 10:53:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Hyun_!</managingEditor>
    <image>
      <title>Hyun's Wonderwall</title>
      <url>https://tistory1.daumcdn.net/tistory/5739094/attach/ad2f611424f74426a3d83238c0bf4f2a</url>
      <link>https://hereishyun.tistory.com</link>
    </image>
    <item>
      <title>Run for music: 바이브코딩으로 나한테 필요한 러닝앱을 자급자족하고 APK 배포까지 한 후기</title>
      <link>https://hereishyun.tistory.com/273</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;요즘 러닝에 빠져서 주에 2번씩은 뛰고 있다. 아직 초보라 혼자 뛸 때는 페이스 조절이 어렵게 느껴진다. 방힘하면 5분대 단거리 달리기와 10분대 걷기를 반복하기 일쑤다. 과감하게 훨씬 먼 거리를 달려봐야지 하는 것도 내일 출근할 체력을 생각하면 좀처럼 쉽지 않다. 혼자 러닝을 하며 이런저런 회고를 해보던 중, 적당한 속도로 '&lt;b&gt;꾸준히&lt;/b&gt; &lt;b&gt;재밌게&lt;/b&gt;' 뛸 수 있는 좋은 방법이 없을까 생각했다.&lt;br&gt;&lt;br&gt;음악을 듣던 중이었어서 불현듯 &lt;b&gt;&quot;뛰는 속도가 늦춰지면 노래가 멈춰버리는&quot;&lt;/b&gt; 앱 아이디어가 떠올랐다. 내가 느려졌다는 사실을 시각 대신 청각을 통해 알 수 있으면 어떨까? (내가 페이스 조절에 실패하게 되는 이유에, 스마트워치를 쓰지 않아서 달리는 중 내 속도를 잘 모르겠던 것도 있었다.)&lt;br&gt;이 아이디어가 꽤 흥미롭게 느껴져서, 그날 밤 바로 앱 기획 구체화에 착수했다.&lt;br&gt;&lt;br&gt;나는 직접 앱 개발을 해본 적은 없지만, 앱 개발자와의 협업 경험과 평소 앱 사용경험으로부터 쌓은 배경지식이 있었다. 즉 구현을 위해 어떤 기술이 필요할지 바로 예상이 됐다. 챗지피티와 클로드를 활용해 바이브코딩으로 데모 앱을 만들었다. 처음에 바로 완벽히 동작하지는 않았고, 직접 몸을 움직이면서 테스팅해 버그를 수정하고 UX를 개선했다. 문제없이 동작하는 앱을 완성하는 데 총 3시간이 걸렸다.&lt;br&gt;&lt;br&gt;앱 이름은&lt;b&gt; &quot;Run For Music&quot;&lt;/b&gt;. 바로 떠오른 직관적인 제목을 붙였다.&lt;br&gt;UI 및 사용 방법은 아래와 같이 단순하다. 서버도 로그인도 없는 로컬 앱이다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsvSZk/dJMcaduY4jc/hOoglr1NZX9MLLT9xJPG21/tfile.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsvSZk/dJMcaduY4jc/hOoglr1NZX9MLLT9xJPG21/tfile.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsvSZk/dJMcaduY4jc/hOoglr1NZX9MLLT9xJPG21/tfile.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsvSZk%2FdJMcaduY4jc%2FhOoglr1NZX9MLLT9xJPG21%2Ftfile.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;1080&quot; height=&quot;2400&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;추적 시작 전의 인터페이스는 위와 같다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5uOrC/dJMcaiJQQlq/klkBU4cDKnacluA6ipUVKk/tfile.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5uOrC/dJMcaiJQQlq/klkBU4cDKnacluA6ipUVKk/tfile.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5uOrC/dJMcaiJQQlq/klkBU4cDKnacluA6ipUVKk/tfile.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5uOrC%2FdJMcaiJQQlq%2FklkBU4cDKnacluA6ipUVKk%2Ftfile.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;1080&quot; height=&quot;2400&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;설정에서 테마색, 목표 페이스, 음악 정지 지연 시간을 설정할 수 있다.&lt;br&gt;시스템 설정에 따라 라이트/다크모드를 지원한다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eqHf5t/dJMcad2PPaD/sxaytvOXmJS7kfZ8Xvai0k/tfile.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eqHf5t/dJMcad2PPaD/sxaytvOXmJS7kfZ8Xvai0k/tfile.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eqHf5t/dJMcad2PPaD/sxaytvOXmJS7kfZ8Xvai0k/tfile.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeqHf5t%2FdJMcad2PPaD%2FsxaytvOXmJS7kfZ8Xvai0k%2Ftfile.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;1080&quot; height=&quot;2400&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;[라이트 모드] 추적을 시작하고, 내가 설정해 둔 목표 페이스 이내로 빠르게 달리면 음악이 재생된다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuX5RG/dJMcacbP95O/nN5t0Ta3AV6P2V1MpUs0f0/tfile.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuX5RG/dJMcacbP95O/nN5t0Ta3AV6P2V1MpUs0f0/tfile.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuX5RG/dJMcacbP95O/nN5t0Ta3AV6P2V1MpUs0f0/tfile.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuX5RG%2FdJMcacbP95O%2FnN5t0Ta3AV6P2V1MpUs0f0%2Ftfile.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;1080&quot; height=&quot;2400&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;2400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;내가 설정해 둔 목표 페이스보다 천천히 달리면 음악이 정지되어버린다.&lt;br&gt;빠르게 달리면 자동으로 음악이 다시 재생된다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yXQkZ/dJMcacbP95P/qJQ7fJvSDfMeWebm2Qu9DK/tfile.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yXQkZ/dJMcacbP95P/qJQ7fJvSDfMeWebm2Qu9DK/tfile.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yXQkZ/dJMcacbP95P/qJQ7fJvSDfMeWebm2Qu9DK/tfile.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyXQkZ%2FdJMcacbP95P%2FqJQ7fJvSDfMeWebm2Qu9DK%2Ftfile.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;1080&quot; height=&quot;1348&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;직접 사용해 본 결과 잘 작동했고, 기대보다 더 만족스러웠다!&lt;br&gt;느려진다 싶으면 음악이 멈춰버리니까 걸을 수 없었다. 특히 좋아하는 노래가 나올 때, 하이라이트가 끊기지 않도록 일정한 속도로 뛰게 됐다 ‍♀️  음악이 페이스메이커 역할을 해준 것이다. 그 덕분에 혼자 하는 러닝도 지루하지 않게 느껴져, 평소 뛰던 거리보다 1km나 더 뛰었다! &lt;br&gt;인스타그램으로 친구들에게 보여주었는데, 무려 3명이나 쓰고 싶다고 APK 다운 링크를 요청했다! 아이디어가 공감을 얻었고, 사람들에게 실질적인 가치를 전달했다는 것이 정말 기뻤다 &lt;/p&gt;</description>
      <category>Wonderwall/Hyun</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/273</guid>
      <comments>https://hereishyun.tistory.com/273#entry273comment</comments>
      <pubDate>Tue, 28 Apr 2026 01:22:24 +0900</pubDate>
    </item>
    <item>
      <title>[Do it! 알고리즘 코딩테스트 - 자바 편] 09. 그래프</title>
      <link>https://hereishyun.tistory.com/272</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;에지&lt;b&gt; 리스트와 인접 리스트가 헷갈림:&amp;nbsp;&lt;/b&gt;&lt;a href=&quot;https://u-it.tistory.com/491&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://u-it.tistory.com/491&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;09. 그래프&lt;/b&gt;&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래프:&amp;nbsp;&lt;/b&gt;노드와 에지로 구성된 집합&lt;br&gt;&lt;b&gt;- 노드:&lt;/b&gt; 데이터를 표현하는 단위&lt;br&gt;&lt;b&gt;- 에지:&lt;/b&gt; 노드를 연결&lt;br&gt;(트리도 그래프의 일종)&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;09-1. 그래프의 표현&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;그래프를 구현하는 방법은 &lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3가지.&lt;/span&gt;&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;&lt;span style=&quot;background-color: #F6E199;&quot;&gt;1. 에지 리스트(edge list)&lt;/span&gt;: &quot;에지를 중심&quot;&lt;/b&gt;으로 그래프를 표현.&lt;br&gt;&lt;b&gt;- 배열&lt;/b&gt;에 &lt;b&gt;&quot;출발 노드, 도착 노드&quot;&lt;/b&gt;를 저장하여 에지를 표현&lt;br&gt;- 또는 &lt;b&gt;&quot;출발 노드, 도착 노드, 가중치&quot;&lt;/b&gt;를 저장하여 가중치가 있는 에지를 표현.&lt;br&gt;&amp;nbsp;&lt;br&gt;에지 리스트로 가중치 없는 그래프 표현하기&lt;br&gt;- 가중치가 없는 그래프는 출발 노드와 도착 노드만 표현 -&amp;gt; 배열 열은 2개면 충분.&lt;br&gt;노드는 여러 자료형을 사용할 수 있는데 다음의 경우 노드는 Integer형.&lt;br&gt;&lt;b&gt;방향 그래프:&lt;/b&gt; 1-&amp;gt;2, 1-&amp;gt;3, 2-&amp;gt;4, 2-&amp;gt;5, 3-&amp;gt;4, 4-&amp;gt;5&lt;br&gt;=&amp;gt; [[1, 2]], [1, 3], [2, 4], [2, 5], [4, 5]] &lt;b&gt;= A[N][2]&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;이처럼 방향이 있는 그래프는 &lt;b&gt;순서에 맞게 노드를 배열에 저장하는 방식&lt;/b&gt;으로 표현한다.&lt;br&gt;그리고&lt;b&gt; 노드를 배열에 저장하여 에지를 표현하므로 에지 리스트&lt;/b&gt;라고 한다.&lt;br&gt;- 만약 방향이 없는 그래프라면 1&amp;lt;-&amp;gt;2는 [1, 2], [2, 1]&lt;br&gt;&amp;nbsp;&lt;br&gt;에지 리스트로 &lt;b&gt;가중치 있는 그래프&lt;/b&gt;&amp;nbsp;표현하기&lt;br&gt;가중치가 있는 그래프는 열을 3개로 늘려&lt;b&gt; 3번째 열에 가중치를 저장&lt;/b&gt;하면 된다.&lt;br&gt;1-&amp;gt;2로 향하는 가중치가 8인 에지는 이제 [1, 2, 8]로 표현된다.&lt;br&gt;[[1, 2, 8], [1, 3, 3], ...]&lt;b&gt; = A[N][3]&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;에지 리스트는 구현하기 쉬운데 특정 노드와 관련되어있는 에지를 탐색하기는 지 않다.&lt;br&gt;에지 리스트는 &lt;b&gt;벨만 포드나 크루스칼(MST)&lt;/b&gt; 알고리즘에 사용한다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;&lt;span style=&quot;background-color: #F6E199;&quot;&gt;2. 인접 행렬(adjacency matrix)&lt;/span&gt;&lt;/b&gt;은 2차원 배열을 자료구조로 이용하여 그래프를 표현한다.&lt;br&gt;&lt;b&gt;노드 중심&lt;/b&gt;으로 그래프를 표현한다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;인접 행렬로 가중치 없는 그래프 표현하기&lt;/b&gt;&lt;br&gt;1~5번 노드가 각각 간선 가짐. &lt;b&gt;출발노드: 행, 도착노드: 열&lt;/b&gt;&lt;br&gt;x-&amp;gt;y가 있으면 5*5 행렬에서 arr[x][y]=1로 설정&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;인접 행렬로 가중치 있는 그래프 표현하기&lt;/b&gt;&lt;br&gt;x-num-&amp;gt;y가 있으면 5*5 행렬에서 arr[x][y]=가중치값num 으로 설정&lt;br&gt;&amp;nbsp;&lt;br&gt;인접 행렬을 이용한 그래프 구현은, 쉽고 두 노드를 연결하는 에지의 여부와 가중치값을 배열에 직접 접근해 바로 확인할 수 있는 게 장점.&lt;br&gt;하지만 노드와 관련되어있는 에지를 탐색하려면 N번 접근해야 하므로, 노드 개수에 비해 에지가 적을 때는 공간 효율성이 떨어진다.&lt;br&gt;또한 &lt;b&gt;노드 개수가 많은 경우 아예 2차원 배열 선언 자체를 할 수 없음.&lt;/b&gt;&lt;br&gt;=&amp;gt; 따라서 인접 행렬은 &lt;b&gt;노드 개수에 따라 사용 여부를 적절하게 판단해야&lt;/b&gt; 함&lt;br&gt;&lt;b&gt;예를 들어 노드가 3만 개를 넘으면&lt;/b&gt; 자바 힙 스페이스 &lt;b&gt;에러가 발생한다.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;&lt;span style=&quot;background-color: #F6E199;&quot;&gt;3.인접 리스트: 리스트 배열.&lt;/span&gt;&lt;/b&gt;&lt;br&gt;인접 리스트는 ArrayList로 그래프를 표현한다. 노드 개수만큼 ArrayList를 선언. 자료형은 경우에 맞게 사용.&lt;br&gt;ArrayList&amp;lt;Integer&amp;gt;[5]&lt;br&gt;- 인접 리스트에는 N번 노드와 연결되어 있는 노드를 배열의 위치 N에 연결된 노드 개수만큼 배열을 연결하는 방식으로 표현한다.&lt;br&gt;- 예를 들어 노드 1과 연결된 2, 3 노드는 ArrayList[1]에 [2, 3]을 연결하는 방식으로 표현한다.&lt;br&gt;ArrayList&amp;lt;Integer&amp;gt;[N] = [1]-&amp;gt;[2],[3]&amp;nbsp; [2]-&amp;gt;[4],[5] ... 이런식&lt;br&gt;- 여기서도 방향이 있는 그래프를 표현한것&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;&lt;span style=&quot;color: #EE2323;&quot;&gt;인접 리스트로 가중치 있는 그래프 표현하기&lt;/span&gt;&lt;/b&gt;&lt;br&gt;- 가중치가 있는 경우 자료형을 클래스로 사용한다.&lt;br&gt;&lt;b&gt;(도착 노드, 가중치)&lt;/b&gt;를 갖는 Node 클래스를 선언하여 ArrayList에 사용한다.&lt;br&gt;&lt;b&gt;ArrayList&amp;lt;Node&amp;gt;[N]&lt;/b&gt; = [1]-&amp;gt;[2,8],[3,3]&amp;nbsp; [2]-&amp;gt;[4,4][5,15] ...&lt;br&gt;&amp;nbsp;&lt;br&gt;ArrayList[1]에 [(2,8), (3,3)]&lt;br&gt;노드 1과 2가 가중치 8 에지로, 노드 1과 3이 가중치 3 에지로 연결되어있다는 것을 보여줌. 방향성도 고려되어있음&lt;br&gt;인접리스트 구현은 복잡한 편이지만, 노드와 연결되어있는 에지를 탐색하는 시간이 매우 뛰어남&lt;br&gt;노드 개수가 커도 공간 효율이 좋아 메모리 초과 에러 발생 X&lt;br&gt;&lt;b&gt;이런 장점으로 실제 코딩 테스트에서는 인접 리스트를 이용한 그래프 구현을 선호한다.&lt;/b&gt;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[18352번: 특정 거리의 도시 찾기] / 실2&lt;/b&gt;&lt;br&gt;&lt;b&gt;Java&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static List&amp;lt;Integer&amp;gt;[] graph;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int N, M, K, X;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;N = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;M = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;K = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;X = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph = new ArrayList[N+1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=1; i&amp;lt;=N; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[i] = new ArrayList&amp;lt;&amp;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;for(int i=0; i&amp;lt;M; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int A = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int B = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[A].add(B); 
&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;int[] dist = new int[N+1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Arrays.fill(dist, -1); // 방문 안 한 상태 초기화
&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;Queue&amp;lt;Integer&amp;gt; q = new ArrayDeque&amp;lt;&amp;gt;();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.add(X);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dist[X] = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(!q.isEmpty()){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int cur = q.poll();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int next : graph[cur]){
&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;if(dist[next] == -1){ // 첫 방문일 때만
&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;dist[next] = dist[cur] + 1;
&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;q.add(next);
&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;&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;boolean printed = false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=1; i&amp;lt;=N; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(dist[i] == K){
&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;System.out.println(i);
&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;printed = true;
&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(!printed) System.out.println(-1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;C++&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;

using namespace std;

int dist[300001];

int main() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ios::sync_with_stdio(false);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin.tie(0);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int n, m, k, x;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; m &amp;gt;&amp;gt; k &amp;gt;&amp;gt; x;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; graph(n+1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; m; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int a, b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[a].push_back(b);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// dist 초기화 (-1 = 미방문)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fill(dist, dist+n+1, -1);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;queue&amp;lt;int&amp;gt; q;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.push(x);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dist[x] = 0;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// BFS
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (!q.empty()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int curr = q.front();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.pop();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int next : graph[curr]) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (dist[next] == -1) {
&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;dist[next] = dist[curr] + 1;
&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;q.push(next);
&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;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bool found = false; // 1개라도 찾았는지 확인용
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 오름차순 출력
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 1; i &amp;lt;= n; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (dist[i] == k) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;found = true;
&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;if (!found) cout &amp;lt;&amp;lt; -1;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[1325번: 효율적인 해킹] / 실1&lt;/b&gt;&lt;br&gt;&lt;b&gt;Java&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static List&amp;lt;Integer&amp;gt;[] graph;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int N, M;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int[] count;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int[] visited;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int visitId = 1; // 현재 visited하는 번호

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;N = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;M = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph = new ArrayList[N+1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;count = new int[N+1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited = new int[N+1];

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 1; i &amp;lt;= N; i++) graph[i] = new ArrayList&amp;lt;&amp;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;// 방향: b -&amp;gt; a
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; M; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int a = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int b = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[b].add(a);
&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;int max = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 1; i &amp;lt;= N; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;count[i] = bfs(i);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max = Math.max(max, count[i]);
&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;StringBuilder sb = new StringBuilder();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 1; i &amp;lt;= N; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (count[i] == max) {
&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;sb.append(i).append(' ');
&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(sb);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int bfs(int start) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visitId++;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ArrayDeque&amp;lt;Integer&amp;gt; q = new ArrayDeque&amp;lt;&amp;gt;();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.add(start);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[start] = visitId;
&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;int cnt = 1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (!q.isEmpty()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int cur = q.poll();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int nxt : graph[cur]) {
&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;if (visited[nxt] != visitId) { // 이번에 아직 방문 안 했는지
&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;visited[nxt] = visitId;
&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;cnt++;
&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;q.add(nxt);
&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;&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;return cnt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;C++&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;

using namespace std;

int main()
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ios::sync_with_stdio(false);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin.tie(0);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int n, m;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; m;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; graph(n+1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=0; i&amp;lt;m; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int a, b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[b].push_back(a); // b로인해 a로 가는걸 확인해야
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//BFS
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int maxCnt=0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vector&amp;lt;int&amp;gt; comp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=1; i&amp;lt;=n; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;queue&amp;lt;int&amp;gt; q;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bool visited[n+1]={};
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int cnt=0;
&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;q.push(i);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[i]=true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(!q.empty()){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int c=q.front();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.pop();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int j : graph[c]){
&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;if(!visited[j]){
&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;cnt++;
&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;visited[j]=true;
&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;q.push(j);
&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;&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;if(maxCnt==cnt) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comp.push_back(i);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else if(maxCnt&amp;lt;cnt){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maxCnt=max(maxCnt,cnt);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;comp.assign(1, i);
&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;for(int c : comp)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout&amp;lt;&amp;lt;c&amp;lt;&amp;lt;&quot; &quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 0;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[1707번: 이분그래프] / 골4&lt;/b&gt;&lt;br&gt;&lt;b&gt;Java&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static List&amp;lt;Integer&amp;gt;[] graph;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int[] color;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int V, E;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringBuilder sb = new StringBuilder();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int K = Integer.parseInt(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (K-- &amp;gt; 0) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;V = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph = new ArrayList[V + 1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 1; i &amp;lt;= V; i++) 
&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;graph[i] = new ArrayList&amp;lt;&amp;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;for (int i = 0; i &amp;lt; E; i++) {
&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;st = new StringTokenizer(br.readLine());
&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;int a = Integer.parseInt(st.nextToken());
&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;int b = Integer.parseInt(st.nextToken());
&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;graph[a].add(b);
&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;graph[b].add(a);
&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;&amp;nbsp;color = new int[V+1]; // 0: 미방문, 1/-1: 두 그룹
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (check()) sb.append(&quot;YES\n&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else sb.append(&quot;NO\n&quot;);
&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;System.out.print(sb.toString());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean check() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 1; i &amp;lt;= V; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (color[i] == 0) {
&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;if (!bfs(i)) {
&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;return false;
&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;&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;return true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean bfs(int start) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Queue&amp;lt;Integer&amp;gt; q = new ArrayDeque&amp;lt;&amp;gt;();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.add(start);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color[start] = 1;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (!q.isEmpty()) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int cur = q.poll();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int next : graph[cur]) {
&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;if (color[next] == 0) {
&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;color[next] = -color[cur]; // 반대 색으로 칠하기
&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;q.add(next);
&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;} else {
&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;if (color[next] == color[cur]) { // 이미 색이 있는데, 인접한 두 정점의 색이 같다면 이분 그래프 X
&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;&amp;nbsp;return false;
&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;&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;&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;return true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;C++&lt;br&gt;오랜만에 풀어서 이분그래프 뜻을 까먹었었는데... 노드마다 두가지 색을 칠할 수 있는데, 연결된 것끼리는 다 색이 다르면 이분그래프.&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt; #include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;

using namespace std;

bool check(vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; graph, int v){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int visited[v+1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fill(visited, visited+v+1, 0);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=0; i&amp;lt;v; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;queue&amp;lt;int&amp;gt; q;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.push(i);
&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;if(visited[i]==0) visited[i]=1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(!q.empty()){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int c=q.front();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.pop();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int j : graph[c]){
&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;if(visited[j]==0) {
&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;q.push(j);
&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;visited[j]=3-visited[c];
&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;}if(visited[j]==visited[c]) {
&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;return false;
&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;&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;return true;
}

int main()
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ios::sync_with_stdio(false);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin.tie(0);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int tk, v, e;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin&amp;gt;&amp;gt;tk;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(tk--&amp;gt;0){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin&amp;gt;&amp;gt;v&amp;gt;&amp;gt;e;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; graph(v+1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=0; i&amp;lt;e; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int a, b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cin&amp;gt;&amp;gt;a&amp;gt;&amp;gt;b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[a].push_back(b);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[b].push_back(a);
&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;if(check(graph, v))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout&amp;lt;&amp;lt;&quot;YES\n&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&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;cout&amp;lt;&amp;lt;&quot;NO\n&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;유니온파인드&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;[1717]&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;[1976]&lt;br&gt;&amp;nbsp;&lt;br&gt;[1043]&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;위상 정렬 (Topological Sort)&lt;/b&gt;&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;br&gt;[과목 수강] 수학 → 물리 → 양자역학, 수학 → 통계. &quot;위상 정렬 결과: 수학 → 물리 → 통계 → 양자역학&quot;&lt;br&gt;&lt;b&gt;순서. 줄세우기. 하면 위상정렬.&lt;/b&gt;&lt;br&gt;&lt;b&gt;진입차수(indegree):&lt;/b&gt; 어떤 노드로 들어오는 간선의 수. (진입차수 0 = 선행 조건 없음 = 지금 당장 처리 가능)&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;알고리즘 동작 (BFS 방식)&lt;/b&gt;&lt;br&gt;&lt;b&gt;1. 모든 노드의 진입차수 계산 (a-&amp;gt;b면 v[a].push_back(b))&lt;/b&gt;&lt;br&gt;&lt;b&gt;2.&amp;nbsp;진입차수&amp;nbsp;==&amp;nbsp;0인&amp;nbsp;노드를&amp;nbsp;큐에&amp;nbsp;삽입&lt;/b&gt;&lt;br&gt;&lt;b&gt;3.&amp;nbsp;큐에서&amp;nbsp;노드를&amp;nbsp;꺼내&amp;nbsp;출력&lt;/b&gt;&lt;br&gt;&lt;b&gt;4.&amp;nbsp;해당&amp;nbsp;노드의&amp;nbsp;이웃&amp;nbsp;노드들의&amp;nbsp;진입차수&amp;nbsp;-1&lt;/b&gt;&lt;br&gt;&lt;b&gt;5.&amp;nbsp;진입차수가&amp;nbsp;0이&amp;nbsp;된&amp;nbsp;노드를&amp;nbsp;큐에&amp;nbsp;삽입&lt;/b&gt;&lt;br&gt;&lt;b&gt;6.&amp;nbsp;큐가&amp;nbsp;빌&amp;nbsp;때까지&amp;nbsp;반복&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;DFS로도 할 수 있는데 BFS가 더 좋음. 아래는 DFS...&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;DFS로 끝까지 내려간 뒤
스택에 쌓고 역순 출력
void dfs(int x){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[x] = true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int nxt : graph[x]){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(!visited[nxt]) dfs(nxt);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stk.push(x); // 끝난 뒤 push
}
→ 마지막에 스택 pop하면 위상정렬

dfs(1)
&amp;nbsp;&amp;nbsp;dfs(2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(4)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;갈 곳 없음 → stack push(4)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stack push(2)
&amp;nbsp;&amp;nbsp;dfs(3)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4는 이미 visited
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stack push(3)
&amp;nbsp;&amp;nbsp;stack push(1)

stack: [1, 3, 2, 4] (top이 1)
출력:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1&amp;nbsp;&amp;nbsp;3&amp;nbsp;&amp;nbsp;2&amp;nbsp;&amp;nbsp;4&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;DAG (Directed Acyclic Graph) 에서만 가능&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;사이클이 있으면 위상 정렬 불가 (큐가 비었는데 출력한 노드 수 &amp;lt; 전체 노드 수 → 사이클 존재)&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;br&gt;BFS는&amp;nbsp;&lt;span style=&quot;color: #8100C2;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #2B303B;&quot;&gt;(&lt;/span&gt;출력한 노드 수 &lt;span style=&quot;color: #14181F;&quot;&gt;!=&lt;/span&gt; n&lt;span style=&quot;color: #2B303B;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #2B303B;&quot;&gt;{&lt;/span&gt;&amp;nbsp;&amp;nbsp;cout &lt;span style=&quot;color: #14181F;&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&quot;color: #008000;&quot;&gt;&quot;사이클 존재&quot;&lt;/span&gt;&lt;span style=&quot;color: #2B303B;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: #2B303B;&quot;&gt;} 면 사이클 있음. 사이클 유무만 판단 가능.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #2B303B;&quot;&gt;DFS는 vector&amp;lt;int&amp;gt; state(n + 1, 0); 로 &lt;/span&gt;&lt;span style=&quot;color: #2B303B;&quot;&gt;미방문했었으면 state[nxt]=0,&lt;/span&gt;&lt;span style=&quot;color: #2B303B;&quot;&gt; 방문 중이면 state[nxt]=1, 완료했으면 state[nxt]=2로 체크.&lt;/span&gt;&lt;br&gt;&lt;b&gt;&lt;span style=&quot;color: #2B303B;&quot;&gt;사이클 경로를 추적할 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void printCycle(int start, int cur) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vector&amp;lt;int&amp;gt; cycle;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cycle.push_back(cur);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (cur != start) {&amp;nbsp;&amp;nbsp;// 시작점 만나면 종료
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cur = parent[cur];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cycle.push_back(cur);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reverse(cycle.begin(), cycle.end()); // 가장 부모부터 출력위해
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int node : cycle) cout &amp;lt;&amp;lt; node &amp;lt;&amp;lt; ' ';
}

void dfs(int cur) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;state[cur] = 1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int nxt : graph[cur]) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (state[nxt] == 1) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printCycle(nxt, cur);&amp;nbsp;&amp;nbsp;// nxt가 사이클 시작점
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&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;if (state[nxt] == 0) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parent[nxt] = cur;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(nxt);
&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;state[cur] = 2;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;다익스트라&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;벨만포드&lt;br&gt;&amp;nbsp;&lt;br&gt;플로이드워셜&lt;br&gt;&amp;nbsp;&lt;br&gt;최소신장트리&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/PS</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/272</guid>
      <comments>https://hereishyun.tistory.com/272#entry272comment</comments>
      <pubDate>Fri, 10 Apr 2026 23:32:20 +0900</pubDate>
    </item>
    <item>
      <title>undefined로 검색이 안 되는 버그를 발견한 일</title>
      <link>https://hereishyun.tistory.com/270</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;카카오톡 이용 중 의도치 않게도 흥미로운 버그를 발견했다.&lt;br /&gt;프로필 뮤직에 Xdinary Heroes의 UNDEFINED라는 노래를 설정하고 싶어서 &lt;b&gt;undefined를 검색&lt;/b&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;처음에 단순 오류인 줄로 생각해서 5번 이상 반복 입력했다가, &lt;b&gt;'설마 JavaScript 데이터 타입으로 인식되는 건가??'&lt;/b&gt; 추측했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색어를 UNDEFINED 대문자로 작성하니 잘 검색되는 것을 확인할 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-04 오후 9.51.17.png&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;940&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VmyLI/dJMcaiCPM8u/nG7ZaANha2AbV1kjikyYoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VmyLI/dJMcaiCPM8u/nG7ZaANha2AbV1kjikyYoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VmyLI/dJMcaiCPM8u/nG7ZaANha2AbV1kjikyYoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVmyLI%2FdJMcaiCPM8u%2FnG7ZaANha2AbV1kjikyYoK%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;292&quot; height=&quot;355&quot; data-filename=&quot;스크린샷 2026-04-04 오후 9.51.17.png&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;940&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-04 오후 9.51.26.png&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xje4P/dJMcagLPbLg/Cs4uOcVDm2IK6Ksx7Krj5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xje4P/dJMcagLPbLg/Cs4uOcVDm2IK6Ksx7Krj5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xje4P/dJMcagLPbLg/Cs4uOcVDm2IK6Ksx7Krj5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXje4P%2FdJMcagLPbLg%2FCs4uOcVDm2IK6Ksx7Krj5k%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;290&quot; height=&quot;323&quot; data-filename=&quot;스크린샷 2026-04-04 오후 9.51.26.png&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-04 오후 9.51.57.png&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;1068&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqeDr/dJMcafF8GnA/EofrtABPFlnRZyYzkLXZP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqeDr/dJMcafF8GnA/EofrtABPFlnRZyYzkLXZP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqeDr/dJMcafF8GnA/EofrtABPFlnRZyYzkLXZP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrqeDr%2FdJMcafF8GnA%2FEofrtABPFlnRZyYzkLXZP0%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;291&quot; height=&quot;397&quot; data-filename=&quot;스크린샷 2026-04-04 오후 9.51.57.png&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;1068&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;어떤 구조 때문에 발생하는 걸까? 사용자 입력을 &quot;undefined&quot; 문자열로 처리하면 이런 문제가 발생할 가능성이 없지 않나?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;style3&quot; /&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; 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;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 문제가 되는 코드 (추정)
function search(query) {
  if (!query) {
    showMessage(&quot;검색어를 입력해주세요&quot;);
    return;
  }
  // 검색 실행...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 &quot;undefined&quot;를 문자열로 입력했는데, 어딘가에서 이 값이 실제 undefined로 평가되는 상황이 발생한 거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1. 가장 유력한 시나리오는 &lt;b&gt;타입 변환(type coercion) 과정&lt;/b&gt;입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 입력값을 파싱하거나 객체에서 꺼내는 과정에서
let query = searchInput.value;  // &quot;undefined&quot; (문자열)

// 어딘가에서 이런 처리가 일어났을 가능성
let parsed = JSON.parse(someData);
let keyword = parsed.query; // 키가 없으면 &amp;rarr; 실제 undefined

// 혹은 문자열 비교 없이 falsy 체크만 했을 때
if (!keyword) { ... }  // undefined &amp;rarr; falsy &amp;rarr; &quot;검색어 입력&quot; 메시지 출력&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;&quot;undefined&quot;를 명시적으로 예외 처리&lt;/b&gt;했을 가능성도 있습니다:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 방어 코드를 잘못 작성한 경우
if (!query || query === &quot;undefined&quot;) {
  showMessage(&quot;검색어를 입력해주세요&quot;);
  return;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 코드는 다른 곳에서 실제 undefined가 문자열로 변환된 채로 넘어오는 걸 막으려고 쓰는 패턴인데, 진짜로 &quot;UNDEFINED&quot;라는 곡을 검색하는 사람도 막아버리는 부작용이 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;명시적으로 예외 처리했다면, 어떤 역사에서 생겨났을까? (추측)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 레거시 코드에서 undefined를 문자열로 넘기는 실수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날 JavaScript 코드(혹은 지금도 종종)에서 이런 패턴이 흔했습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 어딘가에서 값이 없을 때
let keyword = getUserInput(); // 실패하면 undefined 반환

// 문자열 템플릿이나 URL에 그냥 붙여버림
fetch(`/search?q=${keyword}`);
// &amp;rarr; /search?q=undefined  &amp;larr; &quot;undefined&quot;라는 문자열이 서버로 전송됨&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 &quot;undefined&quot;라는 쿼리를 받으면 &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;2. localStorage / URL 파라미터에서 꺼낼 때&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 저장할 때 실수로 undefined가 저장됨
localStorage.setItem(&quot;lastSearch&quot;, undefined);
// &amp;rarr; 실제로 &quot;undefined&quot;라는 문자열로 저장됨

// 나중에 꺼내면 문자열 &quot;undefined&quot;가 나옴
const query = localStorage.getItem(&quot;lastSearch&quot;); // &quot;undefined&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 &quot;undefined&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;3. 서버에서 JSON으로 받을 때&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const data = await response.json();
const query = data.lastKeyword; // 키가 없으면 &amp;rarr; undefined
const queryStr = String(query);  // &amp;rarr; &quot;undefined&quot; (문자열)

// 이걸 그냥 검색창 초기값으로 넣어버리면...
searchInput.value = queryStr; // &quot;undefined&quot;가 입력창에 표시됨&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외 처리가 필요했던 역사가 있지 않았을까 추측해본다. undefined라는 제목의 노래가 꽤 있기 때문에 다른 이용자들도 동일한 버그를 경험했을 수 있을 것 같아서 고객센터 문의로 제보하였다. 나중에는 undefined를 검색할 수 있게 될지 궁금하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1876&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Oc5kq/dJMcaadLuGE/IDxyT2RVwFYgJchUz4b8v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Oc5kq/dJMcaadLuGE/IDxyT2RVwFYgJchUz4b8v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Oc5kq/dJMcaadLuGE/IDxyT2RVwFYgJchUz4b8v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOc5kq%2FdJMcaadLuGE%2FIDxyT2RVwFYgJchUz4b8v0%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;1876&quot; height=&quot;960&quot; data-origin-width=&quot;1876&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;회사에서 서비스 개발할 때 테스팅도 많이 해서 &quot;버그 발견 -&amp;gt; 재현 -&amp;gt; 원인 분석 -&amp;gt; 보고 및 해결&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;p.s.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LqZwM/dJMcafe6heO/zYKkdoDSDDrMGONukLAuT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LqZwM/dJMcafe6heO/zYKkdoDSDDrMGONukLAuT1/img.png&quot; data-alt=&quot;GitHub는 undefined가 안 되고 null은 된다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LqZwM/dJMcafe6heO/zYKkdoDSDDrMGONukLAuT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLqZwM%2FdJMcafe6heO%2FzYKkdoDSDDrMGONukLAuT1%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;276&quot; height=&quot;146&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GitHub는 undefined가 안 되고 null은 된다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-04-04 오후 10.34.21.png&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2LVvy/dJMcaiQlxxW/KKI4Wbm63DNWFy1qVGMJnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2LVvy/dJMcaiQlxxW/KKI4Wbm63DNWFy1qVGMJnk/img.png&quot; data-alt=&quot;Instagram은 null이 안 되고 undefined는 된다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2LVvy/dJMcaiQlxxW/KKI4Wbm63DNWFy1qVGMJnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2LVvy%2FdJMcaiQlxxW%2FKKI4Wbm63DNWFy1qVGMJnk%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;271&quot; height=&quot;188&quot; data-filename=&quot;스크린샷 2026-04-04 오후 10.34.21.png&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Instagram은 null이 안 되고 undefined는 된다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Wonderwall/Hyun</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/270</guid>
      <comments>https://hereishyun.tistory.com/270#entry270comment</comments>
      <pubDate>Sat, 4 Apr 2026 22:16:14 +0900</pubDate>
    </item>
    <item>
      <title>[Do it! 알고리즘 코딩테스트 - 자바 편] 07. 그리디</title>
      <link>https://hereishyun.tistory.com/267</link>
      <description>&lt;h2 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;07. 그리디&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그리디 알고리즘: &lt;/b&gt;'현재 상태에서 보는 선택지 중 최선의 선택지'가 전체 선택지 중 최선의 선택지라고 가정하는 알고리즘&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그리디 알고리즘의 핵심 이론:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 해 선택:&amp;nbsp;&lt;/b&gt;현재 상태에서 가장 최선이라고 생각되는 해를 선택한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 적절성 검사:&lt;/b&gt; 현재 선택한 해가 전체 문제의 제약 조건에 벗어나지 않는지 검사한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 해 검사:&amp;nbsp;&lt;/b&gt;현재까지 선택한 해 집합이 전체 문제를 해결할 수 있는지 검사한다. 전체 문제를 해결하지 못한다면 1로 돌아가 같은 과정을 반복한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[11047번: 동전 0] / 실4&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;동전을 최소로 사용해 K를 만들기 위해서는 가장 가격이 큰 동전부터 차례대로 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1762430221404&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {
    public static void solution() throws Exception {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        int count = 0;
        int[] coins = new int[n];

        for (int i = 0; i &amp;lt; n; i++) {
            coins[i] = sc.nextInt();
        }
        for (int i = n - 1; i &amp;gt;= 0; i--) {
            if (k == 0)
                break;
            count += k / coins[i];
            k %= coins[i];
        }
        System.out.print(count);
    }

    public static void main(String[] args) throws Exception {
        solution();
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[1715번: 카드 정렬하기] / 골5&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;현재 데이터 중 가장 작은 카드의 개수를 가진 묶음 2개를 뽑아야 하고, 이 2개를 기준으로 합친 새로운 카드 묶음을 다시 데이터에 넣고 정렬해야 한다. -&amp;gt; 데이터의 삽입 삭제 정렬이 자주 일어남 -&amp;gt; 우선순위 큐를 이용.&lt;/p&gt;
&lt;pre id=&quot;code_1762667078052&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();
        for(int i=0; i&amp;lt;n; i++) {
            pq.add(Integer.parseInt(br.readLine()));
        }
        int sum=0;
        while(pq.size() &amp;gt;= 2){
            int a = pq.poll();
            int b = pq.poll();
            pq.add(a+b);
            sum += (a+b);
        }
        System.out.println(sum);
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[1744번: 수 묶기]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절댓값이 큰 것들부터 서로 곱해야 결과값이 커지고, 음수의 갯수가 홀수 개일 때 0이 있다면 곱해서 없애주어야 한다.&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;gt; 음수를 오름차순으로 양수를 내림차순으로 정렬하는 큐에 넣은 뒤 절댓값이 큰 것부터 소모시키기. 1은 항상 곱하지 말고 더해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1762667319487&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        PriorityQueue&amp;lt;Integer&amp;gt; plus = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder()); // 양수는 내림차순 정렬
        PriorityQueue&amp;lt;Integer&amp;gt; minus = new PriorityQueue&amp;lt;&amp;gt;(); // 음수는 오름차순 정렬
        int oneCount = 0;
        int zeroCount = 0;
        int result = 0;

        for (int i = 0; i &amp;lt; n; i++) {
            int k = Integer.parseInt(br.readLine());
            if (k &amp;gt; 1) plus.add(k);
            else if (k == 1) oneCount++;
            else if (k == 0) zeroCount++;
            else minus.add(k);
        }
        
        // 양수 처리 (내림차순)
        while (plus.size() &amp;gt; 1) {
            int a = plus.poll();
            int b = plus.poll();
            result += a * b;
        }
        if (!plus.isEmpty())
            result += plus.poll();

        // 음수 처리 (오름차순)
        while (minus.size() &amp;gt; 1) {
            int a = minus.poll();
            int b = minus.poll();
            result += a * b;
        }
        if (!minus.isEmpty()) { // 음수 하나 남은 경우
            if (zeroCount == 0)
                result += minus.poll(); // 0 없으면 더함
        }

        // 1은 전부 더하기
        result += oneCount;

        System.out.println(result);
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[1931번: 회의실 배정] / 골5&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬을 사용해, 무조건&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://hereishyun.tistory.com/209&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hereishyun.tistory.com/209&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1762670069060&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

public class Main{
    public void solution() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int n = Integer.parseInt(br.readLine());
        int[][] meetings = new int[n][2];
        for(int i=0; i&amp;lt;n; i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            meetings[i][0] = Integer.parseInt(st.nextToken());
            meetings[i][1] = Integer.parseInt(st.nextToken());
        }
        // 끝나는 시간이 작은 것부터 오름차순 정렬
        Arrays.sort(meetings, (a, b) -&amp;gt; {
            if (a[1] != b[1]) return Integer.compare(a[1], b[1]);
            return Integer.compare(a[0], b[0]);
        });
        
        int count = 0, prevEnd = 0;
        for (int i=0; i&amp;lt;meetings.length; i++) {
            if (meetings[i][0] &amp;gt;= prevEnd) {
                prevEnd = meetings[i][1];
                count++;
            }
        }
        System.out.println(count);
    }
	public static void main(String[] args) throws Exception {
		new Main().solution();
	}
}&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;br /&gt;[1541번:&lt;span&gt; 잃어버린 괄호] / 실2&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;괄호를 적절히 쳐서 식의 값을 최소로 만드려 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-를 기준으로 식을 분리(-&amp;gt;그룹), 첫번째 그룹(숫자합)을 구하고 나머지 그룹(숫자합)들을 &lt;span style=&quot;color: #333333; 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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Python&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1762670188502&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;expr = input().strip()

parts = expr.split('-')

initial = sum(map(int, parts[0].split('+')))

rest = 0
for part in parts[1:]:
    rest += sum(map(int, part.split('+')))

print(initial - rest)&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;Java&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1762670414608&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String expr = br.readLine();
        String[] minusSplit = expr.split(&quot;-&quot;);
        int result = 0;
        for (int i = 0; i &amp;lt; minusSplit.length; i++) {
            int groupSum = 0;
            // '+'로 나눈 부분을 모두 더하기
            String[] plusSplit = minusSplit[i].split(&quot;\\+&quot;);
            for (String num : plusSplit) {
                groupSum += Integer.parseInt(num);
            }
            // 첫 그룹은 더하고, 이후 그룹들은 모두 빼기
            if (i == 0) result = groupSum;
            else result -= groupSum;
        }

        System.out.println(result);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/PS</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/267</guid>
      <comments>https://hereishyun.tistory.com/267#entry267comment</comments>
      <pubDate>Thu, 6 Nov 2025 20:59:48 +0900</pubDate>
    </item>
    <item>
      <title>[Do it! 알고리즘 코딩테스트 - 자바 편] 06. 탐색 (DFS, BFS, 백트래킹, 이진탐색)</title>
      <link>https://hereishyun.tistory.com/259</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;06. 탐색&lt;/b&gt;&lt;/h2&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;탐색: &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;주어진 데이터에서 자신이 원하는 데이터를 찾아내는 알고리즘. 주어진 데이터의 성질(정렬/비정렬)에 따라 적절한 탐색 알고리즘을 선택하는 것이 중요, 직접 구현해 원리를 완벽하게 이해해야 한다.&lt;/span&gt;&lt;br&gt;그래프를 자주 이용한다.&lt;br&gt;( c.f. [알고리즘] 완전탐색 기법 &lt;a href=&quot;https://velog.io/@717lumos/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%99%84%EC%A0%84%ED%83%90%EC%83%89-%EA%B8%B0%EB%B2%95&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://velog.io/@717lumos/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%99%84%EC%A0%84%ED%83%90%EC%83%89-%EA%B8%B0%EB%B2%95&lt;/span&gt;&lt;/a&gt; )&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;06-1. 깊이 우선 탐색&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DFS: &lt;/b&gt;그래프 완전 탐색 기법 중 하나.&lt;br&gt;&lt;b&gt;- 특징: 재귀 함수로 구현, 스택 자료구조 이용&lt;/b&gt;&lt;br&gt;- 시간 복잡도: O(V+E)&lt;br&gt;- 실제 구현 시 재귀 함수를 이용하므로 &lt;b&gt;스택 오버플로우에 유의&lt;/b&gt;해야 한다.&lt;br&gt;&lt;b&gt;- DFS로 풀 수 있는 대표 문제 유형: 단절점 찾기, 단절선 찾기, 사이클 찾기, 위상 정렬&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;DFS의 핵심 이론 -&lt;/b&gt; 한 번 방문한 노드를 다시 방문하면 안 되므로, 노드의 &lt;b&gt;방문 여부를 체크할 배열 필요. 인접 리스트로 표현.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;1. DFS를 시작할 노드를 정한 후 사용할 자료구조 초기화하기&lt;/b&gt;&lt;br&gt;- DFS를 위해 필요한 초기 작업은 &lt;b&gt;(1) 인접 리스트로 그래프 표현하기, (2) 방문 배열 초기화하기, (3) 시작 노드 스택에 삽입하기&lt;/b&gt; (재귀 시작하기. 방문 체크.)&lt;br&gt;&lt;b&gt;2. 스택에서 노드를 꺼낸 후 꺼낸 노드의 인접 노드를 다시 스택에 삽입하기&lt;/b&gt;&lt;br&gt;- pop을 수행해 노드 꺼내기.&lt;br&gt;- 꺼낸 노드를 탐색 순서에 기록하고, &lt;b&gt;인접 리스트의 인접 노드를 스택에 삽입하며 방문 배열을 체크.&lt;/b&gt;&lt;br&gt;&amp;nbsp; (1-&amp;gt;2, 3 이라면 1을 꺼내고 2, 3을 넣을 때 2, 3의 방문여부를 T로 변경)&lt;br&gt;&lt;b&gt;3. 스택 자료구조에 값이 없을 때까지 반복하기&lt;/b&gt;&lt;br&gt;- 이미 다녀간 노드는 방문 배열을 바탕으로 재삽입하지 않기&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[11724번: 연결 요소의 개수] / 실2&lt;/b&gt;&lt;br&gt;방향 없는 그래프가 주어졌을 때, 연결 요소(Connected Component)의 개수를 구하는 프로그램을 작성하는 문제.&lt;br&gt;입력: 정점의 개수 N, 간선의 개수 M, 간선(양 끝 점 u, v번호로서 주어짐)&amp;nbsp;&lt;br&gt;- 같은 간선은 한 번만 주어진다.&lt;br&gt;출력: 첫째 줄에 연결 요소의 개수를 출력&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static List&amp;lt;Integer&amp;gt;[] graph; // 그래프 나타내는 리스트 배열
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean[] visited; // 방문 확인용 배열

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String[] nm = br.readLine().split(&quot; &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int n = Integer.parseInt(nm[0]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int m = Integer.parseInt(nm[1]);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph = new ArrayList[n+1]; // 0번은 사용하지 않음
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i=1; i&amp;lt;=n; i++) graph[i] = new ArrayList&amp;lt;&amp;gt;();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i=0; i&amp;lt;m; i++) { // 간선 m개
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String[] uv = br.readLine().split(&quot; &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int u = Integer.parseInt(uv[0]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int v = Integer.parseInt(uv[1]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// graph 각각의 리스트에 원소 삽입
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[u].add(v);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[v].add(u);
&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;visited = new boolean[n+1]; // 방문 확인용 배열
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int count = 0; // 연결 요소의 개수 세는 변수
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i=1; i&amp;lt;=n; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!visited[i]) {
&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;dfs(i);
&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;count++;
&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(count);
&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;static void dfs(int node) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[node] = true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int neighbor : graph[node]) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!visited[neighbor]) {
&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;dfs(neighbor);
&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;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[2023번: 신기한 소수] / 골5&lt;/b&gt;&lt;br&gt;앞에서부터 한 자리씩 추가하며 읽었을 때 모두 소수이면 '신기한 소수'.&lt;br&gt;&lt;span style=&quot;color: #555555;&quot;&gt;N이 입력되면, N자리 수 중에서 신기한 소수를 오름차순으로 정렬해 한 줄에 하나씩 출력.&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #555555;&quot;&gt;처음에 에라토스테네스의 체를 사용해 풀었는데 메모리 초과가 발생했다. 크기가 1억인 배열을 만든 것이 문제였&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;다...&lt;/span&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;span style=&quot;color: #555555;&quot;&gt;소수 여부를 확인하기 위해 boolean 배열 대신 &lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;boolean &lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;메소드를 이용해, i를 약수로 갖는지 확인하는 방식으로 풀어야 했다. (i는 2 이상, i*i&amp;lt;=num)&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #555555;&quot;&gt;사실 맨 처음에 떠올렸던 방법인데 아쉽다..! 너무 큰 메모리를 잡지 않도록 주의하자.&lt;/span&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int n;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = Integer.parseInt(br.readLine());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 1자리 소수에서 시작
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int[] primes = {2, 3, 5, 7};
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int p : primes) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(1, p);
&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;// curr이 소수인 경우 계속 탐색, digit이 n자리 도달 시 출력
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static void dfs(int digit, int curr) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!isPrime(curr))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (digit == n) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(curr);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&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;// 다음 자릿수 붙이기 (1~9)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i=1; i&amp;lt;=9; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(digit+1, curr*10+i);
&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;static boolean isPrime(int num) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (num &amp;lt; 2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i=2; i*i&amp;lt;=num; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (num%i==0)
&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;return false;
&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;return true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[13023번: ABCDE] / 골5&lt;/b&gt;&lt;br&gt;총 N명이 있다. A-B-C-D-E 이렇게 5명이 이어진 관계가 존재하는지, 즉 dfs 깊이가 5이상이 되는 것이 있는지 여부를 출력.&lt;br&gt;쓸데없이 사이클 형성에 대해 고민했는데...;&amp;nbsp; 사이클을 생각할 필요 없었다.&amp;nbsp;&lt;br&gt;이 문제에서는 visited 방문 배열을 연결 요소 문제처럼 '한 번이라도 연결되어있는지' 확인 목적이 아니라, '이번의 쭉 긴 탐색에서 거쳤는지' 목적으로 사용해야 했다. 따라서 백트래킹 식으로 visited를 true/false 바꿔주어야 했다...!!&lt;br&gt;&lt;b&gt;visited 방문 배열 사용 목적에 대해 정확하게 고민할 것!! 이건 백트래킹!!&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int N, M;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static ArrayList&amp;lt;Integer&amp;gt;[] graph;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean[] visited;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean found = false;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;N = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;M = Integer.parseInt(st.nextToken());
&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;graph = new ArrayList[N];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; N; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[i] = new ArrayList&amp;lt;&amp;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;for (int i = 0; i &amp;lt; M; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int a = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int b = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[a].add(b);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;graph[b].add(a);
&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;visited = new boolean[N];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; N; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(i, 1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (found) break;
&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;System.out.println(found ? 1 : 0);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static void dfs(int node, int depth) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (found) return; // 이미 찾았으면 중단
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (depth == 5) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;found = true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&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;visited[node] = true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int next : graph[node]) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!visited[next]) {
&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;dfs(next, depth + 1);
&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[node] = false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;06-2. 백트래킹&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;백트래킹:&amp;nbsp;&lt;/b&gt;문제를 해결하는 모든 경로를 탐색하는 기법. (조건에 맞는)&lt;br&gt;- 특징: 재귀 함수로 구현, 가지치기로 성능 향상(pruning-유효하지 않는 경로 조기 차단)&lt;br&gt;- 시간 복잡도: O(N^d)&lt;br&gt;- 백트래킹을 활용 가능한 대표 문제: 조합, 순열, N-Queens&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;백트래킹의 핵심 이론&lt;/b&gt; - 문제를 해결하기 위해 가능한 경로를 탐색하면서, 조건을 만족하지 않는 경로를 가지치기해 탐색 범위를 줄임. 재귀로 구현. (바로 이전 단계로 되돌아가 다른 경로를 시도)&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;1. 가능한 선택지 탐색하기:&lt;/b&gt; &lt;b&gt;현재 상태에서 가능한 모든 선택지를 탐색&lt;/b&gt;&lt;br&gt;&lt;b&gt;2. 유효성 검사 및 가지치기&lt;/b&gt;: 각 선택지가 문제의 조건을 만족하는지 검사. 만약 조건을 만족하지 않으면, 해당 경로는 더이상 탐색하지 않고 즉시 이전 단계로 되돌아감.&lt;br&gt;&lt;b&gt;3. 해답 도출하기: 조건을 만족하는 해답을 찾으면 이를 기록하고,&lt;/b&gt; 필요에 따라 다른 경로도 계속 탐색.&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[15649번: N과 M] / 실3&lt;/b&gt;&lt;br&gt;&lt;span style=&quot;color: #333333;&quot;&gt;자연수 N과 M이 주어졌을 때,&amp;nbsp;&lt;/span&gt;&quot;1부터 N까지 자연수 중에서 중복 없이 M개를 고른 수열&quot;(길이가 M)을 모두 구하기&lt;br&gt;아래처럼 풀었는데, 사용한 값인지 확인하는 코드와 현재 수열의 값을 보관하는 코드를 어느 줄에 써야 할지 약간 헷갈렸다...&lt;br&gt;이건 매 회차 사용여부가 달라지는 백트래킹 문제! if문 안에서 재귀함수 진입지점 주위로 t/f 감싸자!&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int n, m;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean[] visited;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int[] nums;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited = new boolean[n+1]; // n번이 사용되었는지를 확인 (1~n)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nums = new int[m];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=1; i&amp;lt;=n; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(i, 0);
&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;static void dfs(int curr, int idx) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(visited[curr]) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&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;visited[curr] = true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nums[idx]=curr;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(idx==m-1){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=0; i&amp;lt;m; i++) {
&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;System.out.print(nums[i]+&quot; &quot;);
&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;&amp;nbsp;System.out.println();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=1; i&amp;lt;=n; i++){
&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;dfs(i, idx+1);
&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[curr] = false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;이 풀이가 더 직관적인 것 같다.&lt;br&gt;이건 매 회차 사용여부가 달라지는 백트래킹 문제! 사용되지 않았음을 확인한 if문 내에서, 재귀함수 호출지점 위아래로 check t/f 업데이트 코드를 두어서 감싸자!&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int n, m;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int[] num;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean[] check;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static void backtracking(int cnt) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (cnt == m) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringBuilder sb = new StringBuilder();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; m; i++) {
&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;sb.append(num[i]).append(' ');
&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;&amp;nbsp;System.out.println(sb);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&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;for (int i = 1; i &amp;lt;= n; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (!check[i]) {
&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;num[cnt] = i;
&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;check[i] = true;
&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;backtracking(cnt + 1);
&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;check[i] = false;
&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;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = Integer.parseInt(st.nextToken());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;num = new int[m];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;check = new boolean[n + 1];

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;backtracking(0);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[N-Queen 배치하기] / 골4&lt;/b&gt;&lt;br&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/9663&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/9663&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[17136번: 색종이 붙이기] / 골2&lt;/b&gt;&lt;br&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17136&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/17136&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;06-3. BFS&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BFS: &lt;/b&gt;그래프 완전 탐색 기법 중 하나. 시작 노드에서 출발해 시작 노드를 기준으로 가까운 노드를 먼저 방문하면서 탐색하는 알고리즘.&lt;br&gt;&lt;b&gt;- 특징: FIFO 탐색, Queue 자료구조 이용&lt;/b&gt;&lt;br&gt;- 시간 복잡도: O(V+E)&lt;br&gt;&amp;nbsp;&lt;br&gt;BFS는 FIFO 방식으로 탐색하므로 큐를 이용해 구현한다.&lt;br&gt;&lt;b&gt;BFS는 탐색 시작 노드와 가까운 노드를 우선하여 탐색하므로, 목표 노드에 도착하는 경로가 여러 개일 때 최단 경로를 보장한다.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;BFS의 핵심 이론:&lt;/b&gt;&lt;br&gt;&lt;b&gt;1. BFS를 시작할 노드를 정한 후 사용할 자료구조 초기화하기&lt;/b&gt;&lt;br&gt;&lt;b&gt;2. 큐에서 노드를 꺼낸 후 꺼낸 노드의 인접 노드를 다시 큐에 삽입하기&lt;/b&gt;&lt;br&gt;&lt;b&gt;3. 큐 자료구조에 값이 없을 때까지 반복하기&lt;/b&gt;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[1260번: DFS와 BFS] / 실2&lt;/b&gt;&lt;br&gt;DFS와 BFS를 구현하는 문제. 이 형태 완전히 암기하기!!&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int n, m, v;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static List&amp;lt;Integer&amp;gt;[] A; // 그래프
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean[] visited;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws IOException {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = Integer.parseInt(st.nextToken()); // 정점 수
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = Integer.parseInt(st.nextToken()); // 간선 수
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v = Integer.parseInt(st.nextToken()); // 탐색 시작 정점 수
&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;A = new ArrayList[n+1]; // n+1 크기의 배열 (A[0]은 사용하지 않음)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=1; i&amp;lt;=n; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[i] = new ArrayList&amp;lt;&amp;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;for(int i=0; i&amp;lt;m; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int s = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int e = Integer.parseInt(st.nextToken());
&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;&amp;nbsp;A[s].add(e);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[e].add(s);
&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;&amp;nbsp;// 번호가 작은 것부터 먼저 방문하기 위해 정렬
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i=1; i&amp;lt;=n; i++){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Collections.sort(A[i]);
&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;&amp;nbsp;visited = new boolean[n+1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(v);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println();
&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;visited = new boolean[n+1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bfs(v);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println();
	}
	
	//for문+재귀
	static void dfs(int node){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.print(node+&quot; &quot;);
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[node]=true;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i : A[node]){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(!visited[i])
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs(i);
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
	}
	// while문+for문+큐
	static void bfs(int node){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Queue&amp;lt;Integer&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;q.add(node);
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;visited[node]=true;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while(!q.isEmpty()){
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int now = q.poll();
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.print(now+&quot; &quot;);
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for(int i : A[now]) {
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(!visited[i]){
	&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;visited[i]=true;
	&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;q.add(i);
	&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;&amp;nbsp;}
	}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br&gt;[2176번: 합리적인 이동경로] / 실1&lt;/b&gt;&lt;br&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2176&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/2176&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[1167번:&amp;nbsp;트리의 지름] / 실1&lt;/b&gt;&lt;br&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1167&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/1167&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;06-4. 이진 탐색&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;br&gt;- 기능: 타깃 데이터 탐색&lt;br&gt;- 특징: 중앙값 비교를 이용한 대상 축소 방식&lt;br&gt;- 시간 복잡도: O(logN)&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;이진 탐색의 핵심 이론:&lt;/b&gt; 오름차순으로 정렬된 데이터에서 다음 4가지 과정을 반복. (내림차순이라면 조건을 반대로 하여 과정을 반복)&lt;br&gt;1. 현재 데이터셋의 중앙값을 선택.&lt;br&gt;2. 중앙값 &amp;gt; 타깃 데이터 일 때 중앙값 기준으로 왼쪽 데이터셋을 선택.&lt;br&gt;3. 중앙값 &amp;lt; 타깃 데이터 일 때 중앙값 기준으로 오른쪽 데이터셋을 선택.&lt;br&gt;4. 과정 1~3을 반복하다가 중앙값==타깃 데이터일 때 탐색을 종료.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[1920번: 수 찾기] / 실4&lt;/b&gt;&lt;br&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1920&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/1920&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[2343번: 기타 레슨] / 골5&lt;/b&gt;&lt;br&gt;강의 순서를 유지하면서 M개의 블루레이에 모든 강의를 나누되, 블루레이 용량의 최소값을 구하는 문제.&lt;br&gt;이진 탐색으로 가능한 최소 용량을 찾아야 함 =&amp;gt; 각 블루레이 용량을 mid로 가정해 필요한 블루레이 개수를 계산!!&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int n, m;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static int[] a;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static boolean can(int cap) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int cnt = 1, sum = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int x : a) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (sum + x &amp;gt; cap) {
&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;cnt++;
&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;sum = 0;
&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;&amp;nbsp;sum += x;
&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;return cnt &amp;lt;= m;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;StringTokenizer st = new StringTokenizer(br.readLine());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a = new int[n];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;st = new StringTokenizer(br.readLine());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int l = 0, r = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; n; i++) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a[i] = Integer.parseInt(st.nextToken());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;l = Math.max(l, a[i]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r += a[i];
&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;int ans = r;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (l &amp;lt;= r) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int mid = l + (r - l) / 2;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (can(mid)) {
&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;ans = mid;
&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;r = mid - 1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else {
&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;l = mid + 1;
&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(ans);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;[1300번: K번째 수]&lt;/b&gt;&lt;br&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1300&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/1300&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/PS</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/259</guid>
      <comments>https://hereishyun.tistory.com/259#entry259comment</comments>
      <pubDate>Thu, 30 Oct 2025 19:59:44 +0900</pubDate>
    </item>
    <item>
      <title>[CS 지식의 정석] 3. 네트워크</title>
      <link>https://hereishyun.tistory.com/266</link>
      <description>&lt;h3 data-end=&quot;235&quot; data-start=&quot;217&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크 기초&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;459&quot; data-start=&quot;236&quot; data-ke-size=&quot;size16&quot;&gt;네트워크: 노드(서버&amp;middot;라우터&amp;middot;스위치 등)와 링크(유선&amp;middot;무선)가 연결된 구조로 자원 공유를 목표로 함.&lt;br /&gt;트래픽: 특정 시점에 흐르는 데이터 총량 (단위 bps).&lt;br /&gt;처리량: 성공적으로 전송된 데이터량 &amp;rarr; 트래픽 처리 성능 지표.&lt;br /&gt;대역폭: 일정 시간 동안 흐를 수 있는 최대 비트 수(=최대 처리용량). 대역폭&amp;uarr; &amp;rarr; 서비스 속도&amp;uarr;.&lt;br /&gt;RTT: 왕복지연시간. 송신~수신확인까지 걸리는 시간.&lt;/p&gt;
&lt;h3 data-end=&quot;486&quot; data-start=&quot;466&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크 토폴로지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;738&quot; data-start=&quot;487&quot; data-ke-size=&quot;size16&quot;&gt;버스형: 하나의 회선에 모든 노드 연결. 설치 간단&amp;middot;저비용 / 회선 장애 시 전체 영향.&lt;br /&gt;스타형: 중앙 노드(허브&amp;middot;스위치) 중심 별모양 연결. 보안관리 용이 / 중앙노드 장애 시 전체 마비.&lt;br /&gt;트리형: 계층 구조. 리프노드 확장 용이 / 루트노드 장애 시 전체 영향.&lt;br /&gt;링형: 노드들이 고리 형태로 연결. 토큰 기반 충돌 無 / 전송 지연&amp;middot;고장 노드 탐지 용이.&lt;br /&gt;메시형: 모든 노드가 서로 직접 연결. 안정성&amp;uarr; / 비용&amp;middot;설계 복잡도&amp;uarr;.&lt;/p&gt;
&lt;h3 data-end=&quot;770&quot; data-start=&quot;745&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;병목현상과 토폴로지 필요성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;878&quot; data-start=&quot;771&quot; data-ke-size=&quot;size16&quot;&gt;병목현상: 특정 구간에 트래픽 집중으로 속도 저하. 원인=대역폭 부족, 서버 처리 한계, 토폴로지 설계 미흡.&lt;br /&gt;토폴로지 분석을 통해 병목 구간 파악&amp;rarr;로드밸런싱&amp;middot;서버 분산 등 해결 가능.&lt;/p&gt;
&lt;h3 data-end=&quot;905&quot; data-start=&quot;885&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터 전송 방식&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;989&quot; data-start=&quot;906&quot; data-ke-size=&quot;size16&quot;&gt;유니캐스트: 1:1 전송 (예: HTTP).&lt;br /&gt;멀티캐스트: 1:N(특정 그룹 대상).&lt;br /&gt;브로드캐스트: 1:N(모든 노드). 대표 예: ARP.&lt;/p&gt;
&lt;h3 data-end=&quot;1014&quot; data-start=&quot;996&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크 분류&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1092&quot; data-start=&quot;1015&quot; data-ke-size=&quot;size16&quot;&gt;LAN: 근거리망(가정&amp;middot;사무실). 속도&amp;uarr;, 안정성&amp;uarr;.&lt;br /&gt;MAN: 대도시망, 여러 LAN 연결.&lt;br /&gt;WAN: 국가 간 통신망, 인터넷.&lt;/p&gt;
&lt;h3 data-end=&quot;1129&quot; data-start=&quot;1099&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TCP/IP 4계층과 OSI 7계층&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1394&quot; data-start=&quot;1130&quot; data-ke-size=&quot;size16&quot;&gt;TCP/IP 4계층:&lt;br /&gt;① 애플리케이션(HTTP, FTP, SSH, SMTP)&lt;br /&gt;② 전송(TCP, UDP)&lt;br /&gt;③ 인터넷(IP, ICMP, ARP)&lt;br /&gt;④ 링크(Ethernet 등 물리적 전송).&lt;br /&gt;캡슐화: 상위 데이터에 하위 계층 헤더 추가.&lt;br /&gt;비캡슐화: 수신측이 헤더 역으로 제거.&lt;br /&gt;PDU: 계층별 데이터 단위 (메시지&amp;ndash;세그먼트&amp;ndash;패킷&amp;ndash;프레임&amp;ndash;비트).&lt;br /&gt;체크섬: 전송 오류 검증용 값. (IPv4, TCP/UDP=1의보수합, Ethernet=CRC32).&lt;/p&gt;
&lt;hr data-end=&quot;1399&quot; data-start=&quot;1396&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;18&quot; data-start=&quot;0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MTU와 단편화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;190&quot; data-start=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;MTU(Maximum Transmission Unit): 한 번에 전송 가능한 최대 프레임 크기(이더넷 기준 1500B). MTU 초과 시 IP 단편화(Fragmentation) 발생 &amp;rarr; 성능 저하 위험. TCP는 MSS(Max Segment Size)로 MTU 이하로 조절, UDP는 자체 제어 없음.&lt;/p&gt;
&lt;h3 data-end=&quot;210&quot; data-start=&quot;192&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TCP와 UDP&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;569&quot; data-start=&quot;211&quot; data-ke-size=&quot;size16&quot;&gt;TCP(Transmission Control Protocol): 연결형, 신뢰성 보장, 순서 보장, 흐름&amp;middot;혼잡 제어 지원. 3-way handshake(연결)와 4-way handshake(해제) 사용. 전송 단위=세그먼트.&lt;br /&gt;UDP(User Datagram Protocol): 비연결형, 신뢰성&amp;middot;순서 미보장, 빠른 전송(스트리밍, DNS 등). 전송 단위=데이터그램.&lt;br /&gt;TCP 흐름 제어(Sliding Window): 송신측이 수신측 버퍼 크기 고려해 전송량 조절.&lt;br /&gt;혼잡 제어(Congestion Control): 네트워크 혼잡 시 윈도우 크기 줄이는 알고리즘 (Slow Start, Congestion Avoidance 등).&lt;/p&gt;
&lt;h3 data-end=&quot;587&quot; data-start=&quot;571&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;포트와 소켓&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;743&quot; data-start=&quot;588&quot; data-ke-size=&quot;size16&quot;&gt;포트(Port): 애플리케이션 식별 번호(0~65535). TCP/UDP 각각 독립 관리.&lt;br /&gt;소켓(Socket): IP + Port 결합한 통신 단위. (예: 192.168.0.1:8080).&lt;br /&gt;Ephemeral Port: 임시 세션용 포트(보통 49152~65535).&lt;/p&gt;
&lt;h3 data-end=&quot;764&quot; data-start=&quot;745&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;nbsp;라우팅과 NAT&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1001&quot; data-start=&quot;765&quot; data-ke-size=&quot;size16&quot;&gt;라우팅(Routing): 패킷 전달 경로를 결정하는 과정. 정적 라우팅(관리자 수동 설정), 동적 라우팅(라우터 간 정보 교환: RIP, OSPF, BGP).&lt;br /&gt;NAT(Network Address Translation): 사설 IP &amp;harr; 공인 IP 변환 기술. IPv4 주소 절약, 내부망 보호.&lt;br /&gt;PAT(Port Address Translation): 여러 내부 IP를 하나의 공인 IP로 변환 시 포트번호로 구분.&lt;/p&gt;
&lt;h3 data-end=&quot;1022&quot; data-start=&quot;1003&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;nbsp;IP 주소 체계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1330&quot; data-start=&quot;1023&quot; data-ke-size=&quot;size16&quot;&gt;IPv4: 32비트(4옥텟), 예: 192.168.0.1. 클래스 A~E(네트워크/호스트 구분). 사설 IP: A(10.0.0.0/8), B(172.16.0.0/12), C(192.168.0.0/16).&lt;br /&gt;IPv6: 128비트, 16진수 표기(예: 2001:db8::1). 주소 부족 해결, 자동 설정, 보안 강화(IPsec 내장).&lt;br /&gt;서브넷 마스크: 네트워크/호스트 영역 구분. (예: 255.255.255.0 &amp;rarr; /24).&lt;br /&gt;CIDR(Classless Inter-Domain Routing): 클래스 구분 없이 네트워크 경계 자유 설정.&lt;/p&gt;
&lt;h3 data-end=&quot;1366&quot; data-start=&quot;1332&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DNS(Domain Name System)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1562&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;도메인명 &amp;harr; IP 주소 변환.&lt;br /&gt;계층 구조: Root &amp;rarr; TLD(.com/.kr) &amp;rarr; 2차 도메인 &amp;rarr; 서브도메인.&lt;br /&gt;동작: 클라이언트 &amp;rarr; 로컬 DNS &amp;rarr; 루트 DNS &amp;rarr; 권한 DNS &amp;rarr; IP 반환.&lt;br /&gt;레코드 유형: A(IPv4), AAAA(IPv6), MX(메일), CNAME(별칭), TXT(인증).&lt;br /&gt;캐싱으로 성능 향상(TTL 기반).&lt;/p&gt;
&lt;h3 data-end=&quot;1616&quot; data-start=&quot;1564&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DHCP(Dynamic Host Configuration Protocol)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1746&quot; data-start=&quot;1617&quot; data-ke-size=&quot;size16&quot;&gt;IP 자동 할당 프로토콜. Discover &amp;rarr; Offer &amp;rarr; Request &amp;rarr; Acknowledge(DORA 과정).&lt;br /&gt;임대 기간(Lease time) 만료 시 재갱신 요청.&lt;br /&gt;수동 IP 충돌 방지, 대규모 네트워크 자동화.&lt;/p&gt;
&lt;h3 data-end=&quot;20&quot; data-start=&quot;0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HTTP 프로토콜&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;537&quot; data-start=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;HTTP(HyperText Transfer Protocol): 클라이언트와 서버 간 요청&amp;middot;응답 기반 통신 규약.&lt;br /&gt;Stateless 구조로, 각 요청은 독립적으로 처리.&lt;br /&gt;요청 구성: Method(행위), Header(메타데이터), Body(데이터).&lt;br /&gt;응답 구성: Status Line(코드), Header, Body.&lt;br /&gt;주요 Method: GET(조회), POST(생성), PUT(전체 수정), PATCH(부분 수정), DELETE(삭제).&lt;br /&gt;주요 Status Code: 200 OK, 301 Redirect, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 500 Internal Server Error.&lt;br /&gt;HTTP/1.1: Keep-Alive로 다중 요청 가능, 파이프라이닝 지원.&lt;br /&gt;HTTP/2: 멀티플렉싱, 헤더 압축(HPACK), 서버 푸시.&lt;br /&gt;HTTP/3: QUIC 기반 UDP 프로토콜로 지연 최소화, 연결 복원성 강화.&lt;/p&gt;
&lt;h3 data-end=&quot;560&quot; data-start=&quot;539&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;nbsp;HTTPS 프로토콜&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;736&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;HTTP + SSL/TLS 암호화 계층을 더한 보안 통신 프로토콜.&lt;br /&gt;핸드셰이크 과정에서 인증서 기반 공개키 교환 및 세션키 생성.&lt;br /&gt;대칭키로 데이터 암호화, 비대칭키로 키 교환.&lt;br /&gt;SSL 인증서: 인증기관(CA)이 발급, 사이트 신뢰성 검증.&lt;br /&gt;이점: 데이터 암호화, 무결성 보장, 중간자 공격 방지.&lt;/p&gt;
&lt;h3 data-end=&quot;755&quot; data-start=&quot;738&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;쿠키와 세션&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;954&quot; data-start=&quot;756&quot; data-ke-size=&quot;size16&quot;&gt;쿠키: 브라우저에 저장되는 Key-Value 데이터. 로그인 유지, 사용자 맞춤 기능에 사용. 서버 응답 시 Set-Cookie 헤더로 전달.&lt;br /&gt;세션: 서버 메모리 또는 DB에 사용자 상태를 저장. 클라이언트는 Session ID만 쿠키로 저장.&lt;br /&gt;쿠키는 클라이언트 중심, 세션은 서버 중심 관리.&lt;br /&gt;세션이 보안상 유리하나 서버 부하가 커짐.&lt;/p&gt;
&lt;h3 data-end=&quot;978&quot; data-start=&quot;956&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;브라우저 렌더링 과정&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1234&quot; data-start=&quot;979&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1003&quot; data-start=&quot;979&quot;&gt;HTML 파싱 &amp;rarr; DOM 트리 생성&lt;/li&gt;
&lt;li data-end=&quot;1029&quot; data-start=&quot;1004&quot;&gt;CSS 파싱 &amp;rarr; CSSOM 트리 생성&lt;/li&gt;
&lt;li data-end=&quot;1059&quot; data-start=&quot;1030&quot;&gt;두 트리를 결합해 Render Tree 구성&lt;/li&gt;
&lt;li data-end=&quot;1093&quot; data-start=&quot;1060&quot;&gt;Layout(배치 계산) &amp;rarr; Paint(화면 출력)&lt;/li&gt;
&lt;li data-end=&quot;1234&quot; data-start=&quot;1094&quot;&gt;JavaScript 실행: DOM 조작, 이벤트 처리&lt;br /&gt;렌더링 차단 요소: &amp;lt;script&amp;gt; 태그의 동기 로드. 해결: async/defer 속성 사용.&lt;br /&gt;Reflow(Layout 재계산)과 Repaint(화면 갱신)는 성능 저하 요인.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-end=&quot;1254&quot; data-start=&quot;1236&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CORS 정책&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1573&quot; data-start=&quot;1255&quot; data-ke-size=&quot;size16&quot;&gt;CORS(Cross-Origin Resource Sharing): 다른 도메인 간 리소스 요청 제한 정책.&lt;br /&gt;브라우저 보안상 SOP(Same-Origin Policy) 기반으로 동작.&lt;br /&gt;Origin: 프로토콜 + 도메인 + 포트가 모두 동일해야 동일 출처로 간주.&lt;br /&gt;Preflight Request: 실제 요청 전 OPTIONS 메서드로 서버 허용 여부 확인.&lt;br /&gt;해결 방법: 서버에서 Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers 지정.&lt;/p&gt;
&lt;h3 data-end=&quot;1592&quot; data-start=&quot;1575&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;보안 취약점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1878&quot; data-start=&quot;1593&quot; data-ke-size=&quot;size16&quot;&gt;XSS(Cross-Site Scripting): 악성 스크립트를 삽입해 사용자 브라우저에서 실행. 방지: 입력값 이스케이프, CSP(Content Security Policy) 적용.&lt;br /&gt;CSRF(Cross-Site Request Forgery): 사용자의 인증 정보를 도용해 원치 않는 요청 수행. 방지: CSRF Token 검증, Referer 검증, SameSite 쿠키 설정.&lt;br /&gt;SQL Injection: 쿼리 조작을 통한 DB 침투. 방지: Prepared Statement 사용, 입력값 검증.&lt;/p&gt;
&lt;h3 data-end=&quot;1901&quot; data-start=&quot;1880&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네트워크 계층 요약&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2084&quot; data-start=&quot;1902&quot; data-ke-size=&quot;size16&quot;&gt;물리 계층: 전기적 신호 전송.&lt;br /&gt;데이터링크 계층: 프레임 단위 전송, MAC 주소 기반.&lt;br /&gt;네트워크 계층: IP 주소 기반 라우팅.&lt;br /&gt;전송 계층: TCP/UDP 전송 관리.&lt;br /&gt;세션 계층: 연결 관리 및 동기화.&lt;br /&gt;표현 계층: 암호화&amp;middot;압축 처리.&lt;br /&gt;응용 계층: 사용자 서비스 (HTTP, FTP, SMTP 등).&lt;/p&gt;</description>
      <category>Study</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/266</guid>
      <comments>https://hereishyun.tistory.com/266#entry266comment</comments>
      <pubDate>Fri, 24 Oct 2025 14:02:06 +0900</pubDate>
    </item>
    <item>
      <title>[CS 지식의 정석] 2. 디자인패턴</title>
      <link>https://hereishyun.tistory.com/265</link>
      <description>&lt;h4&gt;&lt;strong&gt;[디자인패턴의 소개]&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;[디자인패턴의 의의]&lt;/strong&gt;&lt;br&gt;프로그램 설계 시 반복적 문제를 객체 간 관계를 이용해 해결하도록 정의된 규약.&lt;br&gt;라이브러리·프레임워크 설계의 기초 원리로 사용됨.&lt;br&gt;패턴 학습을 통해 문제 해결력 및 팀 내 의사소통 효율 향상.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[디자인패턴의 종류]&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;생성패턴:&lt;/strong&gt; 객체 생성 규약&lt;br&gt;ex) 싱글톤, 팩토리, 추상팩토리, 빌더, 프로토타입  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;구조패턴:&lt;/strong&gt; 클래스·객체 구조 설계 규약&lt;br&gt;ex) 프록시, 어댑터, 브리지, 복합체, 데코레이터, 퍼사드, 플라이웨이트  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;행동패턴:&lt;/strong&gt; 객체 간 알고리즘·책임 할당 규약&lt;br&gt;ex) 이터레이터, 옵저버, 전략, 책임연쇄, 커맨드, 중재자, 메멘토, 상태, 템플릿메서드, 비지터&lt;br&gt;(추가 예: Flux, MVC, MVVM 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;[라이브러리와 프레임워크의 차이]&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;공통점:&lt;/strong&gt; 재사용 가능한 기능을 모듈화한 구성 요소 집합  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;라이브러리:&lt;/strong&gt; 폴더·파일 구조 규약 없음, 호출 주도권이 사용자에게 있음&lt;br&gt;예시 → &lt;code&gt;axios&lt;/code&gt;: &lt;code&gt;.get()&lt;/code&gt;, &lt;code&gt;.then()&lt;/code&gt; 등 일정한 호출 규약 존재  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프레임워크:&lt;/strong&gt; 폴더·파일 구조 등 엄격한 규약 존재, 제어 흐름이 프레임워크 중심&lt;br&gt;예시 → &lt;code&gt;Vue.js&lt;/code&gt;: 컴포넌트 기반 구조, 명확한 코드 작성 규약&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;[싱글톤패턴]&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; 하나의 클래스가 단 하나의 인스턴스만 갖도록 하는 생성패턴 규약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;활용:&lt;/strong&gt; 인스턴스 생성 비용이 큰 객체(DB 연결 모듈 등)에 사용  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;장점:&lt;/strong&gt; 인스턴스 생성 효율화, 자원 절약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단점:&lt;/strong&gt;  &lt;ul&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;OOP 원칙(캡슐화, DI) 위반 가능성  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;[JAVA에서의 싱글톤 구현 방식]&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;단순 메서드 호출&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;인스턴스 존재 여부 확인 후 생성  &lt;/li&gt;
&lt;li&gt;멀티스레드 환경에서 원자성 결여  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;synchronized 사용&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;메서드 단위 잠금으로 동시성 보장  &lt;/li&gt;
&lt;li&gt;호출 시마다 lock 발생 → 성능 저하  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;정적 멤버 (Eager Initialization)&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클래스 로드 시 즉시 인스턴스 생성  &lt;/li&gt;
&lt;li&gt;호출 전에도 메모리 점유  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;정적 블록 초기화&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;static 블록에서 인스턴스 초기화  &lt;/li&gt;
&lt;li&gt;즉시 초기화로 메모리 비효율 가능  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;정적 내부 클래스 (Lazy Holder)&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;내부 클래스 로딩 시 최초 생성  &lt;/li&gt;
&lt;li&gt;thread-safe, lazy-loading 보장  &lt;/li&gt;
&lt;li&gt;외부 new 호출 방지를 위한 private 생성자 필요  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;이중 확인 잠금 (Double Checked Locking)&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;두 번의 null 검사로 동기화 최소화  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;volatile&lt;/code&gt;로 메모리 일관성 보장  &lt;/li&gt;
&lt;li&gt;멀티스레드 환경 안전  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;enum 방식&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JVM이 인스턴스 생성·동기화 보장  &lt;/li&gt;
&lt;li&gt;thread-safe, 직렬화 안전  &lt;/li&gt;
&lt;li&gt;Joshua Bloch(Effective Java) 추천 방식  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;추천 구현 방식: 정적 내부 클래스(5번) 또는 enum 방식(7번)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[팩토리패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; 상속 관계 클래스 간 객체 생성 책임을 하위 클래스에 위임하는 생성패턴 규약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;상위 클래스 → 객체 생성 방식 모름  &lt;/li&gt;
&lt;li&gt;하위 클래스 → 구체적 생성 로직 관리  &lt;/li&gt;
&lt;li&gt;객체 생성 구조의 유연성 및 유지보수성 향상  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[이터레이터패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; 이터레이터(iterator)를 통해 컨테이너 요소에 순차 접근하는 행동패턴 규약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;자료구조(배열, 맵 등)와 무관한 동일 인터페이스 제공  &lt;/li&gt;
&lt;li&gt;데이터 순회 로직 분리로 코드 일관성 확보  &lt;/li&gt;
&lt;li&gt;예시 → &lt;code&gt;for...of&lt;/code&gt; (JavaScript)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[DI (Dependency Injection)와 DIP (Dependency Inversion Principle)]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DI 의의:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;메인 모듈이 직접 하위 모듈을 생성하지 않고 외부 주입자를 통해 의존성 전달  &lt;/li&gt;
&lt;li&gt;의존성 결합 완화, 모듈 교체 용이 구조 확보  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DI 코드 예시:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Project&lt;/code&gt; 클래스가 &lt;code&gt;BackendDeveloper&lt;/code&gt;, &lt;code&gt;FrontEndDeveloper&lt;/code&gt; 객체를 생성자 주입으로 전달받음  &lt;/li&gt;
&lt;li&gt;생성자 주입은 DI 형태이지만, 구체 클래스에 직접 의존 → DIP 위반  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DIP 의의:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;상위 모듈과 하위 모듈 모두 추상화에 의존해야 함  &lt;/li&gt;
&lt;li&gt;세부 구현이 추상화에 따라 변경되어야 함  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DIP 규칙:&lt;/strong&gt;  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;상위 모듈은 하위 모듈에 의존하지 않아야 함  &lt;/li&gt;
&lt;li&gt;추상화는 세부사항에 의존하지 않아야 함  &lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DI 장점:&lt;/strong&gt; 모듈 교체 용이 (외부 주입 구조), 단위 테스트 및 마이그레이션 용이, 의존 방향 일관성 확보  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DI 단점:&lt;/strong&gt; 모듈 증가로 인한 복잡도 상승, 런타임 의존 주입 → 컴파일 시 오류 검출 어려움  &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[전략패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; 캡슐화된 알고리즘(전략)을 컨텍스트 내에서 상호 교체 가능하게 하는 행동패턴 규약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;실행 중 전략 교체 가능  &lt;/li&gt;
&lt;li&gt;알고리즘 독립성 및 유연성 확보  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[옵저버패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; 주체(subject)가 상태 변화를 감지해 옵저버(observer)들에게 통지하는 행동패턴 규약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;주체-옵저버 간 느슨한 결합  &lt;/li&gt;
&lt;li&gt;이벤트 기반 구조 구현에 적합  &lt;/li&gt;
&lt;li&gt;예시 → 트위터 알림 로직, MVC 패턴  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[프록시패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; 객체 접근 전 중간 계층(proxy)을 두어 접근 제어, 로깅, 캐싱 등을 수행하는 구조패턴 규약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;실제 객체 접근 전 필터링·제어 가능  &lt;/li&gt;
&lt;li&gt;대표 사례 → 프록시 서버(Cloudflare 등), 캐싱·보안 필터  &lt;/li&gt;
&lt;li&gt;코드 예시 → &lt;code&gt;Proxy&lt;/code&gt; 객체로 변경 감지 및 콜백 실행  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;&lt;strong&gt;[MVC, MVP, MVVM 패턴]&lt;/strong&gt;&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;[MVC 패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; Model–View–Controller로 구성된 대표적 아키텍처 규약  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;구성요소:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model:&lt;/strong&gt; 데이터 및 비즈니스 로직 관리 계층 (DB, 상수, 변수 등)  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View:&lt;/strong&gt; 사용자 인터페이스(UI) 계층, 데이터 표시 담당  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controller:&lt;/strong&gt; Model과 View를 연결하며 이벤트 및 로직 처리 담당  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;Controller가 Model↔View 간 데이터 흐름 제어  &lt;/li&gt;
&lt;li&gt;각 계층의 책임 분리로 재사용성·확장성 확보  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;장점:&lt;/strong&gt;  &lt;ol&gt;
&lt;li&gt;역할 분리로 병렬 개발 및 유지보수 용이  &lt;/li&gt;
&lt;li&gt;재사용성과 확장성 우수  &lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단점:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;복잡한 애플리케이션에서는 Model–View 간 의존관계 복잡화  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;적용사례:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;&lt;code&gt;Spring Web MVC&lt;/code&gt; (DispatcherServlet 중심 아키텍처)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;[Spring MVC 적용 사례]&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;구조:&lt;/strong&gt; DispatcherServlet(Front Controller)이 중심이 되어 요청–응답 흐름 제어  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;처리 과정:&lt;/strong&gt;  &lt;ol&gt;
&lt;li&gt;클라이언트 요청 → DispatcherServlet 수신  &lt;/li&gt;
&lt;li&gt;HandlerMapping 참고 후 적절한 Controller 선택  &lt;/li&gt;
&lt;li&gt;Controller가 비즈니스 로직 수행 및 Model 생성  &lt;/li&gt;
&lt;li&gt;ViewResolver가 뷰 위치 결정  &lt;/li&gt;
&lt;li&gt;View 렌더링 및 사용자 응답 반환  &lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;핵심 역할:&lt;/strong&gt; DispatcherServlet이 요청 분배자이자 중앙 제어기 역할 수행  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[MVP 패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; MVC의 Controller를 Presenter로 교체한 구조  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;View와 Presenter가 1:1 관계  &lt;/li&gt;
&lt;li&gt;View가 Presenter를 직접 참조  &lt;/li&gt;
&lt;li&gt;Controller보다 강한 결합 구조  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;장점:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;뷰 로직 테스트 용이  &lt;/li&gt;
&lt;li&gt;프레젠테이션 로직 분리로 코드 가독성 향상  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단점:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;View–Presenter 간 결합도 증가로 복잡도 상승  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[MVVM 패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; MVC의 Controller를 ViewModel로 대체한 패턴  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;구조:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;ViewModel은 View를 추상화한 계층  &lt;/li&gt;
&lt;li&gt;ViewModel : View = 1 : N 관계  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;핵심 개념:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Command:&lt;/strong&gt; 여러 UI 동작을 하나의 액션으로 처리  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Binding:&lt;/strong&gt; 화면(UI) 데이터와 메모리 데이터의 자동 동기화  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;특징:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;View와 ViewModel 간 양방향 데이터 바인딩  &lt;/li&gt;
&lt;li&gt;UI와 비즈니스 로직 분리로 유지보수성 향상  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;대표 프레임워크:&lt;/strong&gt; &lt;code&gt;Vue.js&lt;/code&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;관계 비교:&lt;/strong&gt;  &lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;MVC&lt;/th&gt;
&lt;th&gt;MVP&lt;/th&gt;
&lt;th&gt;MVVM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;관계&lt;/td&gt;
&lt;td&gt;Controller–View: 1:N&lt;/td&gt;
&lt;td&gt;Presenter–View: 1:1&lt;/td&gt;
&lt;td&gt;ViewModel–View: 1:N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View 참조&lt;/td&gt;
&lt;td&gt;Controller X&lt;/td&gt;
&lt;td&gt;Presenter O&lt;/td&gt;
&lt;td&gt;ViewModel O&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[Flux 패턴]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;의의:&lt;/strong&gt; 데이터의 흐름을 단방향(One-way)으로 유지하는 구조 패턴  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;등장 배경:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;MVC 구조의 양방향 데이터 흐름으로 인한 복잡성 및 일관성 문제 해결  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;구성요소:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Action:&lt;/strong&gt; 사용자 이벤트(입력·클릭 등) 발생 및 디스패처로 전달  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dispatcher:&lt;/strong&gt; Action의 유형(type)에 따라 로직 결정 및 Store로 전달  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Store:&lt;/strong&gt; 애플리케이션의 상태(state) 저장 및 관리 계층  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View:&lt;/strong&gt; Store 데이터를 기반으로 UI 렌더링  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;장점:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;데이터 일관성 강화  &lt;/li&gt;
&lt;li&gt;버그 추적 및 단위 테스트 용이  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;대표 구현체:&lt;/strong&gt; &lt;code&gt;Redux&lt;/code&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;예시 코드:&lt;/strong&gt;  &lt;ul&gt;
&lt;li&gt;&lt;code&gt;switch(action.type)&lt;/code&gt; 구문으로 Action 타입별 상태 갱신 로직 수행  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[전략패턴 vs 의존성주입]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;공통점:&lt;/strong&gt;&lt;br&gt;교체 가능한 구조를 설계하기 위한 패턴 규약  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;차이점:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;전략패턴:&lt;/strong&gt;&lt;br&gt;동일한 행동 계약(인터페이스)을 정의하고, 이를 기반으로 다양한 알고리즘 구현체를 교체 가능하게 하는 &lt;strong&gt;행동패턴 규약&lt;/strong&gt;&lt;br&gt;→ “어떤 전략(행동)을 사용할지 결정하는 구조”  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의존성주입(DI):&lt;/strong&gt;&lt;br&gt;객체 간 의존성을 외부에서 주입하여 결합도를 낮추는 &lt;strong&gt;설계 패턴이자 구조적 원칙&lt;/strong&gt;&lt;br&gt;→ “어떤 객체를 사용할지 외부에서 주입하는 구조”  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;핵심 구분:&lt;/strong&gt;  &lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;전략패턴&lt;/th&gt;
&lt;th&gt;의존성주입(DI)&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;외부 컨테이너(Spring 등)가 제어&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;/tbody&gt;&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[컨텍스트(Context)]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;의의:&lt;/strong&gt;&lt;br&gt;특정 상태나 환경을 캡슐화하거나, 중단된 작업을 재개할 수 있도록 저장하는 최소 데이터 집합을 의미하는 개념적 규약  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;두 가지 의미:&lt;/strong&gt;  &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;상태·환경의 캡슐화&lt;/strong&gt; — 실행 중인 상황(환경)을 묶어 관리하는 개념  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;작업 재개용 정보 저장&lt;/strong&gt; — 예: 컨텍스트 스위칭 시 프로세스의 레지스터 값, 스택 포인터 등을 저장  &lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;구분:&lt;/strong&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Context:&lt;/strong&gt; 환경 자체 (예: 병원 방문 상황)  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contextual Information:&lt;/strong&gt; 해당 환경에서 의미를 갖는 부가 정보 (예: 이름, 주민번호 등)  &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;예시:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;병원 방문 context → “이름”은 contextual information  &lt;/li&gt;
&lt;li&gt;HTTP 요청 context → “HTTP Header”는 contextual information  &lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;strong&gt;[React의 Context API 예시]&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;의의:&lt;/strong&gt;&lt;br&gt;전역적으로 상태(state)를 전달하기 위한 React 내장 상태 전파 API 규약  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;구조:&lt;/strong&gt;  &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const ThemeContext = React.createContext(&amp;#39;light&amp;#39;);

class App extends React.Component {
  render() {
    return (
      &amp;lt;ThemeContext.Provider value=&amp;quot;dark&amp;quot;&amp;gt;
        &amp;lt;Toolbar /&amp;gt;
      &amp;lt;/ThemeContext.Provider&amp;gt;
    );
  }
}

function Toolbar() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;ThemedButton /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

class ThemedButton extends React.Component {
  static contextType = ThemeContext;
  render() {
    return &amp;lt;Button theme={this.context} /&amp;gt;;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study/CS</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/265</guid>
      <comments>https://hereishyun.tistory.com/265#entry265comment</comments>
      <pubDate>Fri, 24 Oct 2025 13:46:06 +0900</pubDate>
    </item>
    <item>
      <title>[CS 지식의 정석] 1. 개발자 필수 지식</title>
      <link>https://hereishyun.tistory.com/264</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[데이터교환형식 #1. JSON과 직렬화와 역직렬화]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JSON(JavaScript Object Notation): &lt;/b&gt;Javascript 객체 문법으로 구조화된 데이터 교환형식.&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;- 프로그래밍 언어와 플랫폼에 독립적 -&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;서로 다른 시스템간에 데이터를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;교환하기 좋음.&amp;nbsp;&lt;br /&gt;- 여러 언어에서 객체, 해시테이블, 딕셔너리 등으로 변환되어 쓰임. (ex. javascript에서는 javascript object, python에서는 dict)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주로 API 반환 형태, 시스템 구성 설정 파일에 활용&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Javascript 객체 문법: 키(key)와 값(value)으로 구성.&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;- 객체 문법 뿐 아니라 단순 배열, 문자열도 표현 가능 (ex. [1, 2, 3, 4] / &quot;문자열&quot;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 배열은 대괄호 []를 기반으로 표현. 배열의 원소는 [0], [1] 와 같이 접근, 해당 key에 대한 value는 .key 또는 [&quot;key&quot;] 방식으로 접근&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- JSON의 타입: 수(Number), 문자열(String), 참/거짓(Boolean), 배열(Array), 객체(Object), null&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - javascript object와 유사. undefined, 메서드 등은 포함 불가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;JSON 직렬화, 역직렬화&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 직렬화 Serialization: 외부 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터를 변환하는 기술.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - JSON.stringify()로 JS Object에서 JSON 구조 문자열로 바꾸는 것이 직렬화.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 역직렬화 Deserialization:&lt;/b&gt; 바이트-&amp;gt;JSON.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - JSON.parse()로 JSON 에서 객체로 바꾸기 위해서 파싱하는 것이 역직렬화.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[데이터&lt;span&gt;&amp;nbsp;&lt;/span&gt;포맷 #2. XML]&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;XML(Extensible Markup Language):&lt;/b&gt; 마크업 형태를 쓰는 데이터 교환형식.&lt;br /&gt;- 마크업(markup): 태그 등을 이용하여 문서나 데이터의 구조를 나타냄. (속성 부여도 가능)&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;br /&gt;1.&amp;nbsp;프롤로그&amp;nbsp;:&amp;nbsp;버전,&amp;nbsp;인코딩&lt;br /&gt;2. 루트요소(단 1개)&lt;br /&gt;3. 하위 요소들&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #409d00;&quot;&gt;&amp;lt;?xml&amp;nbsp;version=&quot;1.0&quot;&amp;nbsp;encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;lt;OSTList&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;OST like=&quot;1&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;lt;name&amp;gt;마녀&amp;nbsp;배달부&amp;nbsp;키키&amp;lt;/name&amp;gt;&amp;nbsp;&amp;lt;song&amp;gt;따스함에&amp;nbsp;둘러쌓인다면&amp;lt;/song&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;lt;/OST&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;lt;OST&amp;nbsp;like=&quot;2&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;lt;name&amp;gt;하울의&amp;nbsp;움직이는&amp;nbsp;성&amp;lt;/name&amp;gt;&amp;nbsp;&amp;lt;song&amp;gt;세계의&amp;nbsp;약속&amp;lt;/song&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;lt;/OST&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;lt;/OSTList&amp;gt;&lt;/span&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;HTML과 XML 비교&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. [용도] HTML 용도: 데이터를 표시 / XML 용도: 데이터 저장 및 전송&lt;br /&gt;2. [태그] HTML은 태그가 미리 정해져 있음*. / XML은 태그가 정해져 있지 않음.&lt;br /&gt;3. [대소문자] HTML은 대소문자 구분 X / &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;XML은 대소문자 구분 O&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;*보충: html 자체적으로는 고유한 태그를 만들 수 없음. JS의 웹 컴포넌트(Web Components) API를 사용하면 커스텀 태그 작성 가능.&lt;/span&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;JSON과 XML 비교&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- [용량] XML은 닫는 태그가 계속 들어가므로 JSON과 비교하면 무거움.&lt;br /&gt;- [Javascript Object 변환 용이성] JSON은 JSON.parse()면 되어서 간단하지만, XML은 JSON보다는 많은 노력이 필요.&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;xml의 대표 용례는 sitemap.xml&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sitemap.xml: 서비스 내 모든 페이지들을 리스트업한 데이터.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 크롤러가 사이트 데이터 수집 시 일부 페이지를 누락할 수 있는 문제를 방지. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(원인: &lt;span style=&quot;text-align: start;&quot;&gt;사이트가 매우 큼, 서로 링크가 종속적으로 연결되지 않음)&lt;/span&gt;&lt;/span&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;span style=&quot;color: #409d00;&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;lt;urlset&amp;nbsp;xmlns=&quot;&lt;a style=&quot;color: #409d00;&quot; href=&quot;http://www.sitemaps.org/schemas/sitemap/0.9&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://www.sitemaps.org/schemas/sitemap/0.9&lt;/a&gt;&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;color: #409d00; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;lt;url&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #409d00; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;lt;loc&amp;gt;&lt;a style=&quot;color: #409d00;&quot; href=&quot;http://www.example.com/foo.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://www.example.com/foo.html&lt;/a&gt;&amp;lt;/loc&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #409d00; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;lt;lastmod&amp;gt;2018-06-04&amp;lt;/lastmod&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;color: #409d00; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;span style=&quot;color: #409d00; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt; &amp;lt;&lt;/span&gt;&lt;/span&gt;url&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;lt;loc&amp;gt;&lt;a style=&quot;color: #409d00;&quot; href=&quot;http://www.example.com/abc.html&quot;&gt;http://www.example.com/abc.html&lt;/a&gt;&amp;lt;/loc&amp;gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #409d00; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;lt;lastmod&amp;gt;2018-06-04&amp;lt;/lastmod&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/url&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&amp;lt;/urlset&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;API (Application Programming Interface):&lt;/b&gt; 두 시스템 간 통신 규약을 정의한&lt;b&gt; 중계 계층.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;- 서로 다른 소프트웨어 컴포넌트나 시스템 간에 데이터나 기능을 교환하기 위한 명세이자 인터페이스로, 한 프로그램이 다른 프로그램의 기능을 표준화된 방식으로 호출&amp;middot;이용할 수 있도록 정의한 중간 계층을 의미.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;- 요청자(A 컴퓨터)와 응답자(B 컴퓨터) 간 데이터 교환 방식(HTTP, HTTPS, GET, POST 등)을 정의함.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 과거에는 라이브러리&amp;middot;프레임워크 명세서를 포함했으나, 현재는 WEB API(REST API, WebSocket API 등)를 중심으로 사용됨.&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;인터페이스 (Interface): &lt;/b&gt;서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면&lt;br /&gt;- 특징: 내부 서버 구현과 무관하게 통신 가능, 직접 DB 접근 방지(보안&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;[API의 장점]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;보안성 강화&lt;br /&gt;- DB 구조, 테이블 정보, 상수값 등 내부 로직을 노출하지 않아도 됨.&lt;br /&gt;- 필요한 데이터만 선택적으로 공개 가능.&lt;/li&gt;
&lt;li&gt;유연한 서비스 구조&lt;br /&gt;- 내부 DB나 서버 로직 변경 시에도 API 규격만 유지되면 클라이언트 업데이트 불필요.&lt;br /&gt;- 예: DB 튜닝 시 앱 업데이트 불필요.&lt;/li&gt;
&lt;li&gt;개발 효율성&lt;br /&gt;- OPEN API를 통해 외부 서비스와 손쉽게 연동 가능. (ex. 네이버 로그인, 카카오 지도 API)&lt;/li&gt;
&lt;li&gt;데이터 통합 관리&lt;br /&gt;- 이벤트 발생 시 API 호출로 데이터를 중앙화 가능. (ex. yes24 베스트셀러 API &amp;rarr; 사용자 클릭 이벤트 집계)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[API의 종류]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 접근 범위 특징 활용 예&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&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;tr&gt;
&lt;td&gt;Private API&lt;/td&gt;
&lt;td&gt;내부 전용&lt;/td&gt;
&lt;td&gt;하드코딩된 해시 키 기반 통신, 서버 간 비공개 통신&lt;/td&gt;
&lt;td&gt;파트너 간 전용 API(헤더 키 전달)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public API&lt;/td&gt;
&lt;td&gt;외부 공개&lt;/td&gt;
&lt;td&gt;사용자 제한 설정(일일 호출 수 등)&lt;/td&gt;
&lt;td&gt;네이버, 카카오 OPEN API&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;[API 실습 예시 &amp;ndash; Open API 기반 온도 예측]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Open-Meteo API를 통해 인공지능 모델 없이 실시간 날씨 예측 데이터 요청. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;특징:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;API 버전 명시 (예: v1),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;좌표 기반 데이터 요청&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;const OPEN_API = &quot;&lt;a href=&quot;https://api.open-meteo.com/v1/forecast?latitude=37.57&amp;amp;longitude=126.98&amp;amp;hourly=temperature_2m&amp;amp;current_weather=true&amp;amp;timezone=Asia%2FTokyo&quot;&gt;https://api.open-meteo.com/v1/forecast?latitude=37.57&amp;amp;longitude=126.98&amp;amp;hourly=temperature_2m&amp;curren;t_weather=true&amp;amp;timezone=Asia%2FTokyo&lt;/a&gt;&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;[API 구축]&lt;br /&gt;- 목표: 내부 로직이 변경되어도 API 명세를 변경하지 않고 호환성 유지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Node.js: Google V8 엔진 기반 JavaScript 런타임 환경. 비동기 이벤트 주도형 구조. 자바스크립트로 서버&amp;middot;알고리즘&amp;middot;게임 등 실행 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Express.js: Node.js 기반 웹 프레임워크. 라우팅, 미들웨어, 정적 자원 제공 기능 간결화&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;[라우팅 (Routing)]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URI(경로)와 HTTP 메서드(GET, POST 등)에 따라 클라이언트 요청에 응답하는 규약&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: /api/users &amp;rarr; GET(조회), POST(등록), PUT(수정), DELETE(삭제)&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;[URI 분석 예시]&lt;br /&gt;&lt;a href=&quot;http://127.0.0.1:3000/&quot;&gt;http://127.0.0.1:3000&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜 : HTTP&lt;br /&gt;IP&amp;nbsp;:&amp;nbsp;127.0.0.1&amp;nbsp;(루프백IP)&lt;br /&gt;port&amp;nbsp;:&amp;nbsp;3000&lt;br /&gt;app.listen(port,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{&lt;br /&gt;console.log(`http://127.0.0.1:${port}`)&lt;br /&gt;port는 사실 숨겨져 있음&lt;br /&gt;https&amp;nbsp;port&amp;nbsp;:&amp;nbsp;443이&amp;nbsp;기본포트&lt;br /&gt;http&amp;nbsp;port&amp;nbsp;:&amp;nbsp;80이&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;ndash; 실제 사이트 URI]&lt;br /&gt;&lt;a href=&quot;http://www.naver.com&quot;&gt;http://www.naver.com&lt;/a&gt; &amp;rarr; HTTP 기본 포트 80&lt;br /&gt;브라우저 접근 시 프로토콜, IP, 포트는 자동 추상화됨&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;p data-end=&quot;52&quot; data-start=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;[클라우드의 기반 기술 &amp;ndash; 가상머신(Virtual Machine)]&lt;/p&gt;
&lt;p data-end=&quot;131&quot; data-start=&quot;54&quot; data-ke-size=&quot;size16&quot;&gt;전통적 배포방식: 물리 컴퓨터 1대에 OS 1개 설치 &amp;rarr; 여러 프로그램이 같은 자원을 공유&lt;br /&gt;&amp;rarr; 한 앱의 변경이 다른 앱에 영향 가능&lt;/p&gt;
&lt;p data-end=&quot;218&quot; data-start=&quot;133&quot; data-ke-size=&quot;size16&quot;&gt;가상화 배포방식: 하드웨어 위에 하이퍼바이저(Hypervisor)를 두고 여러 OS를 독립적으로 실행&lt;br /&gt;&amp;rarr; 한 컴퓨터에서 여러 VM 동시 구동 가능&lt;/p&gt;
&lt;p data-end=&quot;218&quot; data-start=&quot;133&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;225&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;특징: 하드웨어를 소프트웨어적으로 구현. 설정만으로 CPU&amp;middot;RAM 할당 변경 가능. 서로 완전히 격리된 환경 제공(샌드박스 구조)&lt;/p&gt;
&lt;p data-end=&quot;225&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;단점: 각 VM에 OS를 별도 설치해야 함&lt;/p&gt;
&lt;p data-end=&quot;225&quot; data-start=&quot;220&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;332&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[하이퍼바이저(Hypervisor)]&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;450&quot; data-start=&quot;354&quot; data-ke-size=&quot;size16&quot;&gt;의의: 단일 시스템에서 여러 VM을 구동할 수 있게 하는 중간 계층&lt;br /&gt;역할: 하드웨어 자원 분리&amp;middot;할당 및 VM 관리&lt;br /&gt;예시: VMware, KVM, Hyper-V&lt;/p&gt;
&lt;p data-end=&quot;450&quot; data-start=&quot;354&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;464&quot; data-start=&quot;452&quot; data-ke-size=&quot;size16&quot;&gt;[클라우드 배포 방식]&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;708&quot; data-start=&quot;466&quot; data-ke-align=&quot;alignLeft&quot;&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;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;611&quot; data-start=&quot;517&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;538&quot; data-start=&quot;517&quot;&gt;오프프레미스 (Off-Premise)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;566&quot; data-start=&quot;538&quot;&gt;외부 클라우드 서비스 제공업체가 인프라 호스팅&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;592&quot; data-start=&quot;566&quot;&gt;인프라 설치 없이 저비용 운영, 확장 용이&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;611&quot; data-start=&quot;592&quot;&gt;AWS, Azure, NCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;708&quot; data-start=&quot;612&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;631&quot; data-start=&quot;612&quot;&gt;온프레미스 (On-Premise)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;660&quot; data-start=&quot;631&quot;&gt;기업이 자체 데이터센터(IDC) 직접 구축&amp;middot;운영&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;681&quot; data-start=&quot;660&quot;&gt;보안&amp;middot;통제력 우수, 초기비용 높음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;708&quot; data-start=&quot;681&quot;&gt;네이버 춘천 데이터센터 (프리쿨링 방식 냉각)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;723&quot; data-start=&quot;710&quot; data-ke-size=&quot;size16&quot;&gt;[클라우드 서비스 모델]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;798&quot; data-start=&quot;725&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;798&quot; data-start=&quot;725&quot;&gt;IaaS (Infrastructure as a Service)&lt;br /&gt;의의: 인프라(서버&amp;middot;스토리지&amp;middot;네트워크)만 제공&lt;br /&gt;특징: OS&amp;middot;Runtime&amp;middot;DB를 사용자가 직접 설치, 특정 플랫폼에 종속되지 않음, 유연성 높음, 운영비 효율 낮음&lt;br /&gt;예시: AWS EC2, Naver Cloud Platform(NCP)&lt;/li&gt;
&lt;/ol&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;975&quot; data-start=&quot;911&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;975&quot; data-start=&quot;911&quot;&gt;PaaS (Platform as a Service)&lt;br /&gt;의의: 개발 플랫폼 및 런타임 환경 제공&lt;br /&gt;특징: Node.js, MongoDB 등 미리 설치, CI/CD 및 모니터링 제공, 운영 효율 높으나 플랫폼 종속성 존재&lt;br /&gt;예시: Heroku, Google App Engine&lt;/li&gt;
&lt;/ol&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1148&quot; data-start=&quot;1081&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1148&quot; data-start=&quot;1081&quot;&gt;SaaS (Software as a Service)&lt;br /&gt;의의: 완성된 소프트웨어를 서비스 형태로 제공&lt;br /&gt;특징: 별도 설치 없이 즉시 사용, 실시간 협업, 버전 관리 용이&lt;br /&gt;예시: Google Docs, Notion, Slack&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1238&quot; data-start=&quot;1221&quot; data-ke-size=&quot;size16&quot;&gt;[IaaS vs PaaS 비교]&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1348&quot; data-start=&quot;1240&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;IaaS&lt;/td&gt;
&lt;td&gt;PaaS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1297&quot; data-start=&quot;1282&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1286&quot; data-start=&quot;1282&quot;&gt;유연성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1291&quot; data-start=&quot;1286&quot;&gt;높음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1297&quot; data-start=&quot;1291&quot;&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1313&quot; data-start=&quot;1298&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1302&quot; data-start=&quot;1298&quot;&gt;종속성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1307&quot; data-start=&quot;1302&quot;&gt;낮음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1313&quot; data-start=&quot;1307&quot;&gt;높음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1329&quot; data-start=&quot;1314&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1318&quot; data-start=&quot;1314&quot;&gt;이식성&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1323&quot; data-start=&quot;1318&quot;&gt;높음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1329&quot; data-start=&quot;1323&quot;&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1348&quot; data-start=&quot;1330&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1334&quot; data-start=&quot;1330&quot;&gt;운영비&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1341&quot; data-start=&quot;1334&quot;&gt;비효율적&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1348&quot; data-start=&quot;1341&quot;&gt;효율적&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1379&quot; data-start=&quot;1350&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[컨테이너(Container)와 도커(Docker)]&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1445&quot; data-start=&quot;1381&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너: 애플리케이션 실행 환경을 OS 레벨에서 격리해 빠르고 안정적으로 배포하는 단위&lt;br /&gt;특징: OS를 공유 &amp;rarr; VM보다 경량&amp;middot;고속, 모든 의존성(라이브러리, 설정 등)을 함께 패키징, 완전한 격리성 제공, OS&amp;nbsp;문제&amp;nbsp;발생&amp;nbsp;시&amp;nbsp;다른&amp;nbsp;컨테이너&amp;nbsp;영향&amp;nbsp;가능&lt;/p&gt;
&lt;p data-end=&quot;1445&quot; data-start=&quot;1381&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1445&quot; data-start=&quot;1381&quot; data-ke-size=&quot;size16&quot;&gt;도커(Docker): 컨테이너 생성&amp;middot;관리&amp;middot;배포를 위한 플랫폼&lt;/p&gt;
&lt;p data-end=&quot;1445&quot; data-start=&quot;1381&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;특징:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;동일 이미지에서 다수의 컨테이너 생성 가능,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이미지 불변성으로 재현성 확보&lt;br /&gt;&lt;b&gt;핵심 구성:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1713&quot; data-start=&quot;1599&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1634&quot; data-start=&quot;1599&quot;&gt;&lt;b&gt;Dockerfile: 패키지&amp;middot;환경 변수 설정 기록 파일&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1675&quot; data-start=&quot;1635&quot;&gt;&lt;b&gt;Docker Image: 컨테이너 실행을 위한 불변 상태 스냅샷&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1713&quot; data-start=&quot;1676&quot;&gt;&lt;b&gt;Docker Container: 실행 중인 이미지 인스턴스&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1776&quot; data-start=&quot;1715&quot; data-ke-size=&quot;size16&quot;&gt;작동 과정: Dockerfile &amp;rarr; Build &amp;rarr; Image 생성 &amp;rarr; Run &amp;rarr; Container 실행&lt;/p&gt;
&lt;p data-end=&quot;1851&quot; data-start=&quot;1834&quot; data-ke-size=&quot;size16&quot;&gt;도커 활용 예시: 클라우드 컨테이너 배포(AWS ECS, Kubernetes 등) (구글 서비스 대부분이 도커 기반)&lt;/p&gt;
&lt;p data-end=&quot;1851&quot; data-start=&quot;1834&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1959&quot; data-start=&quot;1940&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[CI/CD (지속적 통합&amp;middot;배포)]: 코드 작성 &amp;rarr; 테스트 &amp;rarr; 빌드 &amp;rarr; 배포까지 자동화하는 파이프라인 구조 규약&lt;/b&gt;&lt;br /&gt;(Continuous Integration / Continuous Delivery / Continuous Deployment)&lt;/p&gt;
&lt;p data-end=&quot;2089&quot; data-start=&quot;2083&quot; data-ke-size=&quot;size16&quot;&gt;필요성: 다수 개발자 협업 시 배포 충돌, 버전 불일치 방지, 테스트 자동화로 품질 유지&lt;/p&gt;
&lt;p data-end=&quot;2150&quot; data-start=&quot;2143&quot; data-ke-size=&quot;size16&quot;&gt;단계별 구성:&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2316&quot; data-start=&quot;2152&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;단계&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2226&quot; data-start=&quot;2178&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2206&quot; data-start=&quot;2178&quot;&gt;Continuous Integration (CI)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2226&quot; data-start=&quot;2206&quot;&gt;코드 빌드&amp;middot;테스트&amp;middot;병합 자동화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2268&quot; data-start=&quot;2227&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2252&quot; data-start=&quot;2227&quot;&gt;Continuous Delivery (CD)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2268&quot; data-start=&quot;2252&quot;&gt;릴리스 버전 자동 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2316&quot; data-start=&quot;2269&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2291&quot; data-start=&quot;2269&quot;&gt;Continuous Deployment&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2316&quot; data-start=&quot;2291&quot;&gt;실제 서비스 환경(프로덕션) 자동 배포&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2323&quot; data-start=&quot;2318&quot; data-ke-size=&quot;size16&quot;&gt;장점: 코드 품질 유지, 테스트 자동화 강제, 배포 주기 단축, 장애 발생 시 롤백 용이&lt;/p&gt;
&lt;p data-end=&quot;2391&quot; data-start=&quot;2384&quot; data-ke-size=&quot;size16&quot;&gt;대표 툴:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2475&quot; data-start=&quot;2392&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2440&quot; data-start=&quot;2392&quot;&gt;CI/CD 플랫폼: GitHub Actions, Jenkins, CircleCI&lt;/li&gt;
&lt;li data-end=&quot;2475&quot; data-start=&quot;2441&quot;&gt;통합형 플랫폼: Heroku(Git 연동 자동 배포 지원)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2491&quot; data-start=&quot;2477&quot; data-ke-size=&quot;size16&quot;&gt;파이프라인 구성 요소:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2830&quot; data-start=&quot;2492&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2557&quot; data-start=&quot;2492&quot;&gt;Build (빌드)
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2557&quot; data-start=&quot;2511&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2530&quot; data-start=&quot;2511&quot;&gt;코드 번들링 및 자원 패키징&lt;/li&gt;
&lt;li data-end=&quot;2557&quot; data-start=&quot;2534&quot;&gt;예: webpack (모듈 번들러)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2656&quot; data-start=&quot;2558&quot;&gt;Test (테스트)
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2656&quot; data-start=&quot;2577&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2630&quot; data-start=&quot;2577&quot;&gt;단위 테스트(Unit), 통합 테스트(Integration), 엔드투엔드(E2E) 테스트&lt;/li&gt;
&lt;li data-end=&quot;2656&quot; data-start=&quot;2634&quot;&gt;대표 도구: Mocha, Jest&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2728&quot; data-start=&quot;2657&quot;&gt;Merge (머지)
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2728&quot; data-start=&quot;2676&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2699&quot; data-start=&quot;2676&quot;&gt;Git 기반 코드 병합, 충돌 해결&lt;/li&gt;
&lt;li data-end=&quot;2728&quot; data-start=&quot;2703&quot;&gt;작은 단위(issue 단위) 병합 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2830&quot; data-start=&quot;2729&quot;&gt;Deploy (배포)
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2830&quot; data-start=&quot;2749&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2787&quot; data-start=&quot;2749&quot;&gt;서비스, 관리자페이지, 데이터 파이프라인 등 환경별 배포 포함&lt;/li&gt;
&lt;li data-end=&quot;2830&quot; data-start=&quot;2791&quot;&gt;GitHub Actions + Heroku 조합으로 자동화 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;2836&quot; data-start=&quot;2832&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[요약]&lt;/b&gt;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2923&quot; data-start=&quot;2838&quot; data-ke-size=&quot;size16&quot;&gt;클라우드: 가상화 기반의 분산 컴퓨팅 인프라. 도커: 컨테이너 단위 애플리케이션 배포 기술. CI/CD: 지속적 통합&amp;middot;자동 배포 파이프라인 규약.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2923&quot; data-start=&quot;2838&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-message-model-slug=&quot;gpt-5&quot; data-message-id=&quot;1dbf0b4f-4d1a-4569-9d24-f3da1bc02668&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;p data-end=&quot;225&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[클래스, 객체, 인스턴스]&lt;/b&gt;&lt;br /&gt;&lt;b&gt;클래스(Class):&lt;/b&gt; 객체를 생성하기 위한 청사진 또는 설계 규약. 속성(필드)과 동작(메서드)의 집합 정의.&lt;br /&gt;&lt;b&gt;객체(Object):&lt;/b&gt; 클래스에서 생성된 실체. 클래스의 구조를 실제 메모리에 할당한 형태.&lt;br /&gt;&lt;b&gt;인스턴스(Instance):&lt;/b&gt; 객체가 메모리에 로드되어 실행 중인 상태. 런타임 시점에 존재하는 실체. ※ AWS 등에서는 &amp;lsquo;가상 서버 단위&amp;rsquo;를 의미하기도 함.&lt;/p&gt;
&lt;p data-end=&quot;225&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;511&quot; data-start=&quot;227&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[static 키워드]&lt;/b&gt;&lt;br /&gt;- 의의: 클래스의 인스턴스가 아닌 클래스 자체에 속하는 멤버를 정의하는 규약. 모든 객체가 공유하는 변수&amp;middot;메서드로 사용.&lt;br /&gt;- 특징: 인스턴스화 없이 클래스명.메서드() 형태로 접근 가능, 클래스 내부에서 공통 기능&amp;middot;전역 자원 관리 시 유용, 명시적이며 가시성 높은 공유 자원 관리 가능.&lt;br /&gt;- 단점: Heap이 아닌 Method Area에 미리 할당되어 GC(가비지 컬렉션) 미적용, 프로그램 종료 전까지 메모리 점유로 불필요한 낭비 위험, 객체지향 원칙(캡슐화&amp;middot;다형성) 약화.&lt;/p&gt;
&lt;p data-end=&quot;511&quot; data-start=&quot;227&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;555&quot; data-start=&quot;513&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[오버로딩(Overloading) vs 오버라이딩(Overriding)]&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;814&quot; data-start=&quot;556&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;오버로딩&lt;/td&gt;
&lt;td&gt;오버라이딩&lt;span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;678&quot; data-start=&quot;613&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;616&quot; data-start=&quot;613&quot;&gt;정의&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;651&quot; data-start=&quot;616&quot;&gt;동일한 메서드명으로 매개변수 타입&amp;middot;개수&amp;middot;순서를 다르게 정의&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;678&quot; data-start=&quot;651&quot;&gt;상위 클래스 메서드를 하위 클래스가 재정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;711&quot; data-start=&quot;679&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;685&quot; data-start=&quot;679&quot;&gt;사용 위치&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;696&quot; data-start=&quot;685&quot;&gt;동일 클래스 내&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;711&quot; data-start=&quot;696&quot;&gt;상속 관계 클래스 간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;750&quot; data-start=&quot;712&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;715&quot; data-start=&quot;712&quot;&gt;목적&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;731&quot; data-start=&quot;715&quot;&gt;코드 유연성&amp;middot;가독성 향상&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;750&quot; data-start=&quot;731&quot;&gt;다형성 실현 및 행위 재정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;784&quot; data-start=&quot;751&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;754&quot; data-start=&quot;751&quot;&gt;제약&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;759&quot; data-start=&quot;754&quot;&gt;없음&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;784&quot; data-start=&quot;759&quot;&gt;static, final 메서드는 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;814&quot; data-start=&quot;785&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;791&quot; data-start=&quot;785&quot;&gt;실행 시점&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;802&quot; data-start=&quot;791&quot;&gt;컴파일 시 결정&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;814&quot; data-start=&quot;802&quot;&gt;런타임 시 결정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1120&quot; data-start=&quot;816&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[추상화(Abstraction)]&lt;/b&gt;&lt;br /&gt;- 의의: 복잡한 구조나 데이터를 단순화하여 핵심만 표현하는 설계 원칙. 불필요한 세부 구현을 감추고 인터페이스로 표현.&lt;br /&gt;- 유형: (1) 데이터 추상화 - 공통 속성을 묶고 세부 차이는 제거 (예: 고양이&amp;middot;강아지 &amp;rarr; &amp;ldquo;동물&amp;rdquo;) (2) 프로세스 추상화 - 내부 절차를 감추고 인터페이스로 제공 (예: DB 내부 저장 과정은 숨기고 INSERT, UPDATE만 노출).&lt;br /&gt;시스템 내 예시: MySQL 아키텍처는 내부 I/O 구조를 감춘 채 쿼리 단위 접근 제공. API, 모듈화 구조도 추상화의 구현 사례.&lt;/p&gt;
&lt;p data-end=&quot;1483&quot; data-start=&quot;1122&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1483&quot; data-start=&quot;1122&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[컴파일러(Compiler)와 인터프리터(Interpreter)]&lt;/b&gt;&lt;br /&gt;공통점: 고수준 언어를 기계어(Machine Code, 0&amp;middot;1)로 변환하는 변환기 규약.&lt;br /&gt;컴파일러 방식: 전체 코드를 한 번에 기계어로 변환, 실행 전 변환으로 속도 빠름, 수정 시 재컴파일 필요. 사용 언어: C, C++, Go, Rust. 과정: 전처리 &amp;rarr; 컴파일러 &amp;rarr; 어셈블러 &amp;rarr; 링커 &amp;rarr; 실행파일 생성.&lt;br /&gt;인터프리터 방식: 코드를 한 줄씩 읽고 즉시 실행, 시작은 빠르나 전체 속도는 느림, 실행 중 변환으로 수정 후 즉시 실행 가능. 사용 언어: Python, JavaScript. 장점: 실시간 실행 및 디버깅 용이. 단점: 반복 변환으로 인한 성능 저하.&lt;/p&gt;
&lt;p data-end=&quot;1483&quot; data-start=&quot;1122&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1869&quot; data-start=&quot;1485&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[JIT 컴파일러 (Just-In-Time Compiler)]&lt;/b&gt;&lt;br /&gt;의의: 컴파일러와 인터프리터의 장점을 결합한 동적(실시간) 컴파일 방식으로, 실행 중 자주 호출되는 코드를 선택적으로 기계어로 변환.&lt;br /&gt;작동 원리: (1) 코드 분석 - 실행 중 &amp;ldquo;핫스팟(hot spot)&amp;rdquo; 탐지 (2) 동적 컴파일 - 자주 실행되는 코드만 변환 (3) 최적화 - 메모리 접근&amp;middot;GC 오버헤드 최소화 (4) 캐싱 - 변환된 코드 메모리 저장 및 재사용.&lt;br /&gt;대표 구현: JVM, .NET CLR, V8 Engine(Node.js, Chrome).&lt;br /&gt;장점: 반복 실행 코드의 성능 극대화, 인터프리터 대비 빠른 실행 속도. 단점: 캐시 저장으로 메모리 사용량 증가, 초기 실행 시 분석 오버헤드 발생.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1991&quot; data-start=&quot;1871&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1991&quot; data-start=&quot;1871&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[요약]&lt;/b&gt;&lt;br /&gt;클래스는 객체의 설계도, static은 공용 자원 선언 규약, 오버로딩&amp;middot;오버라이딩은 다형성 구현 수단, 추상화는 복잡성 완화의 핵심 개념, 컴파일러&amp;middot;인터프리터&amp;middot;JIT은 언어 실행의 세 가지 접근 구조임.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;2923&quot; data-start=&quot;2838&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/CS</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/264</guid>
      <comments>https://hereishyun.tistory.com/264#entry264comment</comments>
      <pubDate>Thu, 16 Oct 2025 12:59:50 +0900</pubDate>
    </item>
    <item>
      <title>[백준 골드2] 1655번: 가운데를 말해요 (우선순위 큐) - Java</title>
      <link>https://hereishyun.tistory.com/263</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1655번:&amp;nbsp;가운데를&amp;nbsp;말해요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1655&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1655&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;&lt;b&gt;문제&lt;/b&gt;&lt;br /&gt;백준이는 동생에게 &quot;가운데를 말해요&quot; 게임을 가르쳐주고 있다. 백준이가 정수를 하나씩 외칠때마다 동생은 지금까지 백준이가 말한 수 중에서 중간값을 말해야 한다. 만약, 그동안 백준이가 외친 수의 개수가 짝수개라면 중간에 있는 두 수 중에서 작은 수를 말해야 한다.&lt;br /&gt;예를&amp;nbsp;들어&amp;nbsp;백준이가&amp;nbsp;동생에게&amp;nbsp;1,&amp;nbsp;5,&amp;nbsp;2,&amp;nbsp;10,&amp;nbsp;-99,&amp;nbsp;7,&amp;nbsp;5를&amp;nbsp;순서대로&amp;nbsp;외쳤다고&amp;nbsp;하면,&amp;nbsp;동생은&amp;nbsp;1,&amp;nbsp;1,&amp;nbsp;2,&amp;nbsp;2,&amp;nbsp;2,&amp;nbsp;2,&amp;nbsp;5를&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;br /&gt;&lt;br /&gt;&lt;b&gt;입력&lt;/b&gt;&lt;br /&gt;첫째&amp;nbsp;줄에는&amp;nbsp;백준이가&amp;nbsp;외치는&amp;nbsp;정수의&amp;nbsp;개수&amp;nbsp;N이&amp;nbsp;주어진다.&amp;nbsp;N은&amp;nbsp;1보다&amp;nbsp;크거나&amp;nbsp;같고,&amp;nbsp;100,000보다&amp;nbsp;작거나&amp;nbsp;같은&amp;nbsp;자연수이다.&amp;nbsp;그&amp;nbsp;다음&amp;nbsp;N줄에&amp;nbsp;걸쳐서&amp;nbsp;백준이가&amp;nbsp;외치는&amp;nbsp;정수가&amp;nbsp;차례대로&amp;nbsp;주어진다.&amp;nbsp;정수는&amp;nbsp;-10,000보다&amp;nbsp;크거나&amp;nbsp;같고,&amp;nbsp;10,000보다&amp;nbsp;작거나&amp;nbsp;같다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;출력&lt;/b&gt;&lt;br /&gt;한&amp;nbsp;줄에&amp;nbsp;하나씩&amp;nbsp;N줄에&amp;nbsp;걸쳐&amp;nbsp;백준이의&amp;nbsp;동생이&amp;nbsp;말해야&amp;nbsp;하는&amp;nbsp;수를&amp;nbsp;순서대로&amp;nbsp;출력한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;예제&amp;nbsp;입력&amp;nbsp;1&amp;nbsp;&lt;/b&gt;&lt;br /&gt;7&lt;br /&gt;1&lt;br /&gt;5&lt;br /&gt;2&lt;br /&gt;10&lt;br /&gt;-99&lt;br /&gt;7&lt;br /&gt;5&lt;br /&gt;&lt;b&gt;예제&amp;nbsp;출력&amp;nbsp;1&amp;nbsp;&lt;/b&gt;&lt;br /&gt;1&lt;br /&gt;1&lt;br /&gt;2&lt;br /&gt;2&lt;br /&gt;2&lt;br /&gt;2&lt;br /&gt;5&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;알고리즘: 자료 구조, 우선순위&amp;nbsp;큐&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;N의 범위가 최대 10만이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;매번 데이터를 정렬하면 비효율적일 것이므로, 정렬된 자료구조인 힙을 이용하는 우선순위 큐 두 개를 사용해야겠다고 생각했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;내림차순 우선순위 큐 smalls: &lt;span style=&quot;background-color: #ffffff; 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;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;오름차순 우선순위 큐 bigs: &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;중앙값 초과의&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;값들을 저장 (*숫자 값이 아닌, 위치에&amp;nbsp; 따른 초과를 위미)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;smalls의 크기 &amp;gt;= bigs의 크기를 유지하며&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;중간의 원소를 bigs로 옮겨주는 방식으로 구현했다.&lt;/span&gt;&lt;/span&gt;&lt;/span&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;pq.peek()이 기억이 안 나서 첫 풀이는 다소 복잡하다.&lt;/p&gt;
&lt;pre id=&quot;code_1760512584291&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main
{
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        PriorityQueue&amp;lt;Integer&amp;gt; smalls = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());
        PriorityQueue&amp;lt;Integer&amp;gt; bigs = new PriorityQueue&amp;lt;&amp;gt;();
        for(int i=0; i&amp;lt;n; i++){
            int input = Integer.parseInt(br.readLine());
            if(smalls.isEmpty()){
                smalls.add(input);
            } else if (smalls.size()&amp;lt;=bigs.size()){
                int s=smalls.poll();
                if(s&amp;gt;=input) {
                    smalls.add(input);
                    smalls.add(s);
                } else {
                    int b=bigs.poll();
                    if(b&amp;gt;=input){
                        smalls.add(input);
                        smalls.add(s);
                        bigs.add(b);
                    } else {
                        smalls.add(s);
                        smalls.add(b);
                        bigs.add(input);
                    }
                }
            } else {
                int s=smalls.poll();
                if(s&amp;gt;=input) {
                    smalls.add(input);
                    bigs.add(s);
                } else {
                    smalls.add(s);
                    bigs.add(input);
                }
            }
            int sTop = smalls.poll();
            System.out.println(sTop);
            smalls.add(sTop);
        }
    }
}&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;/p&gt;
&lt;pre id=&quot;code_1760512865463&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main
{
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        PriorityQueue&amp;lt;Integer&amp;gt; smalls = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());
        PriorityQueue&amp;lt;Integer&amp;gt; bigs = new PriorityQueue&amp;lt;&amp;gt;();
        for(int i=0; i&amp;lt;n; i++){
            int input = Integer.parseInt(br.readLine());
            // 삽입
            if (smalls.isEmpty() || input &amp;lt;= smalls.peek()) {
                smalls.offer(input);
            } else {
                bigs.offer(input);
            }
            // 균형 조정 
            if (smalls.size() &amp;gt; bigs.size()+1) {
                bigs.offer(smalls.poll());
            } else if (bigs.size() &amp;gt; smalls.size()) {
                smalls.offer(bigs.poll());
            }
            System.out.println(smalls.peek());
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/PS</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/263</guid>
      <comments>https://hereishyun.tistory.com/263#entry263comment</comments>
      <pubDate>Wed, 15 Oct 2025 16:21:50 +0900</pubDate>
    </item>
    <item>
      <title>[Do it! 알고리즘 코딩테스트 - 자바 편] 05. 정렬</title>
      <link>https://hereishyun.tistory.com/262</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정렬 알고리즘들과 정의&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 143px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 18px;&quot;&gt;&lt;b&gt;정렬 알고리즘&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 18px;&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 18px;&quot;&gt;&lt;b&gt;버블&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 18px;&quot;&gt;데이터끼리 인접 요소끼리 비교하고, swap 연산을 수행하며 졍렬하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 18px;&quot;&gt;&lt;b&gt;선택&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 18px;&quot;&gt;대상에서 가장 크거나 작은 데이터를 찾아 선택하는 과정을 반복하면서 정렬하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 18px;&quot;&gt;&lt;b&gt;삽입&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 18px;&quot;&gt;대상을 선택해 정렬된 영역에서 선택 데이터의 적절한 위치를 찾아 삽입하면서 정렬하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 18px;&quot;&gt;&lt;b&gt;퀵&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 18px;&quot;&gt;pivot 값을 선정해 해당 값을 기준으로 정렬하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 18px;&quot;&gt;&lt;b&gt;병합(합병)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 18px;&quot;&gt;이미 정렬된 부분 집합들을 효율적으로 병합해 전체를 정렬하는 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 18px;&quot;&gt;&lt;b&gt;힙&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 18px;&quot;&gt;최대 힙 트리나 최소 힙 트리를 구성해 정렬을 하는 방식 (내림차순 정렬-최소 힙 / 오름차순 정렬-최대 힙)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 17px;&quot;&gt;&lt;b&gt;&lt;b&gt;기수&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 87.4419%; height: 17px;&quot;&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;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;05-1. 버블 정렬&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버블 정렬: 두 인접한 데이터의 크기를 비교해 정렬. 시간 복잡도 O(n^2)으로 다른 알고리즘보다 속도가 느림.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루프를 돌면서 인접한 데이터 간에 swap 연산을 해 정렬.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 특정한 루프의 전체 영역에서 swap이 한 번도 발생하지 않았다면 데이터가 모두 정렬되었다는 뜻, 프로세스를 종료해도 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[2750번: 수 정렬하기] / 브2&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;c++로 풀었었어서 생략&lt;/p&gt;
&lt;pre id=&quot;code_1759746879041&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;algorithm&amp;gt;
using namespace std;

int main()
{
    int N;
    cin &amp;gt;&amp;gt; N;
    int* arr = new int[N];
    for (int i = 0; i &amp;lt; N; i++) {
        cin &amp;gt;&amp;gt; arr[i];
    }
    sort(arr, arr + N);
    for (int i = 0; i &amp;lt; N; i++) {
        cout &amp;lt;&amp;lt; arr[i] &amp;lt;&amp;lt; endl;
    }
    delete[] arr; // 메모리 해제
    return 0;
}&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;/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;for(int i=0; i&amp;lt;N-1; i++) {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; for(int j=0; j&amp;lt;n-1-i; j++){&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(A[j]&amp;gt;A[j+1){&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;int temp=A[j];&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; A[j]=A[j+1];&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; A[j+1]=temp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;}&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[1377번: 버블 소트] / 골2&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 c++ 코드를 제공해주었길래 그대로 출력하도록 했는데, 시간초과가 나서 책 을 보고 다시 풀었다...&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버블 정렬에서는 한 번의 루프마다 각 원소가 최대 한 칸씩만 왼쪽으로 이동할 수 있다. 따라서 원소가 처음 위치에서 얼마나 멀리 왼쪽으로 이동했는지를 보면, 실제 버블 정렬이 완료되기까지 필요한 최소 루프 횟수를 구할 수 있다.&lt;br /&gt;실제 정렬 자체는 평균 시간 복잡도 O(n log n)인 Arrays.sort()로 빠르게 수행하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;버블 정렬이 완료되는 최소 루프 횟수는 각 원소의 (정렬 전 인덱스 &amp;minus; 정렬 후 인덱스) 값 중 최댓값에 1을 더해 계산한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759747241258&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main
{
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[][] A = new int[n][2];
        for(int i=0; i&amp;lt;n; i++) {
            A[i][0] = i; // 정렬 전 인덱스
            A[i][1] = Integer.parseInt(br.readLine()); // 값
        }
        Arrays.sort(A, (a, b) -&amp;gt; {
            if(a[1]!=b[1]) return Integer.compare(a[1], b[1]); // 값 기준 정렬
            return Integer.compare(a[0], b[0]);
        });
        int max=0;
        for(int i=0; i&amp;lt;n; i++) {
            if (max &amp;lt; A[i][0]-i) 
                max = A[i][0]-i;
        }
        System.out.println(max+1);
    }
}

    // 문제에서 제공한 코드, 그러나 이렇게 실행하면 시간초과
    // bool changed = false;
    // for (int i=1; i&amp;lt;=N+1; i++) {
    //     changed = false;
    //     for (int j=1; j&amp;lt;=N-i; j++) {
    //         if (A[j] &amp;gt; A[j+1]) {
    //             changed = true;
    //             swap(A[j], A[j+1]);
    //         }
    //     }
    //     if (changed == false) {
    //         cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; '\n';
    //         break;
    //     }
    // }&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;05-2. 선택 정렬&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;span style=&quot;color: #ef5369;&quot;&gt;- 구현 방법이 복잡하고 시간 복잡도도 O(n^2)으로 효율적이지 않아 코딩 테스트에서는 많이 사용하지 않음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;선택 정렬의 핵심 이론: 최솟값 또는 최댓값을 찾고, 남은 정렬 부분의 가장 앞에 있는 데이터와 swap.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[1427번: 소트인사이드] / 실5&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예전에 계수 정렬(Counting Sort)로 푼 적 있는 문제였다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(입력 문자열(str)의 각 숫자 빈도를 numbers[10] 배열에 저장하고, 9부터 0까지 역순으로 출력하므로 내림차순 정렬)&lt;/p&gt;
&lt;pre id=&quot;code_1759748542469&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {
    public static void solution() throws Exception {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        int[] numbers = new int[10];

        for (int i = 0; i &amp;lt; str.length(); i++) {
            int n = str.charAt(i) - '0'; // 0~9
            numbers[n]++;
        }
        for (int i = 9; i &amp;gt;= 0; i--) {
            for (int j = 0; j &amp;lt; numbers[i]; j++) {
                System.out.print(i);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        solution();
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선택 정렬로 푼다면&lt;/p&gt;
&lt;pre id=&quot;code_1759748730402&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        int n = str.length();
        int[] A = new int[n];

        for (int i = 0; i &amp;lt; n; i++) {
            A[i] = str.charAt(i) - '0';
        }

        // 선택 정렬 (내림차순)
        for (int i = 0; i &amp;lt; n - 1; i++) {
            int maxIdx = i;
            for (int j = i + 1; j &amp;lt; n; j++) {
                if (A[j] &amp;gt; A[maxIdx]) {
                    maxIdx = j;
                }
            }
            // swap
            int tmp = A[i];
            A[i] = A[maxIdx];
            A[maxIdx] = tmp;
        }

        for (int num : A) {
            System.out.print(num);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;05-3. 삽입 정렬&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;span style=&quot;color: #ef5369;&quot;&gt;- 평균 시간 복잡도는 O(n^2)으로 느린 편,&lt;/span&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;span style=&quot;color: #006dd7;&quot;&gt; 이진 탐색&lt;/span&gt;을 사용하면 시간복잡도를 줄일 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[11399번: ATM] / 실4&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;c++로, 정렬 후 누적합을 구하는 방식으로 풀었었다.&lt;/p&gt;
&lt;pre id=&quot;code_1759748944234&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;
using namespace std;

int solution(int n, int times[]) {
    // 정렬
    sort(times, times + n);
    int sum = 0;
    int curr = 0;
    for (int i = 0; i &amp;lt; n; i++) {
        curr += times[i];
        sum += curr;
    }
    return sum;
}


int main()
{
    int n;
    int times[1000];
    cin &amp;gt;&amp;gt; n;
    for (int i = 0; i &amp;lt; n; i++) {
        cin &amp;gt;&amp;gt; times[i];
    }
    cout &amp;lt;&amp;lt; solution(n, times);
}&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;sort(times, times + n); 이 부분을 삽입 정렬 코드로 교체한다면 아래와 같이 된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1759749103136&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 삽입 정렬 (오름차순)
for (int i = 1; i &amp;lt; n; i++) {
    int key = times[i];
    int j = i - 1;
    while (j &amp;gt;= 0 &amp;amp;&amp;amp; times[j] &amp;gt; key) {
        times[j + 1] = times[j];
        j--;
    }
    times[j + 1] = key;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;05-4. 퀵 정렬&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;퀵 정렬: 기준값(pivot)을 선정해 해당 값보다 작은 데이터와 큰 데이터로 분류하는 것을 반복해 정렬하는 알고리즘.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기준값을 어떻게 선정하는지가 시간복잡도에 많은 영향을 미침. 평균적인 시간 복잡도는 O(nlogn).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;퀵 정렬의 핵심 이론: pivot을 중심으로 계속 데이터를 2개의 집합으로 나누면서 정렬한다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[11004번: K번째 수] / 실5&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난번에는 정렬을 직접 구현하지 않고 sort()를 사용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1759749418059&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] nk = br.readLine().split(&quot; &quot;);
        int n = Integer.parseInt(nk[0]);
        int k = Integer.parseInt(nk[1]);
        int[] arr = new int[n];
        String[] numbers = br.readLine().split(&quot; &quot;);
        for (int i = 0; i &amp;lt; n; i++) {
            arr[i] = Integer.parseInt(numbers[i]);
        }
        Arrays.sort(arr);
        System.out.println(arr[k-1]);
    }
}&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;/p&gt;
&lt;pre id=&quot;code_1759749861026&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] nk = br.readLine().split(&quot; &quot;);
        int n = Integer.parseInt(nk[0]);
        int k = Integer.parseInt(nk[1]);
        int[] arr = new int[n];
        String[] numbers = br.readLine().split(&quot; &quot;);
        for (int i = 0; i &amp;lt; n; i++) {
            arr[i] = Integer.parseInt(numbers[i]);
        }
        Arrays.sort(arr);
        System.out.println(arr[k-1]);
    }
    
    public static void quickSort(int[] A, int S, int E, int K){
        if (S&amp;lt;E) {
            int pivot=partition(A, S, E);
            
            if (pivot==K) {
                return;
            } else if (K&amp;lt;pivot) {
                quickSort(A, S, pivot-1, K);
            } else {
                quickSort(A, pivot+1, E, K);
            }
        }
    }
    
    public static int partition(int[] A, int S, int E){
        if(S+1==E){
            if(A[S]&amp;gt;A[E]) swap(A, S, E);
            return E;
        }
        int M = (S+E)/2;
        swap(A, S, M);
        int pivot=A[S];
        int i=S+1;
        int j=E;
        while (i&amp;lt;=j) {
            while (j&amp;gt;=S+1 &amp;amp;&amp;amp; pivot&amp;lt;A[j]) {
                j--;
            }
            while (i&amp;lt;=E &amp;amp;&amp;amp; pivot&amp;gt;A[i]) {
                i++;
            }
            if (i&amp;lt;=j) {
                swap(A, i++, j--);
            }
        }
        A[S]=A[j];
        A[j]=pivot;
        return j;
    }
    
    public static void swap(int[] A, int i, int j){
        int temp=A[i];
        A[i]=A[j];
        A[j]=temp;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;05-5. 병합 정렬&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병합 정렬: &lt;b&gt;분할 정복(divide and conquer)&lt;/b&gt; 방식을 사용해 (1) 데이터를 분할하고 (2) 분할한 집합을 정렬하며 합치는 알고리즘.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시간복잡도 평균값 O(nlogn).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병합 정렬의 핵심 이론: (1) 가장 작은 데이터 집합으로 분할 (2) 2개씩 그룹을 합치면서 오름차순 정렬 반복&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2개의 그룹을 병합하는 과정: 투 포인터 개념을 사용해 왼쪽, 오른쪽 그룹을 병합한다.&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;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style8&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[2751번: 수 정렬하기 2] / 실5&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예전에는 그냥 sort()로 했었는데 병합 정렬을 구현하면 다음과 같이 할 수 있다. (문제집 코드)&lt;/p&gt;
&lt;pre id=&quot;code_1759750294726&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Main {
  public static int[] A, tmp;
  public static long result;
  
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    int N = Integer.parseInt(br.readLine());
    A = new int[N + 1];
    tmp = new int[N + 1];
    for (int i = 1; i &amp;lt;= N; i++) {
      A[i] = Integer.parseInt(br.readLine());
    }
    mergeSort(1, N); // 병합정렬 수행하기
    for (int i = 1; i &amp;lt;= N; i++) {
      bw.write(A[i] + &quot;\n&quot;);
    }
    bw.flush();
    bw.close();
  }

  private static void mergeSort(int s, int e) {
    if (e - s &amp;lt; 1)
      return;
    int m = s + (e - s) / 2;
    // 재귀함수 형태로 구현
    mergeSort(s, m);
    mergeSort(m + 1, e);
    for (int i = s; i &amp;lt;= e; i++) {
      tmp[i] = A[i];
    }
    int k = s;
    int index1 = s;
    int index2 = m + 1;
    while (index1 &amp;lt;= m &amp;amp;&amp;amp; index2 &amp;lt;= e) { // 두 그룹을 Merge 해주는 로직
      if (tmp[index1] &amp;gt; tmp[index2]) {
        A[k] = tmp[index2];
        k++;
        index2++;
      } else {
        A[k] = tmp[index1];
        k++;
        index1++;
      }
    }
    // 한쪽 그룹이 모두 선택된 후 남아있는 값 정리하기
    while (index1 &amp;lt;= m) {
      A[k] = tmp[index1];
      k++;
      index1++;
    }
    while (index2 &amp;lt;= e) {
      A[k] = tmp[index2];
      k++;
      index2++;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;[1517번:&lt;span&gt;&amp;nbsp;&lt;/span&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;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;N개의 수로 이루어진 수열 A[1], A[2], &amp;hellip;, A[N]이 있다. 이 수열에 대해서 버블 소트를 수행할 때, Swap이 총 몇 번 발생하는지 알아내는 프로그램을 작성하시오.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&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;3&amp;nbsp;2&amp;nbsp;1&amp;nbsp;이었다고&amp;nbsp;하자.&amp;nbsp;이&amp;nbsp;경우에는&amp;nbsp;인접해&amp;nbsp;있는&amp;nbsp;3,&amp;nbsp;2가&amp;nbsp;바뀌어야&amp;nbsp;하므로&amp;nbsp;2&amp;nbsp;3&amp;nbsp;1&amp;nbsp;이&amp;nbsp;된다.&amp;nbsp;다음으로는&amp;nbsp;3,&amp;nbsp;1이&amp;nbsp;바뀌어야&amp;nbsp;하므로&amp;nbsp;2&amp;nbsp;1&amp;nbsp;3&amp;nbsp;이&amp;nbsp;된다.&amp;nbsp;다음에는&amp;nbsp;2,&amp;nbsp;1이&amp;nbsp;바뀌어야&amp;nbsp;하므로&amp;nbsp;1&amp;nbsp;2&amp;nbsp;3&amp;nbsp;이&amp;nbsp;된다.&amp;nbsp;그러면&amp;nbsp;더&amp;nbsp;이상&amp;nbsp;바꿔야&amp;nbsp;할&amp;nbsp;경우가&amp;nbsp;없으므로&amp;nbsp;정렬이&amp;nbsp;완료된다.&lt;/span&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;아까 문제와 마찬가지로, 제목이 버블 정렬이지만 버블 정렬로 풀면 시간 초과가 나는 문제. (N 최대 범위 500,000 -&amp;gt; O(nlogn) 필요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병합 정렬을 이용해야 한다. 두 그룹을 병합하는 과정에 버블 정렬의 swap이 쓰인다.&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;마지막 병합 전의 데이터 [ 24 32 42 60 ] [ 5 15 45 90 ] 를 생각하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 정렬된 데이터는 [ 5 15 24 32 42 45 60 90 ].&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5는 앞 그룹의 4개 데이터를 제치므로 버블 정렬에서 swap을 4번 하는 것과 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;45는 앞 그룹의 1개 데이터를 제치므로 버블 정렬에서 swap을 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;병합 정렬을 동일하게 진행하는데, 정렬 과정에서 index가 이동한 거리를 result에 저장하자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각 그룹을 정렬하는 과정에서 원소가 앞으로 이동한 거리만큼 result에 더하기.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759751943236&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    static int[] A, tmp;
    static long result;
  
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        A = new int[n+1];
        tmp = new int[n+1];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i=1; i&amp;lt;=n; i++) {
            A[i] = Integer.parseInt(st.nextToken());
        }
        result = 0;
        mergeSort(1, n);
        System.out.println(result);
    }
    
    private static void mergeSort(int s, int e) { 
        if (e-s &amp;lt; 1)
            return;
        int m = s + (e-s)/2;
        //재귀함수 (왼쪽, 오른쪽)
        mergeSort(s, m); 
        mergeSort(m+1, e);
        
        for (int i=s; i&amp;lt;=e; i++) {
            tmp[i] = A[i];
        }
        int k = s; // 병합 결과를 A에 저장하기위한 위치 인덱스
        int index1 = s; // 왼쪽 그룹의 현재 원소 위치
        int index2 = m + 1; // 오른쪽 그룹의 현재 원소 위치
        // 병합 로직 (작은 값을 A[k]에 넣으며 병합)
        while (index1 &amp;lt;= m &amp;amp;&amp;amp; index2 &amp;lt;= e) {
            if (tmp[index1] &amp;gt; tmp[index2]) { // 뒤쪽 데이터 값이 작다면 역전 발생
                A[k] = tmp[index2];
                result += (index2 - k); // 오른쪽 원소가 왼쪽 원소 몇 개를 앞질렀는지
                k++;
                index2++;
            } else {
                A[k] = tmp[index1];
                k++;
                index1++;
            }
        }
        // 두 부분 중 한 쪽이 먼저 소진되었을 때, 남은 원소 병합
        while (index1 &amp;lt;= m) {
            A[k] = tmp[index1];
            k++;
            index1++;
        }
        while (index2 &amp;lt;= e) {
            A[k] = tmp[index2];
            k++;
            index2++;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;05-6. 기수 정렬&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;- 시간복잡도: O(kn). // k: 자릿수. 시간복잡도가 가장 짧은 정렬임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기수 정렬의 핵심 이론: 10개의 큐를 이용. 각 큐는 값의 자릿수를 대표함.&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 data-ke-size=&quot;size16&quot;&gt;원본 배열: 16 80 18 77 03 24 88 23&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 일의 자릿수 기준으로 배열 원소를 큐에 집어넣는다. 그런 다음 0번째 큐부터 9번째 큐까지 pop을 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 결과: 90 03 23 24 16 77 18 88&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) 마지막 자릿수를 기준으로 정렬할 때까지 앞의 과정을 반복.&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 contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[10989번: 수 정렬하기 3] / 브1&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이전에는 계수 정렬로 풀었었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기수 정렬로는 다음과 같이 풀이할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1759752584122&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Main {
    static int[] A;
    static long result;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int N = Integer.parseInt(br.readLine());
        A = new int[N];
        for (int i = 0; i &amp;lt; N; i++) {
            A[i] = Integer.parseInt(br.readLine());
        }
        br.close();
        radixSort(A, 5); //수의 범위가 &amp;lt;=10000
        for (int i = 0; i &amp;lt; N; i++) {
            bw.write(A[i] + &quot;\n&quot;);
        }
        bw.flush();
        bw.close();
    }

    private static void radixSort(int[] A, int maxSize) {
        int[] output = new int[A.length];
        int digit = 1;
        int count = 0;
        while (count != maxSize) { // 최대 자리수 만큼 반복
            int[] bucket = new int[10];
            for (int i = 0; i &amp;lt; A.length; i++) {
                bucket[(A[i] / digit) % 10]++; // 일의 자리 부터 시작
            }
            for (int i = 1; i &amp;lt; 10; i++) { // 합배열을 이용하여 index 계산
                bucket[i] += bucket[i - 1];
            }
            for (int i = A.length - 1; i &amp;gt;= 0; i--) { // 현재 자리수 기준으로 정렬
                output[bucket[(A[i] / digit % 10)] - 1] = A[i];
                bucket[(A[i] / digit) % 10]--;
            }
            for (int i = 0; i &amp;lt; A.length; i++) {
                A[i] = output[i]; // 다음 자리 수 이동을 위해 현재 자리수 기준 정렬 데이터 저장
            }
            digit *= 10; // 자리수 증가
            count++;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;bucket 배열로 현재 자리를 기준으로 정렬하는 방식 잘 확인하기.&lt;/p&gt;</description>
      <category>Study/PS</category>
      <author>Hyun_!</author>
      <guid isPermaLink="true">https://hereishyun.tistory.com/262</guid>
      <comments>https://hereishyun.tistory.com/262#entry262comment</comments>
      <pubDate>Mon, 6 Oct 2025 21:12:15 +0900</pubDate>
    </item>
  </channel>
</rss>