<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>쉽게 쉽게</title>
    <link>https://minsu092274.tistory.com/</link>
    <description>개발자로 경험하면서 겪은 일과 지식을 쉽게 쉽게 써보려고 한다.</description>
    <language>ko</language>
    <pubDate>Sun, 19 Jul 2026 02:39:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>곱마2</managingEditor>
    <item>
      <title>[알고리즘] DFS(깊이 우선 탐색)란? (백준 11724, 2667)</title>
      <link>https://minsu092274.tistory.com/203</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ================================================
    [알고리즘] DFS(깊이 우선 탐색)란? (백준 11724, 2667)
    ================================================ --&gt;&lt;/p&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;&lt;!-- ================================================
    ★ 서식 00 : 전체 CSS (마스터)
    CSS가 날아갔을 때 글 최상단에 이 서식 하나만 삽입하세요.
    ※ 스크립트는 스킨편집 &gt; script.js 에 별도 등록하세요.
       (티스토리가 서식 내 &lt;script&gt; 태그를 자동 삭제합니다)
    ================================================ --&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;500;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue{background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green{background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber{background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red{background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray{background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b !important;box-shadow:0 4px 20px rgba(15,23,42,0.18);}.code-header{background:#1e293b !important;padding:9px 18px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;align-items:center;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:12px;color:#94a3b8 !important;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;font-weight:500;}pre.code-body{background:#0d1117 !important;padding:1.5rem 1.75rem !important;margin:0 !important;overflow-x:auto;font-family:'JetBrains Mono',monospace !important;font-size:14px !important;font-weight:500 !important;line-height:1.9 !important;color:#e2e8f0 !important;border:none !important;border-radius:0 !important;}.code-body *{font-family:'JetBrains Mono',monospace !important;font-size:14px !important;font-weight:500 !important;line-height:1.9 !important;background:transparent !important;border:none !important;padding:0 !important;}.c-blue  {color:#7dd3fc !important;}.c-green {color:#86efac !important;}.c-lime  {color:#bef264 !important;}.c-teal  {color:#5eead4 !important;}.c-purple{color:#e879f9 !important;}.c-cyan  {color:#67e8f9 !important;}.c-yellow{color:#fef08a !important;}.c-gray  {color:#94a3b8 !important;font-style:italic;}.c-base  {color:#e2e8f0 !important;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box{background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box{background:#fffbeb;border:1px solid #fde68a;}.info-box{background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box .box-title{color:#047857;}.tip-box .box-body{color:#065f46;}.warn-box .box-title{color:#b45309;}.warn-box .box-body{color:#92400e;}.info-box .box-title{color:#2563eb;}.info-box .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red{display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue{display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DFS(깊이 우선 탐색)&lt;/b&gt;는 한 방향으로 &lt;b&gt;갈 수 있는 만큼 끝까지 파고든 뒤&lt;/b&gt;, 막히면 되돌아와 다른 길을 탐색하는 알고리즘입니다.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;되돌아오기&amp;rdquo;를 구현하기 위해 &lt;b&gt;스택(Stack)&lt;/b&gt; 또는 &lt;b&gt;재귀 호출&lt;/b&gt;을 사용하며, 실전에서는 재귀 방식이 훨씬 간결합니다.&lt;/li&gt;
&lt;li&gt;최단 거리는 보장하지 않지만, &lt;b&gt;연결 요소 찾기 &amp;middot; 모든 경로 탐색 &amp;middot; 백트래킹&lt;/b&gt;의 기반이 되는 필수 알고리즘입니다.&lt;/li&gt;
&lt;li&gt;백준 &lt;b&gt;11724(연결 요소의 개수)&lt;/b&gt;, &lt;b&gt;2667(단지번호붙이기)&lt;/b&gt; 두 문제로 그래프 DFS와 2차원 격자 DFS를 직접 풀어봅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ==================================================== 목차 ==================================================== --&gt;&lt;/p&gt;
&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; DFS(깊이 우선 탐색)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DFS(Depth-First Search, 깊이 우선 탐색)&lt;/b&gt;는 그래프나 트리에서 &lt;b&gt;한 방향으로 갈 수 있는 만큼 깊이 파고들며&lt;/b&gt; 탐색하는 알고리즘입니다. 미로에서 길을 찾는 사람을 떠올리면 됩니다. 갈림길이 나오면 일단 한쪽 길을 선택해 &lt;b&gt;막다른 곳이 나올 때까지&lt;/b&gt; 걸어가고, 막히면 &lt;b&gt;마지막 갈림길로 되돌아와서&lt;/b&gt; 아직 가보지 않은 다른 길을 시도합니다. 이 과정을 반복하면 결국 미로의 모든 길을 한 번씩 밟게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS가 &amp;ldquo;가까운 곳부터 한 겹씩&amp;rdquo; 넓게 퍼져나갔다면, DFS는 &amp;ldquo;일단 한 길로 끝까지&amp;rdquo; 깊게 들어간다는 점이 정반대입니다.&lt;/p&gt;
&lt;h3 id=&quot;section1-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;스택(Stack)이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스택(Stack)&lt;/b&gt;은 &lt;b&gt;나중에 넣은 데이터가 먼저 나오는(LIFO, Last-In First-Out)&lt;/b&gt; 자료구조입니다. 접시를 쌓아둔 더미처럼, 꺼낼 때는 항상 &lt;b&gt;맨 위(가장 최근에 올린 접시)&lt;/b&gt;부터 꺼냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS에 스택이 필요한 이유는 &lt;b&gt;&amp;ldquo;가장 최근에 지나온 갈림길&amp;rdquo;로 되돌아가야 하기 때문&lt;/b&gt;입니다. 지나온 갈림길을 스택에 차곡차곡 쌓아두면, 막다른 길을 만났을 때 스택의 맨 위를 꺼내는 것만으로 가장 최근 갈림길로 돌아갈 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS가 &amp;ldquo;먼저 발견한 것 먼저&amp;rdquo;를 위해 큐를 썼다면, DFS는 &amp;ldquo;가장 최근 것부터 되짚기&amp;rdquo;를 위해 스택을 씁니다.&lt;/p&gt;
&lt;h3 id=&quot;section1-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;왜 재귀 호출로 구현할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재귀 호출(Recursion)&lt;/b&gt;은 메서드가 자기 자신을 다시 호출하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 사실 자바는 메서드를 호출할 때마다 호출 정보를 &lt;b&gt;콜 스택(Call Stack)&lt;/b&gt;이라는 내부 스택에 자동으로 쌓고, 메서드가 끝나면 꺼내서 이전 위치로 돌아갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 재귀 호출을 쓰면 &lt;b&gt;&amp;ldquo;되돌아오기&amp;rdquo;에 필요한 스택 관리를 자바가 대신 해주는&lt;/b&gt; 셈입니다. 그래서 실전에서는 스택을 직접 다루는 코드보다 재귀 방식이 훨씬 짧고 직관적이라 대부분 재귀로 DFS를 구현합니다.&lt;/p&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;큐를 쓰면 BFS, 스택(재귀)을 쓰면 DFS&lt;/div&gt;
두 알고리즘의 코드 구조는 거의 같습니다. &amp;ldquo;다음에 방문할 노드&amp;rdquo;를 &lt;b&gt;큐&lt;/b&gt;로 관리하면 BFS, &lt;b&gt;스택(또는 재귀)&lt;/b&gt;으로 관리하면 DFS가 됩니다. 자료구조 하나의 차이가 탐색 순서 전체를 바꾼다는 점이 두 알고리즘의 핵심입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; DFS의 동작 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀 기준으로 DFS의 전체 흐름은 아래 4단계입니다. &amp;ldquo;방문 &amp;rarr; 더 깊이 &amp;rarr; 막히면 복귀&amp;rdquo;의 반복이라고 기억하면 됩니다.&lt;/p&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;div class=&quot;prob-sub&quot;&gt;DFS 동작 4단계 (재귀 기준)&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;시작 노드에서 &lt;b&gt;dfs 메서드를 호출&lt;/b&gt;하고, 진입하자마자 방문 처리(visited = true)합니다.&lt;/li&gt;
&lt;li&gt;현재 노드와 연결된 인접 노드를 확인해, &lt;b&gt;아직 방문하지 않은 노드가 있으면 그 노드로 dfs를 재귀 호출&lt;/b&gt;합니다. (더 깊이 파고들기)&lt;/li&gt;
&lt;li&gt;인접 노드를 전부 방문했다면(막다른 길) 메서드가 종료되고, &lt;b&gt;자동으로 이전 노드로 되돌아갑니다.&lt;/b&gt; (백트래킹)&lt;/li&gt;
&lt;li&gt;되돌아온 노드에서 &lt;b&gt;남은 다른 인접 노드&lt;/b&gt;에 대해 2~3번을 반복합니다. 최초 호출까지 종료되면 시작점에서 도달 가능한 모든 노드를 방문한 것입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;방문 처리를 빠뜨리면 무한 재귀에 빠집니다&lt;/div&gt;
그래프에 사이클(순환 경로)이 있을 때 방문 처리를 하지 않으면, 두 노드가 서로를 계속 재귀 호출하다가 &lt;b&gt;StackOverflowError&lt;/b&gt;(콜 스택이 가득 차서 발생하는 에러)로 프로그램이 죽습니다. dfs 메서드에 &lt;b&gt;진입하자마자 방문 처리&lt;/b&gt;하는 것을 습관으로 만드세요.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; DFS vs BFS 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 알고리즘 모두 모든 노드를 한 번씩 방문하므로 시간 복잡도는 O(V + E)로 같습니다. (V = 노드 수, E = 간선 수) 어떤 문제에서 어느 쪽을 골라야 하는지가 실전의 핵심입니다.&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;DFS (깊이 우선 탐색)&lt;/th&gt;
&lt;th&gt;BFS (너비 우선 탐색)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;탐색 방식&lt;/b&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;b&gt;사용 자료구조&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;스택 (Stack) 또는 재귀&lt;/td&gt;
&lt;td&gt;큐 (Queue)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;최단 거리 보장&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-red&quot;&gt;보장 안 됨&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;보장 (가중치 없을 때)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구현 난이도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;재귀로 매우 간결&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-blue&quot;&gt;큐 관리 코드 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;주의할 점&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-amber&quot;&gt;깊은 재귀 시 스택 오버플로우&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-amber&quot;&gt;큐 중복 삽입 시 메모리 초과&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;유리한 문제&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;연결 요소, 모든 경로 탐색, 백트래킹, 사이클 판별&lt;/td&gt;
&lt;td&gt;최단 거리, 최소 횟수, 가까운 대상 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;&amp;ldquo;몇 개인가 / 모든 경우&amp;rdquo;는 DFS, &amp;ldquo;최단 &amp;middot; 최소&amp;rdquo;는 BFS&lt;/div&gt;
연결된 덩어리가 몇 개인지 세거나, 가능한 모든 경우를 탐색하는 문제는 구현이 간결한 DFS가 편합니다. 반면 &amp;ldquo;최단 거리&amp;rdquo;, &amp;ldquo;최소 횟수&amp;rdquo;가 등장하면 BFS를 선택하세요. 단순히 &lt;b&gt;모든 노드를 방문하기만 하면 되는 문제&lt;/b&gt;(연결 요소 등)는 둘 중 아무거나 써도 정답이 같습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; Java로 DFS 구현하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프는 BFS 때와 마찬가지로 &lt;b&gt;인접 리스트&lt;/b&gt;(각 노드마다 &amp;ldquo;연결된 노드 목록&amp;rdquo;을 저장하는 방식)로 표현합니다. 먼저 가장 많이 쓰는 &lt;b&gt;재귀 버전&lt;/b&gt;입니다. 큐 관리 코드가 없어서 BFS보다 훨씬 짧다는 점을 확인해 보세요.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; DFS 기본 템플릿 (재귀)&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body gradle&quot;&gt;&lt;code&gt;import java.util.*;

public class DfsTemplate {

    // graph[i] = i번 노드와 연결된 노드 목록 (인접 리스트)
    static List&amp;lt;Integer&amp;gt;[] graph;
    static boolean[] visited;

    static void dfs(int cur) {
        // 1. 진입하자마자 방문 처리 (무한 재귀 방지!)
        visited[cur] = true;
        System.out.println(&quot;방문: &quot; + cur);

        // 2. 미방문 인접 노드로 더 깊이 파고든다
        for (int next : graph[cur]) {
            if (!visited[next]) {
                dfs(next);
            }
        }
        // 3. for문이 끝나면(막다른 길) 자동으로 이전 노드로 복귀
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 동작을 &lt;b&gt;스택으로 직접&lt;/b&gt; 구현하면 아래와 같습니다. 재귀가 내부적으로 어떤 일을 하는지 이해하는 데 도움이 되고, 재귀 깊이 제한에 걸릴 만큼 그래프가 깊을 때의 대안이 되기도 합니다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; DFS 스택 버전 (참고용)&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;static void dfsWithStack(int start) {
    Deque&amp;lt;Integer&amp;gt; stack = new ArrayDeque&amp;lt;&amp;gt;();
    stack.push(start);

    while (!stack.isEmpty()) {
        int cur = stack.pop(); // 맨 위(가장 최근)부터 꺼낸다
        if (visited[cur]) continue;
        visited[cur] = true;
        System.out.println(&quot;방문: &quot; + cur);

        for (int next : graph[cur]) {
            if (!visited[next]) stack.push(next);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;자바에서 스택은 ArrayDeque를 권장합니다&lt;/div&gt;
자바에는 &lt;code&gt;Stack&lt;/code&gt; 클래스가 있지만 오래된 설계(모든 메서드에 동기화 처리)로 성능이 떨어져, 공식 문서에서도 &lt;code&gt;Deque&lt;/code&gt; 인터페이스와 &lt;code&gt;ArrayDeque&lt;/code&gt; 구현체 사용을 권장합니다. &lt;code&gt;push()&lt;/code&gt;로 맨 위에 넣고 &lt;code&gt;pop()&lt;/code&gt;으로 맨 위에서 꺼냅니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section5&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;5&lt;/span&gt; 문제풀이 1 : 백준 11724 연결 요소의 개수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 문제는 DFS 입문의 정석인 &lt;b&gt;연결 요소의 개수&lt;/b&gt;입니다. &lt;b&gt;연결 요소(Connected Component)&lt;/b&gt;란 그래프 안에서 서로 오갈 수 있는 노드들의 덩어리를 말합니다. 이 문제의 핵심은 &amp;ldquo;&lt;b&gt;모든 노드에 대해 DFS 시도 &amp;rarr; 새로 탐색이 시작된 횟수 = 덩어리 수&lt;/b&gt;&amp;rdquo;라는 패턴입니다.&lt;/p&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;BOJ #11724&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;연결 요소의 개수&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;N &amp;le; 1,000 &amp;middot; M &amp;le; N&amp;times;(N-1)/2 &amp;middot; 시간제한 3초&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-silver&quot;&gt;Silver V&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방향 없는 그래프가 주어졌을 때, &lt;b&gt;연결 요소(서로 연결된 노드 덩어리)의 개수&lt;/b&gt;를 출력하는 문제입니다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;간선이 양방향이므로 &lt;b&gt;인접 리스트에 양쪽 모두&lt;/b&gt; 간선을 추가해 그래프를 만든다.&lt;/li&gt;
&lt;li&gt;1번부터 N번까지 &lt;b&gt;모든 노드를 순회&lt;/b&gt;하면서, 아직 방문하지 않은 노드를 만나면 그 노드에서 DFS를 시작한다.&lt;/li&gt;
&lt;li&gt;DFS 한 번이 끝나면 연결된 덩어리 하나를 전부 방문한 것이므로, &lt;b&gt;DFS를 새로 시작한 횟수&lt;/b&gt;가 곧 연결 요소의 개수다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 백준 11724 연결 요소의 개수&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body reasonml&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    static List&amp;lt;Integer&amp;gt;[] graph;
    static boolean[] visited;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken()); // 노드 수
        int m = Integer.parseInt(st.nextToken()); // 간선 수

        graph = new ArrayList[n + 1];
        visited = new boolean[n + 1];
        for (int i = 1; i &amp;lt;= n; i++) graph[i] = new ArrayList&amp;lt;&amp;gt;();

        // 양방향 간선 등록
        for (int i = 0; i &amp;lt; m; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            graph[a].add(b);
            graph[b].add(a);
        }

        // 모든 노드를 순회하며, 미방문 노드에서 DFS 시작
        int count = 0;
        for (int i = 1; i &amp;lt;= n; i++) {
            if (!visited[i]) {
                dfs(i);
                count++; // 새 덩어리 발견!
            }
        }

        System.out.println(count);
    }

    static void dfs(int cur) {
        visited[cur] = true;
        for (int next : graph[cur]) {
            if (!visited[next]) dfs(next);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;&amp;ldquo;모든 노드 순회 + 미방문 시 DFS&amp;rdquo; 패턴을 기억하세요&lt;/div&gt;
BFS의 바이러스(2606)는 시작점 하나에서 탐색했지만, 이 문제처럼 &lt;b&gt;그래프가 여러 덩어리로 나뉘어 있을 수 있는 경우&lt;/b&gt;에는 모든 노드를 for문으로 순회하며 미방문 노드마다 새로 탐색을 시작해야 합니다. 다음 문제인 단지번호붙이기도 똑같은 패턴입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section6&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;6&lt;/span&gt; 문제풀이 2 : 백준 2667 단지번호붙이기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 문제는 2차원 격자 DFS의 대표 문제인 &lt;b&gt;단지번호붙이기&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 배운 &amp;ldquo;모든 노드 순회 + 미방문 시 DFS&amp;rdquo; 패턴을 격자에 적용하고, 추가로 &lt;b&gt;DFS의 반환값으로 덩어리의 크기를 누적&lt;/b&gt;하는 기법을 배웁니다. 격자에서 상하좌우 이동은 BFS 때와 동일하게 &lt;b&gt;방향 배열(dx, dy)&lt;/b&gt;을 사용합니다.&lt;/p&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;BOJ #2667&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;단지번호붙이기&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;지도 크기 N &amp;le; 25 &amp;middot; 시간제한 1초&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-silver&quot;&gt;Silver I&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N&amp;times;N 지도에서 1은 집, 0은 빈 땅입니다. 상하좌우로 붙어 있는 집들을 하나의 &lt;b&gt;단지&lt;/b&gt;로 묶을 때, &lt;b&gt;총 단지 수&lt;/b&gt;와 &lt;b&gt;각 단지의 집 수를 오름차순으로&lt;/b&gt; 출력하는 문제입니다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;지도의 모든 칸을 이중 for문으로 순회하다가, &lt;b&gt;집(1)이면서 미방문인 칸&lt;/b&gt;을 만나면 그 칸에서 DFS를 시작한다. (= 새 단지 발견)&lt;/li&gt;
&lt;li&gt;DFS는 현재 칸을 방문 처리한 뒤, 상하좌우의 &lt;b&gt;범위 안 &amp;middot; 집 &amp;middot; 미방문&lt;/b&gt; 칸으로 재귀를 이어간다.&lt;/li&gt;
&lt;li&gt;DFS가 &lt;b&gt;&amp;ldquo;자기 자신 1채 + 재귀로 이어진 집들의 수&amp;rdquo;를 반환&lt;/b&gt;하도록 만들면, 최초 호출의 반환값이 곧 그 단지의 집 수가 된다.&lt;/li&gt;
&lt;li&gt;단지별 집 수를 리스트에 모아 &lt;b&gt;오름차순 정렬&lt;/b&gt; 후, 단지 수와 함께 출력한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 백준 2667 단지번호붙이기&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body processing&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    // 상, 하, 좌, 우 네 방향
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};
    static int n;
    static int[][] map;
    static boolean[][] visited;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine().trim());
        map = new int[n][n];
        visited = new boolean[n][n];

        for (int i = 0; i &amp;lt; n; i++) {
            String line = br.readLine();
            for (int j = 0; j &amp;lt; n; j++) {
                map[i][j] = line.charAt(j) - '0';
            }
        }

        // 모든 칸 순회 : 집(1)이면서 미방문이면 새 단지
        List&amp;lt;Integer&amp;gt; sizes = new ArrayList&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; n; i++) {
            for (int j = 0; j &amp;lt; n; j++) {
                if (map[i][j] == 1 &amp;amp;&amp;amp; !visited[i][j]) {
                    sizes.add(dfs(i, j)); // 단지 하나 통째로 탐색
                }
            }
        }

        // 오름차순 정렬 후 출력
        Collections.sort(sizes);
        StringBuilder sb = new StringBuilder();
        sb.append(sizes.size()).append('\n');
        for (int s : sizes) sb.append(s).append('\n');
        System.out.print(sb);
    }

    // 반환값 = 이 칸에서 이어진 단지의 집 수
    static int dfs(int x, int y) {
        visited[x][y] = true;
        int size = 1; // 자기 자신 1채

        for (int d = 0; d &amp;lt; 4; d++) {
            int nx = x + dx[d];
            int ny = y + dy[d];

            // 지도 범위 밖이면 건너뛰기
            if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= n || ny &amp;gt;= n) continue;
            // 빈 땅(0)이거나 이미 방문한 칸이면 건너뛰기
            if (map[nx][ny] == 0 || visited[nx][ny]) continue;

            size += dfs(nx, ny); // 이어진 집 수를 누적
        }
        return size;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;재귀 DFS는 격자가 크면 StackOverflowError가 날 수 있습니다&lt;/div&gt;
이 문제는 지도가 최대 25&amp;times;25 = 625칸이라 재귀 깊이가 얕아 안전합니다. 하지만 격자가 수백&amp;times;수백처럼 커지면 재귀 깊이가 수만~수십만까지 깊어져 콜 스택이 넘칠 수 있습니다. 그럴 때는 &lt;b&gt;스택 버전 DFS로 바꾸거나 BFS로 대체&lt;/b&gt;하는 것이 안전합니다. 이 판단 기준을 알아두면 실전에서 큰 도움이 됩니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section7&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;7&lt;/span&gt; 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS의 핵심을 다시 정리하면 세 가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한 길로 끝까지 파고들고, 막히면 되돌아온다&lt;/b&gt;, &lt;b&gt;재귀 호출이 콜 스택을 통해 &amp;ldquo;되돌아오기&amp;rdquo;를 자동으로 처리해 준다&lt;/b&gt;, &lt;b&gt;dfs 진입 즉시 방문 처리한다&lt;/b&gt;.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/DFS (깊이 우선 탐색)</category>
      <category>DFS</category>
      <category>java</category>
      <category>깊이 우선 탐색</category>
      <category>단지번호붙이기</category>
      <category>백준 11724</category>
      <category>백준 2667</category>
      <category>알고리즘</category>
      <category>연결 요소</category>
      <category>자바 DFS</category>
      <category>재귀</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/203</guid>
      <comments>https://minsu092274.tistory.com/203#entry203comment</comments>
      <pubDate>Sat, 18 Jul 2026 18:58:35 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] BFS(너비 우선 탐색)란 무엇인가? (백준 2606, 2178)</title>
      <link>https://minsu092274.tistory.com/202</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ================================================
    [알고리즘] BFS(너비 우선 탐색)란? (백준 2606, 2178)
    ================================================ --&gt;&lt;/p&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;&lt;!-- ================================================
    ★ 서식 00 : 전체 CSS (마스터)
    CSS가 날아갔을 때 글 최상단에 이 서식 하나만 삽입하세요.
    ※ 스크립트는 스킨편집 &gt; script.js 에 별도 등록하세요.
       (티스토리가 서식 내 &lt;script&gt; 태그를 자동 삭제합니다)
    ================================================ --&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;500;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue{background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green{background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber{background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red{background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray{background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b !important;box-shadow:0 4px 20px rgba(15,23,42,0.18);}.code-header{background:#1e293b !important;padding:9px 18px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;align-items:center;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:12px;color:#94a3b8 !important;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;font-weight:500;}pre.code-body{background:#0d1117 !important;padding:1.5rem 1.75rem !important;margin:0 !important;overflow-x:auto;font-family:'JetBrains Mono',monospace !important;font-size:14px !important;font-weight:500 !important;line-height:1.9 !important;color:#e2e8f0 !important;border:none !important;border-radius:0 !important;}.code-body *{font-family:'JetBrains Mono',monospace !important;font-size:14px !important;font-weight:500 !important;line-height:1.9 !important;background:transparent !important;border:none !important;padding:0 !important;}.c-blue  {color:#7dd3fc !important;}.c-green {color:#86efac !important;}.c-lime  {color:#bef264 !important;}.c-teal  {color:#5eead4 !important;}.c-purple{color:#e879f9 !important;}.c-cyan  {color:#67e8f9 !important;}.c-yellow{color:#fef08a !important;}.c-gray  {color:#94a3b8 !important;font-style:italic;}.c-base  {color:#e2e8f0 !important;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box{background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box{background:#fffbeb;border:1px solid #fde68a;}.info-box{background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box .box-title{color:#047857;}.tip-box .box-body{color:#065f46;}.warn-box .box-title{color:#b45309;}.warn-box .box-body{color:#92400e;}.info-box .box-title{color:#2563eb;}.info-box .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red{display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue{display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BFS(너비 우선 탐색)&lt;/b&gt;는 시작점에서 &lt;b&gt;가까운 곳부터 차례대로&lt;/b&gt; 퍼져나가며 탐색하는 알고리즘입니다.&lt;/li&gt;
&lt;li&gt;탐색 순서를 관리하기 위해 &lt;b&gt;큐(Queue)&lt;/b&gt; 자료구조를 사용하며, 먼저 발견한 노드를 먼저 방문합니다.&lt;/li&gt;
&lt;li&gt;모든 간선의 비용이 같을 때(가중치가 없을 때) &lt;b&gt;최단 거리를 보장&lt;/b&gt;하는 것이 BFS의 가장 큰 강점입니다.&lt;/li&gt;
&lt;li&gt;백준 &lt;b&gt;2606(바이러스)&lt;/b&gt;, &lt;b&gt;2178(미로 탐색)&lt;/b&gt; 두 문제로 연결 요소 탐색과 최단 거리 계산을 직접 풀어봅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ==================================================== 목차 ==================================================== --&gt;&lt;/p&gt;
&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; BFS(너비 우선 탐색)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BFS(Breadth-First Search, 너비 우선 탐색)&lt;/b&gt;는 그래프나 트리에서 &lt;b&gt;시작점과 가까운 노드부터 차례대로&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;시작점에서 거리 1인 노드를 모두 방문한 뒤, 거리 2인 노드, 거리 3인 노드&amp;hellip; 순서로 &lt;b&gt;한 겹씩(너비 단위로)&lt;/b&gt; 탐색 범위를 넓혀갑니다.&lt;/p&gt;
&lt;h3 id=&quot;section1-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;그래프란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS를 이해하려면 먼저 그래프가 무엇인지 알아야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래프(Graph)&lt;/b&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;지하철 노선도를 생각하면 쉽습니다. 각 역이 노드, 역과 역을 잇는 선로가 간선입니다. 컴퓨터 네트워크, SNS 친구 관계, 미로의 길 등 &amp;ldquo;무언가와 무언가가 연결된 구조&amp;rdquo;는 대부분 그래프로 표현할 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;section1-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;왜 큐(Queue)를 사용할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;큐(Queue)&lt;/b&gt;는 &lt;b&gt;먼저 넣은 데이터가 먼저 나오는(FIFO, First-In First-Out)&lt;/b&gt; 자료구조입니다. 은행 창구의 대기줄처럼, 먼저 줄을 선 사람이 먼저 처리됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS가 큐를 사용하는 이유는 &lt;b&gt;&amp;ldquo;먼저 발견한 노드를 먼저 방문해야&amp;rdquo;&lt;/b&gt; 가까운 순서대로 탐색이 진행되기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작점에서 거리 1인 노드들을 큐에 넣으면, 그 노드들을 꺼내 처리하는 동안 거리 2인 노드들이 큐의 뒤에 쌓입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐는 항상 앞에서부터 꺼내므로 거리 1이 모두 끝난 뒤에야 거리 2가 처리됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 성질 덕분에 BFS는 자연스럽게 &lt;b&gt;가까운 순서대로 탐색&lt;/b&gt;하게 되고, 가중치가 없는 그래프에서 &lt;b&gt;최단 거리를 보장&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;스택을 쓰면 DFS가 됩니다&lt;/div&gt;
같은 코드에서 큐 대신 스택(나중에 넣은 것이 먼저 나오는 구조)을 쓰면, 한 방향으로 끝까지 파고드는 &lt;b&gt;DFS(깊이 우선 탐색)&lt;/b&gt;가 됩니다. 즉 &lt;b&gt;어떤 자료구조로 &amp;ldquo;다음에 방문할 노드&amp;rdquo;를 관리하느냐&lt;/b&gt;가 BFS와 DFS를 가르는 핵심입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; BFS의 동작 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS는 큐와 방문 체크 배열(visited) 두 가지만 있으면 동작합니다. 전체 흐름은 아래 4단계의 반복입니다.&lt;/p&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;div class=&quot;prob-sub&quot;&gt;BFS 동작 4단계&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;시작 노드를 큐에 넣고&lt;/b&gt;, 방문 처리(visited = true)합니다.&lt;/li&gt;
&lt;li&gt;큐에서 노드를 하나 &lt;b&gt;꺼냅니다(poll)&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;꺼낸 노드와 연결된 &lt;b&gt;인접 노드 중 아직 방문하지 않은 노드&lt;/b&gt;를 모두 큐에 넣고, 넣는 순간 방문 처리합니다.&lt;/li&gt;
&lt;li&gt;큐가 &lt;b&gt;빌 때까지&lt;/b&gt; 2~3번을 반복합니다. 큐가 비면 시작점에서 도달 가능한 모든 노드를 방문한 것입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;방문 처리는 &amp;ldquo;큐에 넣을 때&amp;rdquo; 해야 합니다&lt;/div&gt;
큐에서 &lt;b&gt;꺼낼 때&lt;/b&gt; 방문 처리를 하면, 같은 노드가 여러 경로를 통해 큐에 &lt;b&gt;중복으로 들어가는&lt;/b&gt; 문제가 생깁니다. 노드 수가 많은 문제에서는 이 중복 때문에 메모리 초과나 시간 초과가 발생할 수 있으니, 반드시 &lt;b&gt;큐에 넣는 순간&lt;/b&gt; 방문 처리하는 습관을 들이세요.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; BFS vs DFS 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS와 DFS는 모두 그래프의 모든 노드를 한 번씩 방문하는 완전 탐색 알고리즘이라 시간 복잡도는 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;탐색 순서&lt;/b&gt;가 다르기 때문에 문제 유형에 따라 유리한 쪽이 달라집니다.&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;BFS (너비 우선 탐색)&lt;/th&gt;
&lt;th&gt;DFS (깊이 우선 탐색)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;탐색 방식&lt;/b&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;b&gt;사용 자료구조&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;큐 (Queue)&lt;/td&gt;
&lt;td&gt;스택 (Stack) 또는 재귀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;최단 거리 보장&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;보장 (가중치 없을 때)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-red&quot;&gt;보장 안 됨&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-blue&quot;&gt;O(V + E)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-blue&quot;&gt;O(V + E)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;유리한 문제&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;최단 거리, 최소 횟수, 가까운 대상 찾기&lt;/td&gt;
&lt;td&gt;모든 경로 탐색, 백트래킹, 사이클 판별&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;문제에서 &amp;ldquo;최단&amp;rdquo;, &amp;ldquo;최소&amp;rdquo;가 보이면 BFS&lt;/div&gt;
&amp;ldquo;최단 거리&amp;rdquo;, &amp;ldquo;최소 이동 횟수&amp;rdquo;, &amp;ldquo;최소 몇 번 만에&amp;rdquo; 같은 표현이 등장하고 간선의 비용이 모두 같다면 BFS를 먼저 떠올리세요. 반대로 간선마다 비용(가중치)이 다르다면 다익스트라 알고리즘이 필요합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; Java로 BFS 구현하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프를 &lt;b&gt;인접 리스트&lt;/b&gt;(각 노드마다 &amp;ldquo;연결된 노드 목록&amp;rdquo;을 저장하는 방식)로 표현하고, 자바의 &lt;code&gt;Queue&lt;/code&gt; 인터페이스와 &lt;code&gt;LinkedList&lt;/code&gt; 구현체로 BFS 기본 뼈대를 작성해 보겠습니다. 이 뼈대는 거의 모든 BFS 문제에서 그대로 재사용됩니다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; BFS 기본 템플릿&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;import java.util.*;

public class BfsTemplate {

    // graph[i] = i번 노드와 연결된 노드 목록 (인접 리스트)
    static List&amp;lt;Integer&amp;gt;[] graph;
    static boolean[] visited;

    static void bfs(int start) {
        Queue&amp;lt;Integer&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();

        // 1. 시작 노드를 큐에 넣고, 넣는 순간 방문 처리
        queue.offer(start);
        visited[start] = true;

        // 4. 큐가 빌 때까지 반복
        while (!queue.isEmpty()) {
            // 2. 큐에서 노드를 하나 꺼낸다
            int cur = queue.poll();
            System.out.println(&quot;방문: &quot; + cur);

            // 3. 인접 노드 중 미방문 노드를 큐에 넣는다
            for (int next : graph[cur]) {
                if (!visited[next]) {
                    visited[next] = true; // 넣는 순간 방문 처리!
                    queue.offer(next);
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;offer / poll 메서드&lt;/div&gt;
&lt;code&gt;offer()&lt;/code&gt;는 큐의 뒤에 데이터를 넣는 메서드, &lt;code&gt;poll()&lt;/code&gt;은 큐의 앞에서 데이터를 꺼내는 메서드입니다. 비슷한 역할의 &lt;code&gt;add()&lt;/code&gt; / &lt;code&gt;remove()&lt;/code&gt;도 있지만, 이 둘은 실패 시 예외를 던지는 반면 &lt;code&gt;offer()&lt;/code&gt; / &lt;code&gt;poll()&lt;/code&gt;은 null 등을 반환하므로 알고리즘 문제에서는 보통 &lt;code&gt;offer()&lt;/code&gt; / &lt;code&gt;poll()&lt;/code&gt;을 사용합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section5&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;5&lt;/span&gt; 문제풀이 1 : 백준 2606 바이러스&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 문제는 BFS 입문 문제의 대표 격인 &lt;b&gt;바이러스&lt;/b&gt;입니다. &amp;ldquo;시작점에서 도달할 수 있는 노드가 몇 개인가&amp;rdquo;를 세는 &lt;b&gt;연결 요소 탐색&lt;/b&gt; 유형으로, 앞에서 만든 기본 템플릿을 거의 그대로 사용할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;BOJ #2606&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;바이러스&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;컴퓨터 수 &amp;le; 100 &amp;middot; 시간제한 1초&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-silver&quot;&gt;Silver III&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터들이 네트워크로 연결되어 있습니다. 1번 컴퓨터가 바이러스에 걸렸을 때, 1번 컴퓨터를 통해 &lt;b&gt;바이러스에 감염되는 컴퓨터의 수&lt;/b&gt;를 출력하는 문제입니다. (1번 자신은 제외)&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;컴퓨터를 노드, 네트워크 연결을 간선으로 보고 &lt;b&gt;인접 리스트&lt;/b&gt;로 그래프를 만든다. 연결은 양방향이므로 간선을 양쪽 모두에 추가한다.&lt;/li&gt;
&lt;li&gt;1번 노드에서 &lt;b&gt;BFS를 시작&lt;/b&gt;해 도달 가능한 모든 노드를 방문한다.&lt;/li&gt;
&lt;li&gt;방문한 노드 수를 세고, 시작점인 &lt;b&gt;1번을 제외&lt;/b&gt;하기 위해 결과에서 1을 뺀다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 백준 2606 바이러스&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); // 컴퓨터(노드) 수
        int m = sc.nextInt(); // 연결(간선) 수

        // 인접 리스트 초기화 (1번 노드부터 쓰기 위해 n+1 크기)
        List&amp;lt;Integer&amp;gt;[] graph = new ArrayList[n + 1];
        for (int i = 1; i &amp;lt;= n; i++) graph[i] = new ArrayList&amp;lt;&amp;gt;();

        // 양방향 간선 등록
        for (int i = 0; i &amp;lt; m; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            graph[a].add(b);
            graph[b].add(a);
        }

        // 1번 노드에서 BFS
        boolean[] visited = new boolean[n + 1];
        Queue&amp;lt;Integer&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();
        queue.offer(1);
        visited[1] = true;

        int count = 0; // 감염된 컴퓨터 수 (1번 제외)

        while (!queue.isEmpty()) {
            int cur = queue.poll();
            for (int next : graph[cur]) {
                if (!visited[next]) {
                    visited[next] = true;
                    queue.offer(next);
                    count++; // 새로 감염될 때마다 카운트
                }
            }
        }

        System.out.println(count);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;1번을 방문 처리한 뒤 count는 0에서 시작&lt;/div&gt;
시작점 1번을 큐에 넣을 때 count를 올리지 않고, &lt;b&gt;새로운 노드가 감염될 때만&lt;/b&gt; count를 올리면 &amp;ldquo;1번을 제외한 감염 컴퓨터 수&amp;rdquo;가 자연스럽게 계산됩니다. 마지막에 1을 빼는 방식보다 실수할 여지가 적습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section6&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;6&lt;/span&gt; 문제풀이 2 : 백준 2178 미로 탐색&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 문제는 BFS의 진짜 강점인 &lt;b&gt;최단 거리&lt;/b&gt;를 활용하는 &lt;b&gt;미로 탐색&lt;/b&gt;입니다. 이번에는 노드가 번호가 아니라 &lt;b&gt;2차원 격자의 칸(행, 열)&lt;/b&gt;이라는 점이 다릅니다. 격자 문제에서는 상하좌우 이동을 표현하는 &lt;b&gt;방향 배열(dx, dy)&lt;/b&gt; 기법을 사용합니다.&lt;/p&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;BOJ #2178&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;미로 탐색&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;N, M &amp;le; 100 &amp;middot; 시간제한 1초&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-silver&quot;&gt;Silver I&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N&amp;times;M 크기의 미로에서 (1, 1)에서 출발해 (N, M)까지 이동할 때 &lt;b&gt;지나야 하는 최소 칸 수&lt;/b&gt;를 구하는 문제입니다. 1은 이동 가능한 칸, 0은 벽이며, 시작 칸과 도착 칸도 개수에 포함됩니다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;ldquo;최소 칸 수&amp;rdquo;를 묻고 모든 이동 비용이 1로 같으므로 &lt;b&gt;BFS로 최단 거리&lt;/b&gt;를 구하면 된다.&lt;/li&gt;
&lt;li&gt;상하좌우 이동을 &lt;b&gt;dx, dy 방향 배열&lt;/b&gt;로 표현하고, 미로 범위를 벗어나거나 벽(0)이거나 이미 방문한 칸은 건너뛴다.&lt;/li&gt;
&lt;li&gt;거리 저장은 별도 배열 대신 &lt;b&gt;미로 배열 값 자체를 누적 거리로 갱신&lt;/b&gt;한다. 다음 칸의 값 = 현재 칸의 값 + 1.&lt;/li&gt;
&lt;li&gt;탐색이 끝나면 도착 칸 (N, M)에 저장된 값이 최단 거리(지나온 칸 수)가 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 백준 2178 미로 탐색&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body angelscript&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    // 상, 하, 좌, 우 네 방향 (dx = 행 이동, dy = 열 이동)
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};

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

        int[][] maze = new int[n][m];
        for (int i = 0; i &amp;lt; n; i++) {
            String line = br.readLine();
            for (int j = 0; j &amp;lt; m; j++) {
                maze[i][j] = line.charAt(j) - '0';
            }
        }

        // BFS : 큐에는 {행, 열} 좌표를 int 배열로 담는다
        boolean[][] visited = new boolean[n][m];
        Queue&amp;lt;int[]&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();
        queue.offer(new int[]{0, 0});
        visited[0][0] = true;

        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            int x = cur[0];
            int y = cur[1];

            // 네 방향을 모두 확인
            for (int d = 0; d &amp;lt; 4; d++) {
                int nx = x + dx[d];
                int ny = y + dy[d];

                // 미로 범위 밖이면 건너뛰기
                if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= n || ny &amp;gt;= m) continue;
                // 벽이거나 이미 방문한 칸이면 건너뛰기
                if (maze[nx][ny] == 0 || visited[nx][ny]) continue;

                visited[nx][ny] = true;
                // 다음 칸의 거리 = 현재 칸의 거리 + 1
                maze[nx][ny] = maze[x][y] + 1;
                queue.offer(new int[]{nx, ny});
            }
        }

        // 도착 칸에 누적된 값 = 지나온 최소 칸 수
        System.out.println(maze[n - 1][m - 1]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;BFS의 최단 거리는 &amp;ldquo;처음 도착한 순간&amp;rdquo; 확정됩니다&lt;/div&gt;
BFS는 가까운 칸부터 순서대로 방문하기 때문에, 어떤 칸에 &lt;b&gt;처음 도착했을 때의 거리가 곧 최단 거리&lt;/b&gt;입니다. 그래서 이미 방문한 칸은 다시 볼 필요가 없고, DFS처럼 모든 경로를 비교할 필요도 없습니다. 이것이 최단 거리 문제에서 BFS를 쓰는 이유입니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section7&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;7&lt;/span&gt; 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS의 핵심을 다시 정리하면 세 가지입니다. &lt;b&gt;큐를 사용해 가까운 노드부터 방문한다&lt;/b&gt;, &lt;b&gt;큐에 넣는 순간 방문 처리한다&lt;/b&gt;, &lt;b&gt;가중치가 없다면 최단 거리가 보장된다&lt;/b&gt;. 이 세 가지만 기억하면 기본 템플릿에서 &amp;ldquo;큐에 무엇을 담을지(노드 번호 or 좌표)&amp;rdquo;와 &amp;ldquo;무엇을 셀지(개수 or 거리)&amp;rdquo;만 바꿔가며 대부분의 BFS 문제를 풀 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;다음 단계 추천 문제&lt;/div&gt;
백준 &lt;b&gt;1926(그림)&lt;/b&gt;, &lt;b&gt;7576(토마토)&lt;/b&gt;, &lt;b&gt;1697(숨바꼭질)&lt;/b&gt;을 추천합니다. 특히 토마토는 시작점이 여러 개인 &lt;b&gt;멀티 소스 BFS&lt;/b&gt;, 숨바꼭질은 격자가 아닌 &lt;b&gt;수직선 위의 BFS&lt;/b&gt;로, 오늘 배운 템플릿을 응용하는 좋은 연습이 됩니다.&lt;/div&gt;
&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/BFS (너비 우선 탐색)</category>
      <category>BFS</category>
      <category>java</category>
      <category>Queue</category>
      <category>너비 우선 탐색</category>
      <category>미로 탐색</category>
      <category>바이러스</category>
      <category>백준 2178</category>
      <category>백준 2606</category>
      <category>알고리즘</category>
      <category>자바 BFS</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/202</guid>
      <comments>https://minsu092274.tistory.com/202#entry202comment</comments>
      <pubDate>Sat, 18 Jul 2026 18:35:45 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 거리두기 확인하기(Java) &amp;mdash;  BFS</title>
      <link>https://minsu092274.tistory.com/201</link>
      <description>&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue  {background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green {background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber {background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red   {background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray  {background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b;box-shadow:0 4px 16px rgba(15,23,42,0.12);}.code-header{background:#1e293b;padding:8px 16px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:11px;color:#64748b;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;}pre.code-body{background:#0d1117;padding:1.25rem 1.5rem;margin:0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.75;color:#cbd5e1;}.c-blue{color:#93c5fd;}.c-green{color:#4ade80;}.c-lime{color:#86efac;}.c-teal{color:#a5f3fc;}.c-purple{color:#f0abfc;}.c-cyan{color:#6ee7b7;}.c-yellow{color:#fde68a;}.c-gray{color:#475569;font-style:italic;}.c-base{color:#cbd5e1;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box   {background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box  {background:#fffbeb;border:1px solid #fde68a;}.info-box  {background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box    .box-title{color:#047857;}.tip-box    .box-body{color:#065f46;}.warn-box   .box-title{color:#b45309;}.warn-box   .box-body{color:#92400e;}.info-box   .box-title{color:#2563eb;}.info-box   .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red  {display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue {display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;blog-post&quot;&gt;&lt;!-- ==================== 01 : 포스트 헤더 ==================== --&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;각 P에서 BFS를 시작&lt;/b&gt; &amp;mdash; 맨해튼 거리 2 이내에 다른 P가 있는지 확인한다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;X는 벽으로 처리&lt;/b&gt; &amp;mdash; 파티션으로 막힌 경로는 큐에 넣지 않으므로 자연스럽게 걸러진다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;거리 2에서 확장 중단&lt;/b&gt; &amp;mdash; &lt;code&gt;dis == 2&lt;/code&gt;인 노드는 검사만 하고 이웃을 큐에 넣지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!-- ==================== 03 : 목차 (자동 생성) ==================== --&gt;&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;&lt;!-- ==================== 문제 카드 ==================== --&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;Programmers #81302&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;거리두기 확인하기&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;5&amp;times;5 대기실 5개 &amp;middot; P(응시자) / O(빈 자리) / X(파티션)&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-green&quot;&gt;Lv.2&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5&amp;times;5 크기의 대기실 5개가 주어진다. 응시자들이 앉은 자리(P) 사이의 &lt;b&gt;맨해튼 거리가 2 이하&lt;/b&gt;이면 거리두기 위반인데, 예외적으로 두 자리 사이가 &lt;b&gt;파티션(X)으로 막혀 있으면&lt;/b&gt; 위반이 아니다. 각 대기실이 거리두기를 지키고 있으면 1, 아니면 0을 배열에 담아 반환한다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;대기실 5개를 각각 독립적으로 검사한다. 하나라도 위반 쌍이 발견되면 그 대기실은 0이다.&lt;/li&gt;
&lt;li&gt;대기실 안의 모든 P를 찾아, 각 P를 시작점으로 BFS를 돌린다.&lt;/li&gt;
&lt;li&gt;BFS 도중 거리 1~2 위치에서 다른 P를 만나면 즉시 위반으로 판정한다. X는 큐에 넣지 않으므로 파티션으로 막힌 경로는 탐색되지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================== 섹션 1 ==================== --&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; 접근 방법 &amp;mdash; 왜 BFS인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제의 핵심은 &amp;ldquo;맨해튼 거리 2 이하&amp;rdquo;와 &amp;ldquo;파티션으로 막혀 있으면 예외&amp;rdquo;라는 두 조건을 동시에 처리하는 것이다.&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;code&gt;P X P&lt;/code&gt;처럼 두 응시자가 한 칸 건너 앉아 있어도, 사이에 파티션이 있으면 거리두기 위반이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 좌표 계산 대신 &lt;b&gt;실제로 이동 가능한 경로 기준의 거리&lt;/b&gt;를 재기로 했다. X를 벽으로 취급하고 O와 P만 지나갈 수 있는 격자에서 BFS를 돌리면, 각 칸까지의 거리는 &amp;ldquo;파티션을 우회해서 도달하는 최단 거리&amp;rdquo;가 된다. 이 거리가 2 이하인 위치에 다른 P가 있을 때만 위반으로 판정하면 두 조건이 한 번에 해결된다.&lt;/p&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;BFS의 최단 거리 보장이 핵심&lt;/div&gt;
BFS는 각 칸에 항상 최단 거리로 먼저 도달한다. &lt;code&gt;P X P&lt;/code&gt; 케이스에서 오른쪽 P까지의 BFS 거리는 파티션을 우회한 3 이상이 되므로, 거리 2 이내 검사에 걸리지 않고 자연스럽게 통과 처리된다. 별도의 예외 분기 없이 파티션 조건이 해결되는 이유다.&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================== 섹션 2 ==================== --&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; BFS 설계&lt;/h2&gt;
&lt;h3 id=&quot;section2-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;큐에 담는 상태&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐에는 &lt;code&gt;{row, col, dis}&lt;/code&gt; 세 값을 담았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리(dis)는 노드마다 달라지는 값이므로 큐 안에 함께 넣어 관리한다. 시작점의 거리는 0이고, 이웃으로 확장할 때마다 &lt;code&gt;dis + 1&lt;/code&gt;로 넣는다.&lt;/p&gt;
&lt;h3 id=&quot;section2-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;위반 판정과 탐색 범위 제한&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐에서 노드를 꺼냈을 때 두 가지를 검사한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;위반 검사&lt;/b&gt; &amp;mdash; &lt;code&gt;dis &amp;gt; 0&lt;/code&gt;이면서 현재 칸이 P라면 거리 2 이내에 다른 응시자가 있다는 뜻이므로 &lt;code&gt;false&lt;/code&gt;를 반환한다. &lt;code&gt;dis &amp;gt; 0&lt;/code&gt; 조건은 시작점 자신(P)을 제외하기 위한 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장 중단&lt;/b&gt; &amp;mdash; &lt;code&gt;dis == 2&lt;/code&gt;라면 검사만 하고 이웃을 큐에 넣지 않는다. 거리 3 이상은 어차피 위반 대상이 아니므로 탐색할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확장 조건은 네 가지를 모두 만족해야 한다. 격자 범위 안이고, 방문하지 않았고, X(파티션)가 아닌 칸만 큐에 넣는다.&lt;/p&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;경계 검사는 배열 접근보다 먼저&lt;/div&gt;
&lt;code&gt;next_row &amp;gt;= 0 &amp;amp;&amp;amp; next_row &amp;lt; 5&lt;/code&gt; 같은 범위 검사를 &lt;code&gt;visited[next_row][next_col]&lt;/code&gt; 배열 접근보다 앞에 두어야 한다. 순서가 뒤집히면 격자 밖 좌표로 배열에 접근해 &lt;code&gt;ArrayIndexOutOfBoundsException&lt;/code&gt;이 발생한다. &amp;amp;&amp;amp; 연산자의 단축 평가(short-circuit) 덕분에 앞 조건이 false면 뒤 조건은 평가되지 않는다.&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================== 섹션 3 ==================== --&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; 전체 코드&lt;/h2&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; Solution.java&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body angelscript&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    static int[] dr = {-1, 1, 0, 0};
    static int[] dc = {0, 0, 1, -1};

    public int[] solution(String[][] places) {
        int[] answer = new int[5];

        for (int i = 0; i &amp;lt; places.length; i++) {
            answer[i] = check(places[i]) ? 1 : 0;
        }

        return answer;
    }

    public boolean check(String[] place) {
        char[][] arr = new char[5][5];

        for (int i = 0; i &amp;lt; 5; i++) {
            for (int j = 0; j &amp;lt; 5; j++) {
                arr[i][j] = place[i].charAt(j);
            }
        }

        for (int i = 0; i &amp;lt; 5; i++) {
            for (int j = 0; j &amp;lt; 5; j++) {
                if (arr[i][j] == 'P') {
                    if (!bfs(arr, i, j)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public boolean bfs(char[][] arr, int startRow, int startCol) {
        ArrayDeque&amp;lt;int[]&amp;gt; deque = new ArrayDeque&amp;lt;&amp;gt;();
        boolean[][] visited = new boolean[5][5];
        deque.add(new int[]{startRow, startCol, 0});
        visited[startRow][startCol] = true;

        while (!deque.isEmpty()) {
            int[] cur = deque.poll();
            int row = cur[0];
            int col = cur[1];
            int dis = cur[2];

            if (dis &amp;gt; 0 &amp;amp;&amp;amp; arr[row][col] == 'P') {
                return false;
            }

            if (dis == 2) continue;  // 거리 2에서는 더 확장하지 않음

            for (int i = 0; i &amp;lt; 4; i++) {
                int nextRow = row + dr[i];
                int nextCol = col + dc[i];

                if (nextRow &amp;gt;= 0 &amp;amp;&amp;amp; nextCol &amp;gt;= 0 &amp;amp;&amp;amp; nextRow &amp;lt; 5 &amp;amp;&amp;amp; nextCol &amp;lt; 5
                        &amp;amp;&amp;amp; !visited[nextRow][nextCol] &amp;amp;&amp;amp; arr[nextRow][nextCol] != 'X') {
                    visited[nextRow][nextCol] = true;
                    deque.add(new int[]{nextRow, nextCol, dis + 1});
                }
            }
        }

        return true;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- ==================== 섹션 4 ==================== --&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; 정리하면서 손본 부분&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 제출한 코드도 정답이었지만, 정리하면서 몇 군데를 다듬었다.&lt;/p&gt;
&lt;h3 id=&quot;section4-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;불필요한 탐색 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 코드는 &lt;code&gt;dis == 2&lt;/code&gt;인 노드에서도 이웃을 큐에 넣고, 꺼낸 뒤에야 &lt;code&gt;if (dis &amp;gt; 2) continue&lt;/code&gt;로 버리는 구조였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답에는 영향이 없지만 거리 3짜리 노드를 만들었다가 버리는 낭비가 있었다. &lt;code&gt;dis == 2&lt;/code&gt; 시점에 확장을 멈추도록 바꾸면 거리 3 이상인 노드가 아예 생성되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 바꾸고 나니 위반 검사 조건도 단순해졌다. 원래는 &lt;code&gt;dis &amp;gt; 0 &amp;amp;&amp;amp; dis &amp;lt;= 2 &amp;amp;&amp;amp; arr[row][col] == 'P'&lt;/code&gt;였는데, 큐에 거리 0~2인 노드만 들어오게 되면서 &lt;code&gt;dis &amp;lt;= 2&lt;/code&gt;가 항상 참이 되어 조건에서 뺄 수 있었다.&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;처음 코드&lt;/th&gt;
&lt;th&gt;수정 후&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;확장 중단&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dis &amp;gt; 2&lt;/code&gt;인 노드를 꺼낸 뒤 &lt;code&gt;continue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dis == 2&lt;/code&gt;에서 확장하지 않음 &lt;span class=&quot;badge-green&quot;&gt;개선&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;위반 검사&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dis &amp;gt; 0 &amp;amp;&amp;amp; dis &amp;lt;= 2 &amp;amp;&amp;amp; P&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dis &amp;gt; 0 &amp;amp;&amp;amp; P&lt;/code&gt; &lt;span class=&quot;badge-blue&quot;&gt;단순화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;거리 3 노드&lt;/b&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;/div&gt;
&lt;h3 id=&quot;section4-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;스타일 정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;answer[i]&lt;/code&gt; 대입을 if/else 대신 삼항 연산자 &lt;code&gt;check(places[i]) ? 1 : 0&lt;/code&gt;으로 줄였다.&lt;/li&gt;
&lt;li&gt;배열 선언을 &lt;code&gt;int dx[]&lt;/code&gt;에서 Java 관례에 맞는 &lt;code&gt;int[] dr&lt;/code&gt; 형태로 바꿨다. 이름도 행/열 의미가 드러나도록 &lt;code&gt;dr&lt;/code&gt;/&lt;code&gt;dc&lt;/code&gt;로 정했다.&lt;/li&gt;
&lt;li&gt;변수명을 &lt;code&gt;start_row&lt;/code&gt; &amp;rarr; &lt;code&gt;startRow&lt;/code&gt;처럼 카멜케이스로 통일했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;조건문으로 직접 확인하는 대안도 있다&lt;/div&gt;
거리 제한이 2로 고정이라, BFS 없이 각 P 기준으로 &amp;ldquo;거리 1 상하좌우 / 거리 2 직선 / 대각선&amp;rdquo; 케이스를 조건문으로 직접 검사하는 풀이도 널리 쓰인다. 다만 케이스 분기가 많아 실수 여지가 있고, BFS 방식은 거리 제한이 바뀌어도 그대로 통용되는 일반적인 형태라 이 방식을 택했다.&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================== 섹션 5 ==================== --&gt;&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;</description>
      <category>알고리즘/BFS (너비 우선 탐색)</category>
      <category>BFS</category>
      <category>거리두기 확인하기</category>
      <category>거리두기 확인하기 자바</category>
      <category>프로그래머스</category>
      <category>프로그래머스 거리두기 확인하기</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/201</guid>
      <comments>https://minsu092274.tistory.com/201#entry201comment</comments>
      <pubDate>Sat, 18 Jul 2026 18:10:50 +0900</pubDate>
    </item>
    <item>
      <title>[Java] StringTokenizer 사용법 - split()과의 차이점</title>
      <link>https://minsu092274.tistory.com/200</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ================================================
     [Java] StringTokenizer 사용법
     ================================================ --&gt;&lt;/p&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;&lt;!-- 전체 CSS --&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue  {background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green {background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber {background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red   {background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray  {background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b;box-shadow:0 4px 16px rgba(15,23,42,0.12);}.code-header{background:#1e293b;padding:8px 16px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:11px;color:#64748b;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;}pre.code-body{background:#0d1117;padding:1.25rem 1.5rem;margin:0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.75;color:#cbd5e1;}.c-blue{color:#93c5fd;}.c-green{color:#4ade80;}.c-lime{color:#86efac;}.c-teal{color:#a5f3fc;}.c-purple{color:#f0abfc;}.c-cyan{color:#6ee7b7;}.c-yellow{color:#fde68a;}.c-gray{color:#475569;font-style:italic;}.c-base{color:#cbd5e1;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box   {background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box  {background:#fffbeb;border:1px solid #fde68a;}.info-box  {background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box    .box-title{color:#047857;}.tip-box    .box-body{color:#065f46;}.warn-box   .box-title{color:#b45309;}.warn-box   .box-body{color:#92400e;}.info-box   .box-title{color:#2563eb;}.info-box   .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red  {display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue {display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;StringTokenizer는 문자열을 구분자 기준으로 잘라주는 클래스&lt;/b&gt; &amp;mdash; 정규식을 쓰지 않아 &lt;code&gt;split()&lt;/code&gt;보다 단순하고 빠르다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세 번째 인자를 true로 주면 구분자도 토큰으로 반환&lt;/b&gt; &amp;mdash; 수식 파싱처럼 구분자 자체가 필요한 경우에 유용하다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빈 토큰은 무시된다&lt;/b&gt; &amp;mdash; 구분자가 연속으로 나올 때 &lt;code&gt;split()&lt;/code&gt;과 결과가 달라지므로 주의&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 목차 (자동 생성) --&gt;&lt;/p&gt;
&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; StringTokenizer란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;java.util.StringTokenizer&lt;/code&gt;는 문자열을 &lt;b&gt;구분자(delimiter) 기준으로 잘라 토큰 단위로 꺼내 쓸 수 있게 해주는 클래스&lt;/b&gt;다. 문자열을 한 번에 배열로 바꾸는 &lt;code&gt;split()&lt;/code&gt;과 달리, &lt;code&gt;hasMoreTokens()&lt;/code&gt;로 남은 토큰이 있는지 확인하면서 &lt;code&gt;nextToken()&lt;/code&gt;으로 하나씩 꺼내는 방식으로 동작한다.&lt;/p&gt;
&lt;h3 id=&quot;section1-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;왜 사용하는가? (split과의 차이)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;split()&lt;/code&gt;은 인자를 &lt;b&gt;정규식으로 해석&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt; 같은 정규식 특수문자를 구분자로 쓰려면 이스케이프가 필요하고, 내부적으로 정규식 엔진을 거치기 때문에 단순 분리 작업치고는 비용이 크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;code&gt;StringTokenizer&lt;/code&gt;는 구분자를 &lt;b&gt;문자 집합으로 그대로 해석&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;&quot;+-*&quot;&lt;/code&gt;를 넘기면 정규식이 아니라 &quot;+ 또는 - 또는 * 중 하나&quot;라는 뜻이라 이스케이프를 고민할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코딩테스트에서 공백으로 구분된 입력을 대량으로 읽을 때 &lt;code&gt;BufferedReader&lt;/code&gt;와 함께 표준 조합으로 쓰이는 이유이기도 하다.&lt;/p&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;구분자는 &quot;문자열&quot;이 아니라 &quot;문자들의 집합&quot;&lt;/div&gt;
&lt;code&gt;new StringTokenizer(str, &quot;+-&quot;)&lt;/code&gt;는 &quot;+-&quot;라는 두 글자짜리 문자열을 찾는 게 아니라, &lt;b&gt;+와 - 각각을 구분자로 취급&lt;/b&gt;한다. 여러 종류의 구분자를 한 번에 처리할 수 있다는 뜻이지만, 두 글자 이상의 문자열 자체를 구분자로 쓰고 싶다면 StringTokenizer로는 안 되고 &lt;code&gt;split()&lt;/code&gt;을 써야 한다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; StringTokenizer 사용법&lt;/h2&gt;
&lt;h3 id=&quot;section2-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;생성자 3가지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자는 인자 개수에 따라 세 가지 형태가 있다. 세 번째 인자가 이 클래스의 핵심 기능이다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 생성자 3가지&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;// 1. 구분자 생략 &amp;mdash; 기본값은 공백류(&quot; \t\n\r\f&quot;)
StringTokenizer st1 = new StringTokenizer(&quot;1 2 3&quot;);
// 토큰: &quot;1&quot;, &quot;2&quot;, &quot;3&quot;

// 2. 구분자 지정 &amp;mdash; 각 문자를 구분자로 취급
StringTokenizer st2 = new StringTokenizer(&quot;100-200+300&quot;, &quot;+-&quot;);
// 토큰: &quot;100&quot;, &quot;200&quot;, &quot;300&quot; &amp;mdash; 구분자는 버려진다

// 3. 세 번째 인자 true &amp;mdash; 구분자도 토큰으로 반환
StringTokenizer st3 = new StringTokenizer(&quot;100-200+300&quot;, &quot;+-&quot;, true);
// 토큰: &quot;100&quot;, &quot;-&quot;, &quot;200&quot;, &quot;+&quot;, &quot;300&quot; &amp;mdash; 구분자가 살아있다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id=&quot;section2-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;주요 메서드&lt;/h3&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; hasMoreTokens / nextToken / countTokens&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;StringTokenizer st = new StringTokenizer(&quot;10 20 30&quot;);

// 1. countTokens() &amp;mdash; 남은 토큰 개수 반환
int count = st.countTokens();  // 3

// 2. hasMoreTokens() + nextToken() &amp;mdash; 표준 순회 패턴
while (st.hasMoreTokens()) {
    String token = st.nextToken();  // &quot;10&quot; &amp;rarr; &quot;20&quot; &amp;rarr; &quot;30&quot;
}

// 3. 개수를 알고 있다면 for문으로도 가능
StringTokenizer st2 = new StringTokenizer(&quot;1 2 3 4 5&quot;);
int[] arr = new int[st2.countTokens()];
for (int i = 0; i &amp;lt; arr.length; i++) {
    arr[i] = Integer.parseInt(st2.nextToken());
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;토큰이 없는데 nextToken()을 호출하면 예외 발생&lt;/div&gt;
남은 토큰이 없는 상태에서 &lt;code&gt;nextToken()&lt;/code&gt;을 호출하면 &lt;code&gt;NoSuchElementException&lt;/code&gt;이 발생한다. 항상 &lt;code&gt;hasMoreTokens()&lt;/code&gt;로 확인하거나, &lt;code&gt;countTokens()&lt;/code&gt;만큼만 반복해야 한다.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&quot;section2-3&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;전체 메서드 한눈에 보기&lt;/h3&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;메서드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;비고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hasMoreTokens()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;남은 토큰이 있으면 true&lt;/td&gt;
&lt;td&gt;while 조건으로 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nextToken()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;다음 토큰 반환&lt;/td&gt;
&lt;td&gt;없으면 &lt;code&gt;NoSuchElementException&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nextToken(delim)&lt;/code&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;code&gt;countTokens()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;남은 토큰 개수 반환&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nextToken()&lt;/code&gt; 호출 시마다 감소&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; split()과의 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 헷갈리기 쉬운 차이는 &lt;b&gt;빈 토큰 처리&lt;/b&gt;다. 구분자가 연속으로 나오거나 문자열이 구분자로 시작하면 두 방식의 결과가 달라진다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 빈 토큰 처리 차이&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;String str = &quot;a,,b&quot;;

// split() &amp;mdash; 빈 문자열도 결과에 포함
String[] arr = str.split(&quot;,&quot;);
// [&quot;a&quot;, &quot;&quot;, &quot;b&quot;] &amp;mdash; 길이 3

// StringTokenizer &amp;mdash; 빈 토큰은 건너뜀
StringTokenizer st = new StringTokenizer(str, &quot;,&quot;);
// &quot;a&quot;, &quot;b&quot; &amp;mdash; 토큰 2개&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;StringTokenizer&lt;/th&gt;
&lt;th&gt;split()&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분자 해석&lt;/b&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;b&gt;빈 토큰&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-amber&quot;&gt;무시&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-blue&quot;&gt;포함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분자 유지&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;가능&lt;/span&gt; (세 번째 인자 true)&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-red&quot;&gt;기본 불가&lt;/span&gt; (lookahead 정규식 필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;속도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;빠름&lt;/span&gt; (정규식 미사용)&lt;/td&gt;
&lt;td&gt;상대적으로 느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;결과 형태&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;하나씩 순회 (Iterator 스타일)&lt;/td&gt;
&lt;td&gt;배열로 한 번에 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;선택 기준&lt;/div&gt;
공백/특정 문자로 잘라서 순서대로 읽기만 하면 되는 입력 파싱은 &lt;b&gt;StringTokenizer&lt;/b&gt;, 빈 문자열을 보존해야 하거나 인덱스로 접근할 배열이 필요하거나 정규식 패턴으로 잘라야 한다면 &lt;b&gt;split()&lt;/b&gt;이 맞다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; 실전 활용&lt;/h2&gt;
&lt;h3 id=&quot;section4-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;BufferedReader와 조합 (입력 파싱)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코딩테스트에서 가장 자주 쓰는 형태다. &lt;code&gt;Scanner&lt;/code&gt;보다 훨씬 빠르기 때문에 입력량이 많은 문제에서는 이 조합이 표준이다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; BufferedReader + StringTokenizer&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

// &quot;5 3&quot; 형태의 한 줄 입력 파싱
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id=&quot;section4-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;구분자를 살려서 수식 파싱하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 번째 인자 &lt;code&gt;true&lt;/code&gt;가 진가를 발휘하는 경우다. 수식을 파싱할 때는 숫자뿐 아니라 &lt;b&gt;연산자 자체도 토큰으로 필요&lt;/b&gt;한데, 세 번째 인자를 &lt;code&gt;true&lt;/code&gt;로 주면 별도 처리 없이 숫자와 연산자가 번갈아 담긴 리스트를 바로 만들 수 있다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 수식을 토큰 리스트로 분리&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;String expression = &quot;100-200*300-500+20&quot;;

List&amp;lt;String&amp;gt; tokens = new ArrayList&amp;lt;&amp;gt;();
StringTokenizer st = new StringTokenizer(expression, &quot;+-*&quot;, true);
while (st.hasMoreTokens()) {
    tokens.add(st.nextToken());
}

// 결과: [100, -, 200, *, 300, -, 500, +, 20]
// 정규식 없이 숫자와 연산자가 번갈아 담긴 리스트 완성&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 작업을 &lt;code&gt;split()&lt;/code&gt;으로 하려면 &lt;code&gt;split(&quot;(?=[+\\-*])|(?&amp;lt;=[+\\-*])&quot;)&lt;/code&gt; 같은 정규식이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히 쓰기도 어렵고 나중에 읽기는 더 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분자를 살려야 하는 파싱이라면 StringTokenizer의 세 번째 인자가 훨씬 단순한 답이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴을 실제로 활용한 문제 풀이는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://minsu092274.tistory.com/199&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2026.07.17 - [알고리즘/완전 탐색 및 백트래킹] - [프로그래머스] 수식 최대화(Java) - 완전탐색&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글에서 확인할 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java/Java</category>
      <category>StringTokenizer</category>
      <category>StringTokenizer 구분자</category>
      <category>StringTokenizer 메서드</category>
      <category>StringTokenizer 사용법</category>
      <category>StringTokenizer와 split()</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/200</guid>
      <comments>https://minsu092274.tistory.com/200#entry200comment</comments>
      <pubDate>Fri, 17 Jul 2026 18:14:41 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 수식 최대화(Java) - 완전탐색</title>
      <link>https://minsu092274.tistory.com/199</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ================================================
     [프로그래머스] Lv.2 수식 최대화 (Java)
     ================================================ --&gt;&lt;/p&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;&lt;!-- 전체 CSS --&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue  {background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green {background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber {background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red   {background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray  {background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b;box-shadow:0 4px 16px rgba(15,23,42,0.12);}.code-header{background:#1e293b;padding:8px 16px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:11px;color:#64748b;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;}pre.code-body{background:#0d1117;padding:1.25rem 1.5rem;margin:0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.75;color:#cbd5e1;}.c-blue{color:#93c5fd;}.c-green{color:#4ade80;}.c-lime{color:#86efac;}.c-teal{color:#a5f3fc;}.c-purple{color:#f0abfc;}.c-cyan{color:#6ee7b7;}.c-yellow{color:#fde68a;}.c-gray{color:#475569;font-style:italic;}.c-base{color:#cbd5e1;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box   {background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box  {background:#fffbeb;border:1px solid #fde68a;}.info-box  {background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box    .box-title{color:#047857;}.tip-box    .box-body{color:#065f46;}.warn-box   .box-title{color:#b45309;}.warn-box   .box-body{color:#92400e;}.info-box   .box-title{color:#2563eb;}.info-box   .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red  {display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue {display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;완전탐색&lt;/b&gt; &amp;mdash; 연산자 3개의 우선순위 순열은 6가지뿐이라 전부 시도해도 충분하다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;토큰 리스트 축약&lt;/b&gt; &amp;mdash; 우선순위가 높은 연산자부터 찾아 [숫자, 연산자, 숫자] 세 토큰을 결과 하나로 접는다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인덱스 보정&lt;/b&gt; &amp;mdash; 리스트를 순회하면서 동시에 수정할 때는 줄어든 크기만큼 인덱스를 되돌려야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 목차 (자동 생성) --&gt;&lt;/p&gt;
&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; 문제 이해&lt;/h2&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;Programmers #67257&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;수식 최대화&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;expression 길이 &amp;le; 100 &amp;middot; 피연산자는 3자리 이하&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-green&quot;&gt;Lv.2&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt; 세 연산자로 이루어진 수식이 주어진다. 연산자 우선순위를 마음대로 재정의할 수 있을 때(단, 우선순위가 같은 연산자는 없음), 수식 결과의 절댓값이 최대가 되는 값을 구하는 문제다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;수식을 숫자와 연산자 토큰으로 분리한다&lt;/li&gt;
&lt;li&gt;우선순위 순열 6가지를 하나씩 시도한다&lt;/li&gt;
&lt;li&gt;각 순열에서 우선순위가 높은 연산자부터 리스트를 훑으며 계산하고, 세 토큰을 결과 하나로 접는다&lt;/li&gt;
&lt;li&gt;최종 결과의 절댓값 중 최댓값을 갱신한다&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; 접근 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자가 &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt; 세 개뿐이라 우선순위 순열은 3! = 6가지밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;expression 길이도 최대 100이라서 6가지를 전부 시도하는 완전탐색으로 충분하다고 판단했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰 분리는 &lt;code&gt;StringTokenizer&lt;/code&gt;의 세 번째 인자를 &lt;code&gt;true&lt;/code&gt;로 주면 구분자인 연산자까지 토큰으로 같이 뽑아준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 정규식 없이 &lt;code&gt;[100, -, 200, *, 300, ...]&lt;/code&gt; 형태의 리스트를 바로 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산은 우선순위가 높은 연산자부터 리스트를 앞에서부터 훑으면서, 해당 연산자를 만나면 양옆 숫자와 함께 세 토큰을 지우고 계산 결과 하나를 그 자리에 넣는 방식이다.&lt;/p&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;중간 결과는 long으로&lt;/div&gt;
곱셈이 먼저 처리되는 순열에서는 중간 결과가 int 범위를 넘을 수 있다. 리스트에 문자열로 다시 넣은 중간 결과를 꺼낼 때 &lt;code&gt;Integer.parseInt&lt;/code&gt;가 아니라 &lt;code&gt;Long.parseLong&lt;/code&gt;으로 읽어야 한다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; 헤맨 부분: 순회 중 리스트 수정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 제출한 코드는 일부 케이스에서 틀렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인은 리스트에서 토큰 3개를 지우고 1개를 넣으면 리스트가 2칸 줄어드는데, 반복문 인덱스 &lt;code&gt;i&lt;/code&gt;는 그대로 &lt;code&gt;i++&lt;/code&gt;로 진행된다는 점이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;1 - 2 - 3&lt;/code&gt;처럼 같은 연산자가 연속으로 나오는 경우를 직접 따라가 보면 문제가 보인다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;trace &amp;mdash; 보정 없이 실행했을 때&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;// copy = [1, -, 2, -, 3],  op = &quot;-&quot;
i=1: &quot;-&quot; 매치 &amp;rarr; 1-2 계산 &amp;rarr; copy = [-1, -, 3]
i=2: copy.get(2) = &quot;3&quot; &amp;rarr; 연산자가 아님
i=3: 루프 종료
// 두 번째 &quot;-&quot;는 인덱스 1로 당겨졌는데 i는 이미 2를 지나 건너뛰었다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축약 후 리스트가 2칸 줄었으니 인덱스도 그만큼 되돌려야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축약 처리 끝에 &lt;code&gt;i--&lt;/code&gt;를 넣으면 루프의 &lt;code&gt;i++&lt;/code&gt;와 합쳐져 결과적으로 &lt;code&gt;i - 1&lt;/code&gt;, 즉 방금 넣은 결과 바로 다음 위치부터 다시 검사하게 된다.&lt;/p&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;순회 중 수정 시 인덱스 보정&lt;/div&gt;
리스트를 순회하면서 동시에 요소를 지우거나 넣을 때는, 크기가 변한 만큼 인덱스를 보정해야 한다. 보정을 빼먹으면 같은 요소가 연속으로 나오는 케이스에서만 조용히 틀리기 때문에 원인을 찾기 어렵다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; 전체 코드&lt;/h2&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; Solution.java&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    private static final String[][] PRIORITIES = {
        {&quot;+&quot;, &quot;-&quot;, &quot;*&quot;}, {&quot;+&quot;, &quot;*&quot;, &quot;-&quot;},
        {&quot;-&quot;, &quot;+&quot;, &quot;*&quot;}, {&quot;-&quot;, &quot;*&quot;, &quot;+&quot;},
        {&quot;*&quot;, &quot;+&quot;, &quot;-&quot;}, {&quot;*&quot;, &quot;-&quot;, &quot;+&quot;}
    };

    public long solution(String expression) {
        // 숫자와 연산자를 토큰으로 분리
        List&amp;lt;String&amp;gt; tokens = new ArrayList&amp;lt;&amp;gt;();
        StringTokenizer st = new StringTokenizer(expression, &quot;+-*&quot;, true);
        while (st.hasMoreTokens()) {
            tokens.add(st.nextToken());
        }

        long answer = 0;
        for (String[] priority : PRIORITIES) {
            List&amp;lt;String&amp;gt; copy = new ArrayList&amp;lt;&amp;gt;(tokens);

            for (String op : priority) {
                for (int i = 0; i &amp;lt; copy.size(); i++) {
                    if (op.equals(copy.get(i))) {
                        long left = Long.parseLong(copy.get(i - 1));
                        long right = Long.parseLong(copy.get(i + 1));
                        long result = calculate(left, right, op);

                        // [left, op, right] 세 토큰을 result 하나로 접기
                        copy.remove(i - 1);
                        copy.remove(i - 1);
                        copy.remove(i - 1);
                        copy.add(i - 1, String.valueOf(result));
                        i--; // 리스트가 2칸 줄었으니 인덱스 보정
                    }
                }
            }
            answer = Math.max(answer, Math.abs(Long.parseLong(copy.get(0))));
        }
        return answer;
    }

    private long calculate(long a, long b, String op) {
        switch (op) {
            case &quot;+&quot;: return a + b;
            case &quot;-&quot;: return a - b;
            case &quot;*&quot;: return a * b;
            default: throw new IllegalArgumentException(&quot;알 수 없는 연산자: &quot; + op);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 순열마다 원본 토큰의 복사본을 만들어 계산하고, 최종적으로 남은 값의 절댓값 중 최댓값을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;calculate&lt;/code&gt;의 default에서 예외를 던지도록 한 건, 여기 도달하면 로직에 버그가 있다는 뜻이라 조용히 0을 반환하는 것보다 바로 드러나는 편이 낫기 때문이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/완전 탐색 및 백트래킹</category>
      <category>수식 최대화</category>
      <category>수식 최대화 자바</category>
      <category>프로그래머스</category>
      <category>프로그래머스 수식 최대화</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/199</guid>
      <comments>https://minsu092274.tistory.com/199#entry199comment</comments>
      <pubDate>Fri, 17 Jul 2026 18:03:32 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 무인도 여행 &amp;mdash; BFS</title>
      <link>https://minsu092274.tistory.com/198</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ★ 서식 00 : 전체 CSS --&gt;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue  {background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green {background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber {background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red   {background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray  {background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b;box-shadow:0 4px 16px rgba(15,23,42,0.12);}.code-header{background:#1e293b;padding:8px 16px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:11px;color:#64748b;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;}pre.code-body{background:#0d1117;padding:1.25rem 1.5rem;margin:0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.75;color:#cbd5e1;}.c-blue{color:#93c5fd;}.c-green{color:#4ade80;}.c-lime{color:#86efac;}.c-teal{color:#a5f3fc;}.c-purple{color:#f0abfc;}.c-cyan{color:#6ee7b7;}.c-yellow{color:#fde68a;}.c-gray{color:#475569;font-style:italic;}.c-base{color:#cbd5e1;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box   {background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box  {background:#fffbeb;border:1px solid #fde68a;}.info-box  {background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box    .box-title{color:#047857;}.tip-box    .box-body{color:#065f46;}.warn-box   .box-title{color:#b45309;}.warn-box   .box-body{color:#92400e;}.info-box   .box-title{color:#2563eb;}.info-box   .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red  {display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue {display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;blog-post&quot;&gt;&lt;!-- ==================================================== 01 : 포스트 헤더 ==================================================== --&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;연결 요소별 합계&lt;/b&gt; &amp;mdash; 격자에서 상하좌우로 이어진 육지(섬)를 BFS로 묶고, 섬마다 식량의 합을 구하는 문제입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;거리 BFS vs 집계 BFS&lt;/b&gt; &amp;mdash; 미로 탈출처럼 거리를 구할 땐 큐에 &lt;code&gt;{r, c, day}&lt;/code&gt;를 싣지만, 이 문제는 탐색 밖의 변수 하나에 누적하면 충분합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 03 : 목차 (자동 생성) ==================================================== --&gt;&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;&lt;!-- ==================================================== 섹션 1 : 문제 소개 ==================================================== --&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; 문제 소개&lt;/h2&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;Programmers #154540&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;무인도 여행&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;지도 최대 100&amp;times;100 &amp;middot; 각 칸은 X 또는 1~9&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-green&quot;&gt;Lv.2&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 배열로 주어지는 지도에서 &lt;code&gt;X&lt;/code&gt;는 바다, 숫자는 그 칸에서 얻을 수 있는 식량입니다. 상하좌우로 연결된 숫자 칸들이 하나의 무인도를 이룰 때, &lt;b&gt;각 섬에서 얻을 수 있는 식량의 총합을 오름차순으로&lt;/b&gt; 반환해야 합니다. 섬이 하나도 없으면 &lt;code&gt;{-1}&lt;/code&gt;을 반환합니다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;문자열 배열을 &lt;code&gt;char[][]&lt;/code&gt; 맵으로 &lt;b&gt;먼저 전부 변환&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;이중 루프를 돌며 아직 방문하지 않은 육지 칸을 만나면 BFS를 시작합니다.&lt;/li&gt;
&lt;li&gt;BFS가 퍼지는 동안 방문하는 칸의 식량을 지역 변수 &lt;code&gt;total&lt;/code&gt;에 누적하고, 탐색이 끝나면 그 값이 곧 섬 하나의 식량 합입니다.&lt;/li&gt;
&lt;li&gt;섬별 합계를 오름차순 정렬해 &lt;code&gt;int[]&lt;/code&gt;로 변환합니다. 리스트가 비어 있으면 &lt;code&gt;{-1}&lt;/code&gt;을 반환합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 문장으로 요약하면 &lt;b&gt;&quot;연결 요소(Connected Component)를 찾고, 각 요소의 값을 합산하라&quot;&lt;/b&gt;는 문제입니다. 얼마 전에 풀었던 미로 탈출과 똑같이 격자 BFS인데, 막상 풀어보니 큐에 실어야 하는 정보가 완전히 달랐습니다. 이번 포스트의 핵심은 바로 그 차이입니다.&lt;/p&gt;
&lt;!-- ==================================================== 섹션 2 : 접근 ==================================================== --&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; 접근: 미방문 육지마다 BFS 한 번씩&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 구조는 격자 연결 요소 문제의 전형적인 패턴입니다. 바깥에서 이중 루프로 모든 칸을 훑다가, &lt;b&gt;바다가 아니고 아직 방문하지 않은 칸&lt;/b&gt;을 만나면 거기서 BFS를 한 번 돌립니다. BFS 한 번이 섬 하나를 통째로 방문 처리하므로, 같은 섬의 다른 칸에서는 두 번 다시 BFS가 시작되지 않습니다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 탐색 시작 구조&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; row; i++) {
    for (int j = 0; j &amp;lt; col; j++) {
        if (map[i][j] != 'X' &amp;amp;&amp;amp; !visited[i][j]) {
            answerList.add(bfs(i, j));  // BFS 1회 = 섬 1개의 식량 합
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;code&gt;visited&lt;/code&gt;를 클래스 필드로 두는 게 포인트입니다. BFS 호출이 끝나도 방문 기록이 유지돼야 &quot;이미 처리한 섬&quot;을 건너뛸 수 있기 때문입니다. 각 칸은 정확히 한 번씩만 방문되므로 전체 시간 복잡도는 O(N&amp;times;M)입니다.&lt;/p&gt;
&lt;!-- ==================================================== 섹션 3 : 핵심 ==================================================== --&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; 핵심: 그 값은 누구의 것인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 미로 탈출을 풀던 습관대로 큐에 &lt;code&gt;{행, 열, 값}&lt;/code&gt; 형태로 값을 실어 나르려고 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이 문제에서는 그럴 필요가 전혀 없었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방식의 차이를 정리해보니, 기준은 &lt;b&gt;&quot;그 값이 칸마다 다른 답을 가지는가?&quot;&lt;/b&gt;라는 질문 하나였습니다.&lt;/p&gt;
&lt;h3 id=&quot;section3-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;밖의 변수 = 탐색 전체의 집계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무인도의 식량 합계는 특정 칸의 속성이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이 칸의 합계&quot;라는 개념 자체가 없고, &lt;b&gt;탐색이 끝났을 때 하나만 나오면 되는 값&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 값은 노드마다 들고 다닐 이유가 없으니 BFS 바깥의 지역 변수에 누적하면 끝입니다.&lt;/p&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; 두 방식 비교&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;// [거리 BFS] 값이 칸마다 다름 &amp;rarr; 큐에 실어 부모&amp;rarr;자식으로 전파
deque.add(new int[]{nr, nc, current[2] + 1});

// [집계 BFS] 값이 탐색 전체에 하나 &amp;rarr; 밖의 변수에 누적
total += map[nr][nc] - '0';
deque.add(new int[]{nr, nc});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;거리 BFS (큐에 싣기)&lt;/th&gt;
&lt;th&gt;집계 BFS (밖에서 누적)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;값의 주인&lt;/b&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;b&gt;값이 정해지는 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;부모 값에서 파생 (&lt;code&gt;부모 + 1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;방문한 칸들의 합&amp;middot;개수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;답을 읽는 시점&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;목표 칸을 발견할 때&lt;/td&gt;
&lt;td&gt;while 루프 종료 후&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;대표 문제&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-blue&quot;&gt;미로 탈출&lt;/span&gt; 최단거리&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;무인도 여행&lt;/span&gt; 섬 크기&amp;middot;합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;상태 설계 판별법&lt;/div&gt;
&quot;이 값이 칸마다 다른 답을 가지는가?&quot;를 먼저 물어보세요. 다르면 큐에 싣고, 탐색 끝에 하나만 나오면 되는 값이면 밖에 둡니다. 같은 격자 BFS라도 &lt;b&gt;문제가 묻는 것&lt;/b&gt;에 따라 큐에 실어야 할 상태가 달라집니다.&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 섹션 5 : 전체 코드 ==================================================== --&gt;
&lt;h2 id=&quot;section5&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;5&lt;/span&gt; 전체 코드&lt;/h2&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; Solution.java&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    static final int[] dx = {-1, 1, 0, 0};
    static final int[] dy = {0, 0, 1, -1};

    int row, col;
    char[][] map;
    boolean[][] visited;

    public int[] solution(String[] maps) {
        row = maps.length;
        col = maps[0].length();
        map = new char[row][col];
        visited = new boolean[row][col];

        // 1단계: 맵 완성
        for (int i = 0; i &amp;lt; row; i++) {
            for (int j = 0; j &amp;lt; col; j++) {
                map[i][j] = maps[i].charAt(j);
            }
        }

        // 2단계: 미방문 육지마다 BFS
        List&amp;lt;Integer&amp;gt; answerList = new ArrayList&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; row; i++) {
            for (int j = 0; j &amp;lt; col; j++) {
                if (map[i][j] != 'X' &amp;amp;&amp;amp; !visited[i][j]) {
                    answerList.add(bfs(i, j));
                }
            }
        }

        if (answerList.isEmpty()) {
            return new int[]{-1};
        }
        return answerList.stream()
                .sorted()
                .mapToInt(Integer::intValue)
                .toArray();
    }

    public int bfs(int startRow, int startCol) {
        ArrayDeque&amp;lt;int[]&amp;gt; deque = new ArrayDeque&amp;lt;&amp;gt;();
        deque.add(new int[]{startRow, startCol});
        visited[startRow][startCol] = true;

        int total = map[startRow][startCol] - '0'; // 시작 칸 식량 포함!

        while (!deque.isEmpty()) {
            int[] current = deque.poll();
            int curRow = current[0];
            int curCol = current[1];

            for (int i = 0; i &amp;lt; 4; i++) {
                int nextRow = curRow + dx[i];
                int nextCol = curCol + dy[i];

                if (nextRow &amp;gt;= 0 &amp;amp;&amp;amp; nextCol &amp;gt;= 0 &amp;amp;&amp;amp; nextRow &amp;lt; row &amp;amp;&amp;amp; nextCol &amp;lt; col
                        &amp;amp;&amp;amp; map[nextRow][nextCol] != 'X' &amp;amp;&amp;amp; !visited[nextRow][nextCol]) {
                    visited[nextRow][nextCol] = true;
                    total += map[nextRow][nextCol] - '0'; // 방문 처리와 같은 시점에 합산
                    deque.add(new int[]{nextRow, nextCol});
                }
            }
        }
        return total;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 칸을 정확히 한 번씩만 방문하므로 시간 복잡도는 &lt;b&gt;O(N&amp;times;M)&lt;/b&gt;으로 최적입니다. 이 문제는 방문 순서가 결과에 영향을 주지 않아서 DFS로 풀어도 무방하지만, 격자 탐색은 BFS 패턴으로 통일해두는 편이 스택 오버플로 걱정도 없고 익숙해서 BFS를 선택했습니다.&lt;/p&gt;
&lt;!-- ==================================================== 섹션 6 : 마무리 ==================================================== --&gt;
&lt;h2 id=&quot;section6&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;6&lt;/span&gt; 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;BFS는 이미 할 줄 안다&quot;고 생각했는데, 미로 탈출의 틀을 그대로 가져왔다가 큐에 실을 필요 없는 값을 실어 나르며 헤맸습니다. 같은 격자 BFS라도 문제가 &lt;b&gt;&quot;몇 번 만에 도달하는가&quot;&lt;/b&gt;를 묻는지 &lt;b&gt;&quot;연결된 덩어리의 합이 얼마인가&quot;&lt;/b&gt;를 묻는지에 따라 상태 설계가 완전히 달라진다는 걸 몸으로 배운 문제였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면 이번 문제에서 챙겨갈 것은 세 가지입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상태 설계 질문&lt;/b&gt; &amp;mdash; 큐에 싣기 전에 &quot;이 값이 칸마다 다른가?&quot;를 먼저 묻는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초기화 &amp;rarr; 탐색 순서&lt;/b&gt; &amp;mdash; 자료구조를 다 만들고 나서 그 위에서 탐색을 시작한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방문&amp;middot;합산 시점 통일&lt;/b&gt; &amp;mdash; 큐에 넣는 순간 방문 처리와 합산을 함께 하고, 시작 칸은 루프 밖에서 미리 더한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/BFS (너비 우선 탐색)</category>
      <category>BFS</category>
      <category>무인도 여행</category>
      <category>무인도 여행 자바</category>
      <category>프로그래머스</category>
      <category>프로그래머스 무인도 여행</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/198</guid>
      <comments>https://minsu092274.tistory.com/198#entry198comment</comments>
      <pubDate>Thu, 16 Jul 2026 19:45:20 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 디펜스 게임 (Java) &amp;mdash; 우선순위 큐</title>
      <link>https://minsu092274.tistory.com/197</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ★ 서식 00 : 전체 CSS (마스터) --&gt;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue  {background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green {background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber {background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red   {background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray  {background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b;box-shadow:0 4px 16px rgba(15,23,42,0.12);}.code-header{background:#1e293b;padding:8px 16px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:11px;color:#64748b;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;}pre.code-body{background:#0d1117;padding:1.25rem 1.5rem;margin:0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.75;color:#cbd5e1;}.c-blue{color:#93c5fd;}.c-green{color:#4ade80;}.c-lime{color:#86efac;}.c-teal{color:#a5f3fc;}.c-purple{color:#f0abfc;}.c-cyan{color:#6ee7b7;}.c-yellow{color:#fde68a;}.c-gray{color:#475569;font-style:italic;}.c-base{color:#cbd5e1;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box   {background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box  {background:#fffbeb;border:1px solid #fde68a;}.info-box  {background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box    .box-title{color:#047857;}.tip-box    .box-body{color:#065f46;}.warn-box   .box-title{color:#b45309;}.warn-box   .box-body{color:#92400e;}.info-box   .box-title{color:#2563eb;}.info-box   .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red  {display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue {display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 01 : 포스트 헤더 ==================================================== --&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;무적권은 소급 적용이 가능하다&lt;/b&gt; &amp;mdash; &quot;언제 쓸지&quot; 미리 결정하지 말고, 병사가 부족해진 순간 &lt;b&gt;지금까지 가장 병사를 많이 쓴 라운드&lt;/b&gt;에 쓴 셈 치면 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최대 힙(PriorityQueue)으로 최댓값 관리&lt;/b&gt; &amp;mdash; 매 라운드 적의 수를 힙에 넣어두면, 소급 적용할 최적의 라운드를 &lt;code&gt;poll()&lt;/code&gt; 한 번(O(log N))으로 찾을 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검증 후 카운트&lt;/b&gt; &amp;mdash; &lt;code&gt;answer++&lt;/code&gt;는 그 라운드를 실제로 막아냈다는 검증이 끝난 뒤에 실행해야 실패한 라운드가 세어지지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 03 : 목차 (자동 생성) ==================================================== --&gt;&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;&lt;!-- ==================================================== 섹션 1 : 문제 설명 ==================================================== --&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; 문제 설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/142085&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/142085&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;Programmers #142085&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;디펜스 게임&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;n &amp;le; 10⁹ &amp;middot; k &amp;le; 500,000 &amp;middot; enemy &amp;le; 1,000,000&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-green&quot;&gt;Lv.2&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병사 &lt;code&gt;n&lt;/code&gt;명으로 매 라운드 &lt;code&gt;enemy[i]&lt;/code&gt;마리의 적을 막는 게임이다. 적을 막으면 그 수만큼 병사가 소모되고, 남은 병사보다 적이 많으면 게임이 끝난다. 단, &lt;b&gt;무적권&lt;/b&gt;을 쓰면 병사 소모 없이 한 라운드를 막을 수 있고 최대 &lt;code&gt;k&lt;/code&gt;번 사용할 수 있다. 무적권을 최적으로 사용했을 때 &lt;b&gt;최대 몇 라운드까지 버틸 수 있는지&lt;/b&gt; 구하는 문제다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;입출력 예&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;n=7, k=3, enemy=[4,2,4,5,3,3,1]&lt;/code&gt; &amp;rarr; 적이 많은 4, 5, 4 라운드에 무적권을 쓰고 나머지를 병사로 막으면 &lt;b&gt;5라운드&lt;/b&gt;까지 버틴다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n=2, k=4, enemy=[3,3,3,3]&lt;/code&gt; &amp;rarr; 병사로는 한 라운드도 못 막지만 무적권 4번으로 &lt;b&gt;4라운드(전부)&lt;/b&gt; 막는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 섹션 2 : 문제 해결 전략 ==================================================== --&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; 문제 해결 전략&lt;/h2&gt;
&lt;h3 id=&quot;section2-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;처음 든 생각: 언제 무적권을 써야 하지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;적이 많은 라운드에 무적권을 아껴 써야 한다&quot;는 건 직관적으로 알겠는데, 문제는 &lt;b&gt;미래의 적 규모를 모른 채로 현재 라운드에서 결정&lt;/b&gt;해야 한다는 점이다. 지금 라운드에 무적권을 썼는데 뒤에 더 큰 적이 나오면 손해다. 그렇다고 모든 경우를 탐색하자니 &lt;code&gt;enemy&lt;/code&gt; 길이가 최대 100만이라 완전탐색은 불가능하다.&lt;/p&gt;
&lt;h3 id=&quot;section2-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;발상의 전환: 무적권을 소급 적용하자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 관점을 바꾸면 문제가 풀린다. &lt;b&gt;무적권을 미리 결정할 필요가 없다.&lt;/b&gt; 일단 모든 라운드를 병사로 막았다고 치고 진행하다가, 병사가 부족해지는 순간(&lt;code&gt;n &amp;lt; 0&lt;/code&gt;)에 &quot;지금까지 지나온 라운드 중 병사를 가장 많이 소모한 라운드에 사실은 무적권을 썼던 걸로&quot; 정정하면 된다. 그 라운드에 썼던 병사(&lt;code&gt;enemy&lt;/code&gt; 최댓값)를 돌려받는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 소급 적용이 항상 최적인 이유는 간단하다. 무적권 한 장이 아껴주는 병사 수는 그 라운드의 적 수와 같으므로, &lt;b&gt;같은 한 장이라면 무조건 적이 가장 많았던 라운드에 쓰는 것이 이득&lt;/b&gt;이기 때문이다. 이것이 이 문제의 그리디 논리다.&lt;/p&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;왜 최대 힙인가?&lt;/div&gt;
&quot;지금까지 지나온 라운드 중 최댓값&quot;을 매번 꺼내야 하는데, 배열에서 매번 최댓값을 찾으면 O(N)이라 전체 O(N&amp;sup2;)이 된다. &lt;b&gt;최대 힙&lt;/b&gt;은 삽입과 최댓값 추출이 모두 O(log N)이므로, &quot;동적으로 원소가 추가되는 집합에서 반복적으로 최댓값을 뽑는&quot; 이 문제에 정확히 들어맞는 자료구조다.&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 섹션 3 : 구체적인 구현 단계 ==================================================== --&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; 구체적인 구현 단계&lt;/h2&gt;
&lt;h3 id=&quot;section3-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;① 최대 힙 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 &lt;code&gt;PriorityQueue&lt;/code&gt;는 기본이 최소 힙이므로, &lt;code&gt;Collections.reverseOrder()&lt;/code&gt;를 생성자에 넘겨 최대 힙으로 만든다.&lt;/p&gt;
&lt;h3 id=&quot;section3-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;② 일단 병사로 막으며 진행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매 라운드 적의 수를 힙에 넣고(&lt;code&gt;pq.add(e)&lt;/code&gt;), 병사에서 차감한다(&lt;code&gt;n -= e&lt;/code&gt;). 이 시점의 &lt;code&gt;n&lt;/code&gt;은 &quot;무적권 없이 여기까지 왔다면 남았을 병사 수&quot;를 의미한다. 음수가 아니라면 그 라운드는 무사히 방어한 것이다.&lt;/p&gt;
&lt;h3 id=&quot;section3-3&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;③ 병사가 부족하면 무적권 소급 적용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;n &amp;lt; 0&lt;/code&gt;이 되는 순간이 결정의 순간이다. 무적권이 남아 있다면(&lt;code&gt;k &amp;gt; 0&lt;/code&gt;) 힙에서 최댓값을 꺼내 병사를 돌려받고(&lt;code&gt;n += pq.poll()&lt;/code&gt;) &lt;code&gt;k&lt;/code&gt;를 차감한다. 방금 넣은 현재 라운드의 적도 힙에 들어 있으므로, 현재 라운드가 역대 최대라면 자연스럽게 현재 라운드에 무적권을 쓰는 셈이 된다. 무적권이 없다면 이 라운드는 막을 수 없으니 &lt;code&gt;break&lt;/code&gt;로 종료한다.&lt;/p&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;복구 후 n은 항상 0 이상이 되는 이유&lt;/div&gt;
힙에서 꺼낸 최댓값은 방금 차감한 현재 라운드의 적 수(&lt;code&gt;e&lt;/code&gt;) 이상이다. 직전까지 &lt;code&gt;n &amp;ge; 0&lt;/code&gt;이었으므로, &lt;code&gt;n - e + (최댓값 &amp;ge; e)&lt;/code&gt;는 반드시 0 이상으로 회복된다. 즉 무적권이 남아 있는 한 &lt;b&gt;단 한 번의 poll로 그 라운드 방어가 보장&lt;/b&gt;되고, while로 반복해서 꺼낼 필요가 없다.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&quot;section3-4&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;④ 검증이 끝난 뒤 answer++&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라운드 방어 성공 여부가 확정된 뒤에야 &lt;code&gt;answer++&lt;/code&gt;를 실행한다. 무적권으로 복구했든 병사로 막았든 여기 도달했다면 방어 성공이고, 실패 시에는 &lt;code&gt;break&lt;/code&gt;로 빠져나가므로 카운트되지 않는다.&lt;/p&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;answer 갱신 타이밍 주의&lt;/div&gt;
&lt;code&gt;answer++&lt;/code&gt;를 루프 시작 부분(검증 전)에 두면, 무적권도 없고 병사도 부족해서 &lt;b&gt;막지 못한 마지막 라운드까지 세어버리는&lt;/b&gt; 오프바이원 오류가 난다. &quot;조건 검증이 모두 끝난 뒤에 확정한다&quot;는 원칙은 이런 시뮬레이션형 문제에서 특히 자주 시험대에 오른다.&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 섹션 4 : 전체 코드 ==================================================== --&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; 전체 코드&lt;/h2&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; Solution.java&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body angelscript&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public int solution(int n, int k, int[] enemy) {
        int answer = 0;

        // 최대 힙: 지나온 라운드 중 가장 큰 적 규모를 O(log N)에 조회
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());

        for (int e : enemy) {
            pq.add(e);  // 현재 라운드도 무적권 후보에 포함
            n -= e;    // 일단 병사로 막았다고 가정

            if (n &amp;lt; 0) { // 병사 부족 &amp;rarr; 결정의 순간
                if (k &amp;gt; 0 &amp;amp;&amp;amp; !pq.isEmpty()) {
                    // 가장 컸던 라운드에 무적권을 소급 적용 &amp;rarr; 병사 회수
                    n += pq.poll();
                    k--;
                } else {
                    break; // 무적권 소진 &amp;rarr; 이 라운드는 못 막음
                }
            }

            answer++; // 검증이 끝난 뒤에만 라운드 카운트
        }

        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간복잡도는 라운드마다 힙 연산이 O(log N)이므로 전체 &lt;b&gt;O(N log N)&lt;/b&gt;. &lt;code&gt;enemy&lt;/code&gt; 길이가 최대 100만이어도 여유 있게 통과한다.&lt;/p&gt;
&lt;!-- ==================================================== 섹션 5 : 정리 ==================================================== --&gt;
&lt;h2 id=&quot;section5&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;5&lt;/span&gt; 정리&lt;/h2&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;핵심 처리&lt;/th&gt;
&lt;th&gt;놓치면 생기는 문제&lt;/th&gt;
&lt;th&gt;중요도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;힙 구성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Collections.reverseOrder()&lt;/code&gt;로 최대 힙 생성&lt;/td&gt;
&lt;td&gt;기본 최소 힙이면 가장 작은 라운드에 무적권 낭비&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-red&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;진행 순서&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;힙 삽입 &amp;rarr; 차감 &amp;rarr; 부족 시 복구&lt;/td&gt;
&lt;td&gt;현재 라운드를 힙에 안 넣으면 현재가 최대인 경우 누락&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-red&quot;&gt;필수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;소급 적용&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n &amp;lt; 0&lt;/code&gt;일 때 최댓값 poll로 병사 회수&lt;/td&gt;
&lt;td&gt;미리 무적권 시점을 정하려 하면 그리디 성립 불가&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-blue&quot;&gt;핵심 발상&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;카운트 시점&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;검증 완료 후 &lt;code&gt;answer++&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;못 막은 라운드까지 세는 오프바이원 오류&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-amber&quot;&gt;함정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;이 문제에서 배운 것&lt;/div&gt;
그리디에서 &quot;언제 쓸까&quot;를 미리 결정하기 어렵다면, &lt;b&gt;일단 진행하고 한계에 부딪힌 순간 과거의 선택을 정정하는 소급 적용&lt;/b&gt;이 강력한 패턴이 된다. 그리고 &quot;동적으로 추가되는 값들 중 최댓값/최솟값을 반복해서 꺼내는&quot; 작업이 보이면 우선순위 큐가 정답 자료구조다. 힙과 그리디는 이렇게 자주 한 세트로 움직인다.&lt;/div&gt;
&lt;/div&gt;
&lt;!-- ==================================================== 푸터 ==================================================== --&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>문제풀이/스택과 큐</category>
      <category>디펜스 게임</category>
      <category>디펜스 게임 자바</category>
      <category>우선순위 큐</category>
      <category>프로그래머스</category>
      <category>프로그래머스 디펜스 게임</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/197</guid>
      <comments>https://minsu092274.tistory.com/197#entry197comment</comments>
      <pubDate>Fri, 10 Jul 2026 17:45:13 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 미로 탈출 (Java) - BFS</title>
      <link>https://minsu092274.tistory.com/196</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ================================================
     [프로그래머스 Lv.2] 미로 탈출 (159993) — BFS 두 번으로 경유지 최단거리 구하기
     ================================================ --&gt;&lt;/p&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;&lt;!-- ================================================
     ★ 서식 00 : 전체 CSS (마스터)
     ================================================ --&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue  {background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green {background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber {background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red   {background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray  {background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b;box-shadow:0 4px 16px rgba(15,23,42,0.12);}.code-header{background:#1e293b;padding:8px 16px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:11px;color:#64748b;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;}pre.code-body{background:#0d1117;padding:1.25rem 1.5rem;margin:0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.75;color:#cbd5e1;}.c-blue{color:#93c5fd;}.c-green{color:#4ade80;}.c-lime{color:#86efac;}.c-teal{color:#a5f3fc;}.c-purple{color:#f0abfc;}.c-cyan{color:#6ee7b7;}.c-yellow{color:#fde68a;}.c-gray{color:#475569;font-style:italic;}.c-base{color:#cbd5e1;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box   {background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box  {background:#fffbeb;border:1px solid #fde68a;}.info-box  {background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box    .box-title{color:#047857;}.tip-box    .box-body{color:#065f46;}.warn-box   .box-title{color:#b45309;}.warn-box   .box-body{color:#92400e;}.info-box   .box-title{color:#2563eb;}.info-box   .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red  {display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue {display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;경유지 최단거리 분해&lt;/b&gt; &amp;mdash; &quot;S에서 E로 가되 반드시 L을 거쳐야 한다&quot;는 조건은 &lt;b&gt;S&amp;rarr;L 최단거리 + L&amp;rarr;E 최단거리&lt;/b&gt;로 쪼갤 수 있다. 경유지가 고정이면 두 BFS 결과를 독립적으로 합쳐도 최단이 보장된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BFS는 target 문자만 알면 된다&lt;/b&gt; &amp;mdash; 목표 좌표를 미리 저장할 필요 없이, 탐색 중 처음 만난 target까지의 거리가 곧 최단거리다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ====================================================
     03 : 목차 (TOC) — h2/h3 태그를 읽어 자동 생성
     ==================================================== --&gt;&lt;/p&gt;
&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ==================== 섹션 1 : 문제 분석 ==================== --&gt;&lt;/p&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; 문제 분석&lt;/h2&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;Programmers #159993&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;미로 탈출&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;5 &amp;le; 세로 &amp;middot; 가로 &amp;le; 100 &amp;middot; Lv.2&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-green&quot;&gt;Level 2&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S(시작점)에서 출발해 E(출구)로 탈출해야 한다. 단, 출구는 잠겨 있어서 &lt;b&gt;반드시 L(레버)을 먼저 당겨야&lt;/b&gt; 열린다. X는 벽이라 지나갈 수 없고, 한 칸 이동에 1초가 걸린다. 탈출까지 걸리는 &lt;b&gt;최소 시간&lt;/b&gt;을 구하고, 탈출할 수 없으면 -1을 반환한다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;미로를 순회하며 S와 L의 좌표를 기록한다. (E는 BFS가 문자로 직접 찾으므로 저장 불필요)&lt;/li&gt;
&lt;li&gt;1차 BFS: S에서 출발해 L까지의 최단거리를 구한다. 도달 불가면 -1 반환.&lt;/li&gt;
&lt;li&gt;2차 BFS: L에서 출발해 E까지의 최단거리를 구한다. 도달 불가면 -1 반환.&lt;/li&gt;
&lt;li&gt;두 최단거리의 합을 반환한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ==================== 섹션 2 : 접근 ==================== --&gt;&lt;/p&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; 접근: BFS를 두 번으로 나누기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제의 핵심은 &quot;레버를 거쳐야 한다&quot;는 제약을 어떻게 처리하느냐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태에 &lt;code&gt;레버를 당겼는지&lt;/code&gt; 여부를 추가해서 한 번의 BFS로 풀 수도 있지만, 훨씬 단순한 관점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;경유지 L이 고정되어 있다&lt;/b&gt;는 점에 주목하면, 전체 경로는 반드시 &quot;S에서 L까지의 구간&quot;과 &quot;L에서 E까지의 구간&quot;으로 나뉜다. 각 구간의 최단거리는 서로 독립적이므로, 두 구간을 각각 BFS로 구해 더하면 그것이 전체 최단 시간이 된다.&lt;/p&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;왜 두 최단거리를 더해도 최단이 보장될까?&lt;/div&gt;
전체 경로가 L을 지나는 순간, 경로는 (S&amp;rarr;L 부분)과 (L&amp;rarr;E 부분)으로 쪼개진다. 만약 전체 최단 경로의 S&amp;rarr;L 부분이 S&amp;rarr;L 최단거리보다 길다면, 그 부분만 최단 경로로 교체해서 더 짧은 전체 경로를 만들 수 있으므로 모순이다. 따라서 &lt;b&gt;각 구간의 최단거리 합 = 전체 최단거리&lt;/b&gt;가 성립한다. 경유지가 하나로 고정일 때만 통하는 논리라는 점에 주의.&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하나의 설계 포인트는 &lt;b&gt;BFS에 목표 좌표가 아닌 목표 문자를 넘긴다&lt;/b&gt;는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS는 거리 순으로 칸을 방문하므로, 탐색 중 target 문자를 처음 만난 시점의 거리가 곧 최단거리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덕분에 E의 좌표를 미리 저장할 필요가 없고, 같은 &lt;code&gt;bfs&lt;/code&gt; 메서드를 두 구간에 그대로 재사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ==================== 섹션 3 : 전체 코드 ==================== --&gt;&lt;/p&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; 전체 코드&lt;/h2&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; Solution.java&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    // 상하좌우 4방향 이동량 (행 변화, 열 변화)
    static final int[] dx = {-1, 1, 0, 0};
    static final int[] dy = {0, 0, -1, 1};

    public int solution(String[] maps) {
        int rows = maps.length;
        int cols = maps[0].length();

        char[][] map = new char[rows][cols];
        int[] start = null;   // 시작 지점 S 좌표
        int[] lever = null;   // 레버 L 좌표

        // 문자열 배열 &amp;rarr; char 2차원 배열 변환하며 S, L 좌표 기록
        // (E는 BFS가 target 문자로 직접 찾으므로 좌표 저장 불필요)
        for (int i = 0; i &amp;lt; rows; i++) {
            for (int j = 0; j &amp;lt; cols; j++) {
                char c = maps[i].charAt(j);
                map[i][j] = c;

                if (c == 'S')      start = new int[]{i, j};
                else if (c == 'L') lever = new int[]{i, j};
            }
        }

        // 1차 BFS: 시작점 &amp;rarr; 레버 최단거리
        int toLever = bfs(start, 'L', map);
        if (toLever == -1) return -1;   // 레버 도달 불가 &amp;rarr; 탈출 불가

        // 2차 BFS: 레버 &amp;rarr; 출구 최단거리
        int toExit = bfs(lever, 'E', map);
        if (toExit == -1) return -1;    // 출구 도달 불가 &amp;rarr; 탈출 불가

        // 경유지(L)가 고정이므로 두 최단거리의 합이 전체 최단 시간
        return toLever + toExit;
    }

    /** start 좌표에서 target 문자까지의 최단거리 반환 (도달 불가 시 -1) */
    private int bfs(int[] start, char target, char[][] map) {
        int rows = map.length;
        int cols = map[0].length;

        Queue&amp;lt;int[]&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();
        boolean[][] visited = new boolean[rows][cols];

        // 큐 원소는 {행, 열, 시작점부터의 거리}
        queue.add(new int[]{start[0], start[1], 0});
        visited[start[0]][start[1]] = true;   // 방문 표시는 enqueue 시점에!

        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            int row = cur[0], col = cur[1], dist = cur[2];

            // 목표 도달 &amp;rarr; BFS 특성상 처음 만난 거리가 곧 최단거리
            if (map[row][col] == target) return dist;

            for (int d = 0; d &amp;lt; 4; d++) {
                int nextRow = row + dx[d];
                int nextCol = col + dy[d];

                // 격자 범위를 벗어나면 스킵
                if (nextRow &amp;lt; 0 || nextRow &amp;gt;= rows || nextCol &amp;lt; 0 || nextCol &amp;gt;= cols) continue;
                // 벽(X)이면 스킵
                if (map[nextRow][nextCol] == 'X') continue;
                // 이미 방문한 칸이면 스킵
                if (visited[nextRow][nextCol]) continue;

                visited[nextRow][nextCol] = true;
                queue.add(new int[]{nextRow, nextCol, dist + 1});
            }
        }

        return -1;   // 큐가 비었는데 target 미도달
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;방문 표시는 queue 삽입 직전에&lt;/div&gt;
방문 표시를 poll 시점에 하면 같은 칸이 큐에 여러 번 들어가 시간과 메모리를 낭비한다. &quot;확인 &amp;rarr; 방문 표시 &amp;rarr; 큐 삽입&quot; 순서를 지켜, 큐에 넣는 순간 방문 처리하는 것이 BFS의 기본 패턴이다.&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ==================== 섹션 4 : 디버깅 &amp; 개선 ==================== --&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/BFS (너비 우선 탐색)</category>
      <category>BFS</category>
      <category>미로 탈출</category>
      <category>미로 탈출 자바</category>
      <category>프로그래머스</category>
      <category>프로그래머스 미로 탈출</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/196</guid>
      <comments>https://minsu092274.tistory.com/196#entry196comment</comments>
      <pubDate>Wed, 8 Jul 2026 14:41:04 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 연속된 부분 수열의 합 (Java) - 투 포인터</title>
      <link>https://minsu092274.tistory.com/195</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ================================================
     [프로그래머스] 연속된 부분 수열의 합 (Java)
     ※ 글 최상단에 서식_00_전체CSS가 삽입되어 있어야 합니다.
     ================================================ --&gt;&lt;/p&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;&lt;!-- ================================================  ★ 서식 00 : 전체 CSS (마스터)  CSS가 날아갔을 때 글 최상단에 이 서식 하나만 삽입하세요.  스크립트는 스킨편집 &gt; script.js 에 별도 등록하세요.  ================================================ --&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post { font-family: 'Noto Sans KR', sans-serif; color: #334155; line-height: 1.8; font-size: 15px; max-width: 780px; margin: 0 auto; padding: 2rem 0; }.blog-post p { margin-bottom: 1rem; }.blog-post strong { color: #0f172a; }.blog-post ul, .blog-post ol { padding-left: 1.5rem; margin-bottom: 1rem; }.blog-post li { margin: 5px 0; font-size: 14px; }.blog-post code { font-family: 'JetBrains Mono', monospace; font-size: 12.5px; background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 4px; padding: 1px 6px; color: #c7254e; }.blog-post hr { border: none; border-top: 1px solid #e2e8f0; margin: 2.5rem 0; }/* ── 02 핵심 요약 박스 ── */.summary-box { background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 10px; padding: 1.25rem 1.5rem; margin-bottom: 2rem; }.summary-label { font-size: 12px; font-weight: 700; color: #2563eb; letter-spacing: 0.06em; margin-bottom: 0.75rem; }.summary-box ul { padding-left: 1.25rem; margin: 0; }.summary-box li { font-size: 14px; color: #334155; margin: 5px 0; line-height: 1.75; }.summary-box li strong { color: #0f172a; }/* ── 03 목차 ── */.my-toc { border-radius: 12px; overflow: hidden; margin-bottom: 2.5rem; border: 1px solid #162d4a; }.my-toc-header { background: #1e3a5f; padding: 16px 22px; display: flex; align-items: center; gap: 10px; }.my-toc-header-bar { width: 3px; height: 22px; background: #93c5fd; border-radius: 2px; flex-shrink: 0; }.my-toc-header-text { font-size: 17px; font-weight: 700; color: #f1f5f9; }.my-toc-body { background: #f8fafc; padding: 12px 16px 14px; }.my-toc-list { display: flex; flex-direction: column; gap: 2px; }.my-toc-list &gt; div &gt; a { display: flex; align-items: center; gap: 12px; padding: 11px 14px; border-radius: 8px; font-size: 15px; font-weight: 500; color: #1e3a5f; text-decoration: none; transition: background 0.15s, color 0.15s; }.my-toc-list &gt; div &gt; a:hover { background: #dbeafe; color: #1d4ed8; }.my-toc-list &gt; div &gt; a:hover .my-toc-num { background: #1e3a5f; color: #fff; }.my-toc-num { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; min-width: 26px; background: #e2e8f0; color: #334155; border-radius: 6px; font-size: 13px; font-weight: 700; flex-shrink: 0; transition: background 0.15s, color 0.15s; }.my-toc-num.active { background: #1e3a5f; color: #fff; }.my-toc-list &gt; div &gt; a.my-toc-active { background: #dbeafe; color: #1e3a5f; }.my-toc-list &gt; div &gt; a.my-toc-active .my-toc-num { background: #1e3a5f; color: #fff; }.my-toc-sub { display: flex; flex-direction: column; gap: 1px; padding: 2px 0 4px 52px; }.my-toc-sub div a { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 6px; font-size: 14px; color: #475569; text-decoration: none; transition: background 0.15s, color 0.15s; }.my-toc-sub div a::before { content: ''; display: inline-block; width: 5px; height: 5px; min-width: 5px; background: #94a3b8; border-radius: 50%; flex-shrink: 0; transition: background 0.15s; }.my-toc-sub div a:hover { background: #f1f5f9; color: #1e3a5f; }.my-toc-sub div a:hover::before { background: #1e3a5f; }.my-toc-sub div a.my-toc-active { color: #1e3a5f; }.my-toc-sub div a.my-toc-active::before { background: #1e3a5f; }/* ── 04 섹션 제목 ── */.my-section-title { font-size: 20px; font-weight: 700; color: #0f172a; margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 2px solid #2563eb; display: flex; align-items: center; gap: 10px; }.my-section-num { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; background: #2563eb; color: #fff; border-radius: 50%; font-size: 13px; font-weight: 700; flex-shrink: 0; }.my-sub-title { font-size: 16px; font-weight: 600; color: #0f172a; margin: 1.5rem 0 0.75rem; padding-left: 12px; border-left: 3px solid #2563eb; }.section-status { font-size: 14px; font-weight: 400; margin-left: 8px; }.status-fail { color: #ef4444; }.status-ok   { color: #10b981; }/* ── 05 코드 블록 ── */.code-wrap { margin: 1.25rem 0; border-radius: 10px; overflow: hidden; border: 1px solid #1e293b; box-shadow: 0 4px 16px rgba(15,23,42,0.12); }.code-header { background: #1e293b; padding: 8px 16px; display: flex; align-items: center; justify-content: space-between; }.code-dots { display: flex; gap: 6px; }.cdot { width: 12px; height: 12px; border-radius: 50%; }.cdot-r { background: #ff5f57; }.cdot-y { background: #febc2e; }.cdot-g { background: #28c840; }.code-lang { font-size: 11px; color: #64748b; font-family: 'JetBrains Mono', monospace; letter-spacing: 0.05em; }pre.code-body { background: #0d1117; padding: 1.25rem 1.5rem; margin: 0; overflow-x: auto; font-family: 'JetBrains Mono', monospace; font-size: 13px; line-height: 1.75; color: #cbd5e1; }.c-blue   { color: #93c5fd; }.c-green  { color: #4ade80; }.c-lime   { color: #86efac; }.c-teal   { color: #a5f3fc; }.c-purple { color: #f0abfc; }.c-cyan   { color: #6ee7b7; }.c-yellow { color: #fde68a; }.c-gray   { color: #475569; font-style: italic; }.c-base   { color: #cbd5e1; }/* ── 06 강조 박스 ── */.tip-box, .warn-box, .info-box, .danger-box { border-radius: 10px; padding: 1rem 1.25rem; margin: 1.25rem 0; display: flex; gap: 12px; align-items: flex-start; }.tip-box    { background: #ecfdf5; border: 1px solid #a7f3d0; }.warn-box   { background: #fffbeb; border: 1px solid #fde68a; }.info-box   { background: #eff6ff; border: 1px solid #bfdbfe; }.danger-box { background: #fef2f2; border: 1px solid #fecaca; }.box-icon    { font-size: 18px; line-height: 1; flex-shrink: 0; margin-top: 2px; }.box-body    { font-size: 14px; line-height: 1.75; flex: 1; }.box-title   { font-weight: 700; margin-bottom: 4px; font-size: 13px; }.box-content { margin: 0; }.tip-box    .box-title   { color: #047857; }.tip-box    .box-content { color: #065f46; }.warn-box   .box-title   { color: #b45309; }.warn-box   .box-content { color: #92400e; }.info-box   .box-title   { color: #2563eb; }.info-box   .box-content { color: #1e40af; }.danger-box .box-title   { color: #b91c1c; }.danger-box .box-content { color: #991b1b; }/* ── 07 비교 표 ── */.table-wrap { overflow-x: auto; margin: 1.25rem 0; }.blog-table { width: 100%; border-collapse: collapse; font-size: 14px; }.blog-table thead tr { background: #0f172a; color: #fff; }.blog-table thead th { padding: 11px 16px; text-align: left; font-weight: 500; font-size: 13px; }.blog-table tbody tr { border-bottom: 1px solid #e2e8f0; }.blog-table tbody tr:last-child { border-bottom: none; }.blog-table tbody td { padding: 11px 16px; color: #334155; vertical-align: middle; }.blog-table tbody tr:nth-child(even) { background: #f8fafc; }.badge-green { display: inline-block; background: #ecfdf5; color: #047857; border: 1px solid #a7f3d0; border-radius: 20px; padding: 1px 10px; font-size: 12px; font-weight: 500; }.badge-red   { display: inline-block; background: #fef2f2; color: #b91c1c; border: 1px solid #fecaca; border-radius: 20px; padding: 1px 10px; font-size: 12px; font-weight: 500; }.badge-blue  { display: inline-block; background: #eff6ff; color: #2563eb; border: 1px solid #bfdbfe; border-radius: 20px; padding: 1px 10px; font-size: 12px; font-weight: 500; }.badge-amber { display: inline-block; background: #fffbeb; color: #b45309; border: 1px solid #fde68a; border-radius: 20px; padding: 1px 10px; font-size: 12px; font-weight: 500; }/* ── 08 문제 카드 ── */.problem-card { border: 1px solid #e2e8f0; border-radius: 10px; overflow: hidden; margin: 1.25rem 0; }.problem-card-header { background: #0f172a; color: #fff; padding: 12px 18px; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; }.prob-num   { font-size: 12px; color: #64748b; font-family: 'JetBrains Mono', monospace; }.prob-title { font-size: 15px; font-weight: 600; margin-top: 2px; }.prob-meta  { font-size: 12px; color: #64748b; text-align: right; line-height: 1.6; }.diff-gold   { color: #fbbf24; }.diff-silver { color: #94a3b8; }.diff-bronze { color: #d97706; }.diff-green  { color: #4ade80; }.problem-card-body { padding: 1.25rem 1.5rem; }.problem-card-body p { font-size: 14px; color: #334155; margin-bottom: 0.75rem; line-height: 1.75; }.prob-sub { font-size: 16px; font-weight: 600; color: #0f172a; margin: 1rem 0 0.6rem; padding-left: 12px; border-left: 3px solid #2563eb; }.step-list { padding-left: 0; list-style: none; counter-reset: steps; }.step-list li { counter-increment: steps; padding: 8px 0 8px 2.5rem; border-bottom: 1px dashed #e2e8f0; font-size: 14px; color: #334155; position: relative; line-height: 1.7; }.step-list li:last-child { border-bottom: none; }.step-list li::before { content: counter(steps); position: absolute; left: 0; top: 9px; display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; background: #2563eb; color: #fff; border-radius: 50%; font-size: 11px; font-weight: 700; }/* ── 포스트 푸터 ── */.post-footer { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid #e2e8f0; font-size: 13px; color: #94a3b8; text-align: center; line-height: 2; }&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;투 포인터로 O(N) 풀이&lt;/b&gt; &amp;mdash; 수열 길이가 최대 100만이라 O(N&amp;sup2;) 완전 탐색은 시간 초과. left/right 두 포인터로 윈도우를 늘렸다 줄였다 하며 한 번만 훑습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성립 근거는 단조성&lt;/b&gt; &amp;mdash; 모든 원소가 1 이상(양수)이라 right를 밀면 합이 반드시 커지고 left를 밀면 반드시 작아집니다. 이 성질 덕분에 각 상황에서 취할 행동이 하나로 정해집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동점 처리는 부등호 하나로&lt;/b&gt; &amp;mdash; &quot;길이가 같으면 시작 인덱스가 작은 것&quot; 조건은 탐색 방향(왼쪽&amp;rarr;오른쪽)과 엄격한 부등호(&lt;code&gt;&amp;lt;&lt;/code&gt;)의 조합으로 자연스럽게 해결됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 목차: h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/p&gt;
&lt;nav class=&quot;my-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; 문제 소개&lt;/h2&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;Programmers #178870&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;연속된 부분 수열의 합&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;수열 길이 &amp;le; 1,000,000 &amp;middot; 원소 1~1,000 &amp;middot; k &amp;le; 10억&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-green&quot;&gt;Programmers Lv.2&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비내림차순으로 정렬된 수열 &lt;code&gt;sequence&lt;/code&gt;와 정수 &lt;code&gt;k&lt;/code&gt;가 주어질 때, 원소의 합이 &lt;code&gt;k&lt;/code&gt;인 &lt;b&gt;연속된 부분 수열&lt;/b&gt;을 찾아 &lt;code&gt;[시작 인덱스, 끝 인덱스]&lt;/code&gt;를 반환하는 문제입니다. 조건을 만족하는 수열이 여러 개라면 &lt;b&gt;길이가 가장 짧은 것&lt;/b&gt;, 길이도 같다면 &lt;b&gt;시작 인덱스가 가장 작은 것&lt;/b&gt;을 골라야 합니다. (합이 k인 부분 수열은 항상 존재한다고 보장됩니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;code&gt;sequence = [1, 2, 3, 4, 5]&lt;/code&gt;, &lt;code&gt;k = 7&lt;/code&gt;이면 합이 7인 구간은 &lt;code&gt;[3, 4]&lt;/code&gt;(인덱스 2~3) 하나뿐이므로 답은 &lt;code&gt;[2, 3]&lt;/code&gt;입니다. &lt;code&gt;sequence = [2, 2, 2, 2, 2]&lt;/code&gt;, &lt;code&gt;k = 6&lt;/code&gt;이면 합이 6인 구간이 세 개인데 길이가 모두 3으로 같으므로, 시작 인덱스가 가장 작은 &lt;code&gt;[0, 2]&lt;/code&gt;가 답입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; 접근 방법&lt;/h2&gt;
&lt;h3 id=&quot;section2-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;제한 조건에서 출발하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 확인한 것은 수열의 길이입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 100만이므로, 모든 시작/끝 인덱스 쌍을 시도하는 O(N&amp;sup2;) 완전 탐색은 최악의 경우 약 5,000억 번 연산이 되어 시간 초과를 피할 수 없습니다. O(N) 또는 O(N log N) 수준의 풀이가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 눈에 들어온 것은 &lt;b&gt;원소가 전부 1 이상의 양수&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;b&gt;단조성&lt;/b&gt;이 보장되기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단조성이 성립하면 투 포인터(가변 크기 윈도우)를 쓸 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;section2-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;투 포인터의 동작&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left와 right 두 포인터로 구간 &lt;code&gt;[left, right]&lt;/code&gt;를 관리하면서, 매 순간 합과 k를 비교해 행동을 결정합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;합이 k보다 &lt;b&gt;작으면&lt;/b&gt; &amp;rarr; right를 오른쪽으로 밀어 구간을 &lt;b&gt;늘린다&lt;/b&gt; (합 증가)&lt;/li&gt;
&lt;li&gt;합이 k보다 &lt;b&gt;크면&lt;/b&gt; &amp;rarr; left를 오른쪽으로 밀어 구간을 &lt;b&gt;줄인다&lt;/b&gt; (합 감소)&lt;/li&gt;
&lt;li&gt;합이 k와 &lt;b&gt;같으면&lt;/b&gt; &amp;rarr; 정답 후보로 기록한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단조성 덕분에 각 상황에서 취할 행동이 하나로 정해지고, 두 포인터 모두 뒤로 돌아가는 일 없이 각자 최대 N번만 전진하므로 전체 시간 복잡도는 &lt;b&gt;O(N)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;0이나 음수가 섞여 있었다면?&lt;/div&gt;
구간을 늘렸는데 합이 그대로거나 오히려 줄어드는 상황이 생겨 단조성이 깨지고, 투 포인터로는 놓치는 구간이 발생합니다. 이 문제는 원소가 전부 양수라서 가능한 풀이라는 점을 유의해야합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; Java 코드&lt;/h2&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&lt;span class=&quot;cdot cdot-r&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;cdot cdot-y&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;cdot cdot-g&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; Solution.java (투 포인터, O(N))&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;class Solution {
    public int[] solution(int[] sequence, int k) {
        int[] answer = new int[2];
        long total = 0;                       // 현재 구간의 합
        int left = 0;                        // 구간의 왼쪽 끝
        int minLength = Integer.MAX_VALUE;   // 지금까지 찾은 최소 길이

        for (int right = 0; right &amp;lt; sequence.length; right++) {
            // 1. 오른쪽 끝을 한 칸 확장
            total += sequence[right];

            // 2. 합이 k를 초과하면 왼쪽 끝을 밀어서 구간을 줄인다
            while (total &amp;gt; k) {
                total -= sequence[left];
                left++;
            }

            // 3. 합이 정확히 k인 구간 발견 &amp;rarr; 더 짧을 때만 갱신
            if (total == k) {
                int currentLength = right - left + 1;
                if (currentLength &amp;lt; minLength) {
                    minLength = currentLength;
                    answer[0] = left;
                    answer[1] = right;
                }
            }
        }

        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; 놓치기 쉬운 포인트&lt;/h2&gt;
&lt;div class=&quot;tip-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;동점 처리는 부등호 하나로 끝난다&lt;/div&gt;
right가 왼쪽에서 오른쪽으로 진행하므로, 같은 길이의 구간이라면 &lt;b&gt;시작 인덱스가 작은 쪽이 항상 먼저 발견&lt;/b&gt;됩니다. 갱신 조건을 &lt;code&gt;currentLength &amp;lt; minLength&lt;/code&gt;처럼 &lt;b&gt;등호 없는 엄격한 부등호&lt;/b&gt;로 두면, 나중에 나온 같은 길이 구간이 앞의 답을 덮어쓰지 못합니다. 만약 &lt;code&gt;&amp;lt;=&lt;/code&gt;로 썼다면 뒤쪽 구간으로 덮어써서 오답이 됩니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;&quot;total == k일 때 left를 더 안 밀어도 되나?&quot;&lt;/div&gt;
저도 처음에 잠깐 헷갈렸던 부분인데, 원소가 전부 양수라서 &lt;code&gt;total == k&lt;/code&gt;인 상태에서 left를 밀면 합이 무조건 k 미만으로 떨어집니다. 즉 현재 right에서 합이 k가 되는 구간은 &lt;b&gt;지금 그 하나뿐&lt;/b&gt;이므로 추가 탐색이 필요 없습니다.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;누적 합 변수는 범위 계산부터&lt;/div&gt;
while문 덕분에 매 반복이 끝나면 &lt;code&gt;total &amp;le; k&lt;/code&gt;가 보장되고, 다음 원소를 더해도 최대 k + 1,000 &amp;asymp; 10억 + 1,000이라 사실 &lt;code&gt;int&lt;/code&gt; 범위(약 21.4억) 안입니다. 다만 k가 조금만 더 컸다면 오버플로가 나는 아슬아슬한 코드였습니다. 누적 합 변수는 &lt;b&gt;일단 최대값부터 계산해 보고, 애매하면 long&lt;/b&gt;을 쓰는 습관을 들이는 것이 안전합니다.&lt;/div&gt;
&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/투 포인터(two pointer)</category>
      <category>연속된 부분 수열의 합</category>
      <category>연속된 부분 수열의 합 자바</category>
      <category>투포인터</category>
      <category>프로그래머스</category>
      <category>프로그래머스 연속된 부분 수열의 합</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/195</guid>
      <comments>https://minsu092274.tistory.com/195#entry195comment</comments>
      <pubDate>Mon, 6 Jul 2026 16:04:54 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 전력망을 둘로 나누기 (Java) &amp;mdash; BFS</title>
      <link>https://minsu092274.tistory.com/194</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- ================================================
     [Programmers Lv.2] 전력망을 둘로 나누기 — BFS 완전탐색 (Java)
     design.html 템플릿 기반 / 티스토리 HTML 모드에 붙여넣기
     ================================================ --&gt;&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;family=JetBrains+Mono:wght@400;600&amp;display=swap');/* ── 공통 ── */.blog-post{font-family:'Noto Sans KR',sans-serif;color:#334155;line-height:1.8;font-size:15px;max-width:780px;margin:0 auto;padding:2rem 0;}.blog-post p{margin-bottom:1rem;}.blog-post strong{color:#0f172a;}.blog-post ul,.blog-post ol{padding-left:1.5rem;margin-bottom:1rem;}.blog-post li{margin:5px 0;font-size:14px;}.blog-post code{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:4px;padding:1px 6px;color:#c7254e;}.blog-post hr{border:none;border-top:1px solid #e2e8f0;margin:2.5rem 0;}/* ── 01 포스트 헤더 ── */.post-header{margin-bottom:2.5rem;padding-bottom:2rem;border-bottom:1px solid #e2e8f0;}.post-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:1rem;}.tag{font-size:12px;padding:3px 12px;border-radius:20px;font-weight:500;}.tag-blue  {background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}.tag-green {background:#ecfdf5;color:#059669;border:1px solid #a7f3d0;}.tag-amber {background:#fffbeb;color:#b45309;border:1px solid #fde68a;}.tag-red   {background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;}.tag-gray  {background:#f1f5f9;color:#475569;border:1px solid #e2e8f0;}.post-title{font-size:28px;font-weight:700;color:#0f172a;line-height:1.35;margin:0 0 0.75rem;letter-spacing:-0.3px;}.post-meta{font-size:13px;color:#94a3b8;display:flex;gap:16px;flex-wrap:wrap;}.post-meta .dot::before{content:'·';margin-right:6px;opacity:0.4;}/* ── 02 핵심 요약 박스 ── */.summary-box{background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:1.25rem 1.5rem;margin-bottom:2rem;}.summary-box .summary-label{font-size:12px;font-weight:700;color:#2563eb;letter-spacing:0.06em;margin-bottom:0.75rem;}.summary-box ul{padding-left:1.25rem;margin:0;}.summary-box li{font-size:14px;color:#334155;margin:5px 0;line-height:1.75;}.summary-box li strong{color:#0f172a;}/* ── 03 목차 (my-toc) ── */.my-toc{border-radius:12px;overflow:hidden;margin-bottom:2.5rem;border:1px solid #162d4a;}.my-toc-header{background:#1e3a5f;padding:16px 22px;display:flex;align-items:center;gap:10px;}.my-toc-header-bar{width:3px;height:22px;background:#93c5fd;border-radius:2px;flex-shrink:0;}.my-toc-header-text{font-size:17px;font-weight:700;color:#f1f5f9;}.my-toc-body{background:#f8fafc;padding:12px 16px 14px;}.my-toc-list{display:flex;flex-direction:column;gap:2px;}.my-toc-list&gt;div&gt;a{display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:8px;font-size:15px;font-weight:500;color:#1e3a5f;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-list&gt;div&gt;a:hover{background:#dbeafe;color:#1d4ed8;}.my-toc-list&gt;div&gt;a:hover .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-num{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-width:26px;background:#e2e8f0;color:#334155;border-radius:6px;font-size:13px;font-weight:700;flex-shrink:0;transition:background 0.15s,color 0.15s;}.my-toc-num.active{background:#1e3a5f;color:#fff;}.my-toc-list&gt;div&gt;a.my-toc-active{background:#dbeafe;color:#1e3a5f;}.my-toc-list&gt;div&gt;a.my-toc-active .my-toc-num{background:#1e3a5f;color:#fff;}.my-toc-sub{display:flex;flex-direction:column;gap:1px;padding:2px 0 4px 52px;}.my-toc-sub div a{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:6px;font-size:14px;color:#475569;text-decoration:none;transition:background 0.15s,color 0.15s;}.my-toc-sub div a::before{content:'';display:inline-block;width:5px;height:5px;min-width:5px;background:#94a3b8;border-radius:50%;flex-shrink:0;transition:background 0.15s;}.my-toc-sub div a:hover{background:#f1f5f9;color:#1e3a5f;}.my-toc-sub div a:hover::before{background:#1e3a5f;}.my-toc-sub div a.my-toc-active{color:#1e3a5f;}.my-toc-sub div a.my-toc-active::before{background:#1e3a5f;}/* ── 04 섹션 제목 (my-section) ── */.my-section{margin-bottom:3rem;}.my-section-title{font-size:20px;font-weight:700;color:#0f172a;margin-bottom:1rem;padding-bottom:0.5rem;border-bottom:2px solid #2563eb;display:flex;align-items:center;gap:10px;}.my-section-num{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;background:#2563eb;color:#fff;border-radius:50%;font-size:13px;font-weight:700;flex-shrink:0;}.my-sub-title{font-size:16px;font-weight:600;color:#0f172a;margin:1.5rem 0 0.75rem;padding-left:12px;border-left:3px solid #2563eb;}/* ── 05 코드 블록 ── */.code-wrap{margin:1.25rem 0;border-radius:10px;overflow:hidden;border:1px solid #1e293b;box-shadow:0 4px 16px rgba(15,23,42,0.12);}.code-header{background:#1e293b;padding:8px 16px;display:flex;align-items:center;justify-content:space-between;}.code-dots{display:flex;gap:6px;}.cdot{width:12px;height:12px;border-radius:50%;}.cdot-r{background:#ff5f57;}.cdot-y{background:#febc2e;}.cdot-g{background:#28c840;}.code-lang{font-size:11px;color:#64748b;font-family:'JetBrains Mono',monospace;letter-spacing:0.05em;}pre.code-body{background:#0d1117;padding:1.25rem 1.5rem;margin:0;overflow-x:auto;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.75;color:#cbd5e1;}.c-blue{color:#93c5fd;}.c-green{color:#4ade80;}.c-lime{color:#86efac;}.c-teal{color:#a5f3fc;}.c-purple{color:#f0abfc;}.c-cyan{color:#6ee7b7;}.c-yellow{color:#fde68a;}.c-gray{color:#475569;font-style:italic;}.c-base{color:#cbd5e1;}/* ── 06 강조 박스 ── */.tip-box,.warn-box,.info-box,.danger-box{border-radius:10px;padding:1rem 1.25rem;margin:1.25rem 0;display:flex;gap:12px;align-items:flex-start;}.tip-box   {background:#ecfdf5;border:1px solid #a7f3d0;}.warn-box  {background:#fffbeb;border:1px solid #fde68a;}.info-box  {background:#eff6ff;border:1px solid #bfdbfe;}.danger-box{background:#fef2f2;border:1px solid #fecaca;}.box-icon{font-size:18px;line-height:1;flex-shrink:0;margin-top:1px;}.box-body{font-size:14px;line-height:1.75;}.box-title{font-weight:700;margin-bottom:3px;font-size:13px;}.tip-box    .box-title{color:#047857;}.tip-box    .box-body{color:#065f46;}.warn-box   .box-title{color:#b45309;}.warn-box   .box-body{color:#92400e;}.info-box   .box-title{color:#2563eb;}.info-box   .box-body{color:#1e40af;}.danger-box .box-title{color:#b91c1c;}.danger-box .box-body{color:#991b1b;}/* ── 07 비교 표 ── */.table-wrap{overflow-x:auto;margin:1.25rem 0;}.blog-table{width:100%;border-collapse:collapse;font-size:14px;}.blog-table thead tr{background:#0f172a;color:#fff;}.blog-table thead th{padding:11px 16px;text-align:left;font-weight:500;font-size:13px;}.blog-table tbody tr{border-bottom:1px solid #e2e8f0;}.blog-table tbody tr:last-child{border-bottom:none;}.blog-table tbody td{padding:11px 16px;color:#334155;vertical-align:middle;}.blog-table tbody tr:nth-child(even){background:#f8fafc;}.badge-green{display:inline-block;background:#ecfdf5;color:#047857;border:1px solid #a7f3d0;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-red  {display:inline-block;background:#fef2f2;color:#b91c1c;border:1px solid #fecaca;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-blue {display:inline-block;background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}.badge-amber{display:inline-block;background:#fffbeb;color:#b45309;border:1px solid #fde68a;border-radius:20px;padding:1px 10px;font-size:12px;font-weight:500;}/* ── 08 문제 카드 ── */.problem-card{border:1px solid #e2e8f0;border-radius:10px;overflow:hidden;margin:1.25rem 0;}.problem-card-header{background:#0f172a;color:#fff;padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;}.prob-num{font-size:12px;color:#64748b;font-family:'JetBrains Mono',monospace;}.prob-title{font-size:15px;font-weight:600;margin-top:2px;}.prob-meta{font-size:12px;color:#64748b;text-align:right;line-height:1.6;}.diff-gold{color:#fbbf24;}.diff-silver{color:#94a3b8;}.diff-bronze{color:#d97706;}.diff-green{color:#4ade80;}.problem-card-body{padding:1.25rem 1.5rem;}.problem-card-body p{font-size:14px;color:#334155;margin-bottom:0.75rem;line-height:1.75;}.prob-sub{font-size:16px;font-weight:600;color:#0f172a;margin:1rem 0 0.6rem;padding-left:12px;border-left:3px solid #2563eb;}.step-list{padding-left:0;list-style:none;counter-reset:steps;}.step-list li{counter-increment:steps;padding:8px 0 8px 2.5rem;border-bottom:1px dashed #e2e8f0;font-size:14px;color:#334155;position:relative;line-height:1.7;}.step-list li:last-child{border-bottom:none;}.step-list li::before{content:counter(steps);position:absolute;left:0;top:9px;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;background:#2563eb;color:#fff;border-radius:50%;font-size:11px;font-weight:700;}/* ── 포스트 푸터 ── */.post-footer{margin-top:3rem;padding-top:1.5rem;border-top:1px solid #e2e8f0;font-size:13px;color:#94a3b8;text-align:center;line-height:2;}&lt;/style&gt;
&lt;/div&gt;
&lt;div class=&quot;summary-box&quot;&gt;
&lt;div class=&quot;summary-label&quot;&gt;  핵심 요약&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;트리의 성질&lt;/b&gt; &amp;mdash; 노드 n개, 간선 n-1개면 트리. 간선 하나를 끊으면 &lt;b&gt;정확히 두 개&lt;/b&gt;의 컴포넌트로 갈라진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;완전탐색으로 충분&lt;/b&gt; &amp;mdash; n &amp;le; 100이라 간선 99개를 전부 끊어봐도 여유롭게 통과한다. 그리디하게 고민할 필요가 없다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한쪽만 세면 끝&lt;/b&gt; &amp;mdash; 한쪽 크기가 &lt;code&gt;count&lt;/code&gt;면 반대쪽은 &lt;code&gt;n - count&lt;/code&gt;. 차이는 &lt;code&gt;Math.abs(count - (n - count))&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트리라서 가능한 단순화&lt;/b&gt; &amp;mdash; 간선을 끊는 대신 &lt;b&gt;반대편 노드 하나를 차단&lt;/b&gt;하는 것으로 같은 효과를 낼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;nav class=&quot;my-toc&quot;&gt;
&lt;div class=&quot;my-toc-header&quot;&gt;
&lt;div class=&quot;my-toc-header-bar&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;my-toc-header-text&quot;&gt;목차&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;my-toc-body&quot;&gt;&lt;!-- h2/h3 태그를 읽어 자동 생성됩니다 --&gt;&lt;/div&gt;
&lt;/nav&gt;
&lt;h2 id=&quot;section1&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;1&lt;/span&gt; 문제 소개&lt;/h2&gt;
&lt;div class=&quot;problem-card&quot;&gt;
&lt;div class=&quot;problem-card-header&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;prob-num&quot;&gt;Programmers #86971&lt;/div&gt;
&lt;div class=&quot;prob-title&quot;&gt;전력망을 둘로 나누기&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;prob-meta&quot;&gt;
&lt;div&gt;2 &amp;le; n &amp;le; 100 &amp;middot; 간선 n-1개&lt;/div&gt;
&lt;div&gt;난이도: &lt;span class=&quot;diff-green&quot;&gt;Lv.2&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;problem-card-body&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n개의 송전탑이 전선을 통해 하나의 &lt;b&gt;트리 형태&lt;/b&gt;로 연결되어 있다. 전선 중 하나를 끊어 전력망을 2개로 분할하려고 한다. 이때 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고, 그 &lt;b&gt;개수 차이(절댓값)&lt;/b&gt;를 반환하는 문제다.&lt;/p&gt;
&lt;div class=&quot;prob-sub&quot;&gt;풀이 과정&lt;/div&gt;
&lt;ol class=&quot;step-list&quot; style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;wires 배열로 양방향 인접 리스트를 만든다.&lt;/li&gt;
&lt;li&gt;간선을 하나씩 &quot;끊었다고 가정&quot;하며 전부 시도한다 (완전탐색).&lt;/li&gt;
&lt;li&gt;끊은 간선의 한쪽 끝에서 BFS를 돌려 그쪽 컴포넌트의 크기 &lt;code&gt;count&lt;/code&gt;를 센다. 이때 반대편 노드를 차단해 간선을 끊은 효과를 낸다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Math.abs(count - (n - count))&lt;/code&gt;로 두 그룹의 차이를 구하고 최솟값을 갱신한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section2&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;2&lt;/span&gt; 접근 아이디어&lt;/h2&gt;
&lt;h3 id=&quot;section2-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;노드 n개 + 간선 n-1개 = 트리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 읽고 처음 눈에 들어온 건 &quot;송전탑 n개, 전선 n-1개&quot;라는 조건이었다. 이건 그래프 이론에서 아주 특별한 형태, 바로 &lt;b&gt;트리&lt;/b&gt;라는 뜻이다. 사이클이 없는 연결 그래프이기 때문에, 트리에서 간선 하나를 끊으면 &lt;b&gt;정확히 두 개의 덩어리로 갈라진다는 게 보장&lt;/b&gt;된다.&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;section2-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;완전탐색으로 충분한 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n이 최대 100이므로 간선은 최대 99개다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;간선을 하나씩 끊어보고 &amp;rarr; 매번 결과를 확인&quot;하는 완전탐색을 해도 간선 99개 &amp;times; 탐색 O(n) 수준이라 시간은 전혀 문제가 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 간선을 끊어야 유리할지 그리디하게 고민할 필요 없이, &lt;b&gt;전부 끊어보면 된다&lt;/b&gt;.&lt;/p&gt;
&lt;h3 id=&quot;section2-3&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;한쪽 크기만 세면 반대쪽은 공짜&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체가 n개인데 한쪽이 &lt;code&gt;count&lt;/code&gt;개라면, 나머지는 자동으로 &lt;code&gt;n - count&lt;/code&gt;개다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 BFS는 한 번만 돌리면 되고, 두 그룹의 차이는 아래 한 줄로 정리된다.&lt;/p&gt;
&lt;div class=&quot;info-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;ℹ️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;차이 계산과 Math.abs가 필요한 이유&lt;/div&gt;
&lt;code&gt;count - (n - count)&lt;/code&gt;는 count가 작은 쪽 덩어리인지 큰 쪽 덩어리인지에 따라 음수가 될 수 있다. 문제가 원하는 건 부호 없는 &quot;차이&quot;이므로 &lt;code&gt;Math.abs&lt;/code&gt;로 절댓값을 씌운다. 이게 없으면 음수 diff가 &lt;code&gt;Math.min&lt;/code&gt;에서 부당하게 이겨버려 답이 망가진다.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section3&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;3&lt;/span&gt; BFS 설계 &amp;mdash; 간선 대신 노드를 차단하기&lt;/h2&gt;
&lt;h3 id=&quot;section3-1&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;트리라서 가능한 단순화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;간선 (a, b)를 끊는다&quot;를 구현하는 가장 정직한 방법은 BFS 중에 a&amp;rarr;b, b&amp;rarr;a 양방향 이동을 모두 검사해서 막는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 트리에서는 더 단순한 방법이 있다. a에서 출발하는 BFS가 b 쪽 덩어리로 건너가는 통로는 &lt;b&gt;그 간선 하나뿐&lt;/b&gt;이므로, &lt;b&gt;&quot;b 노드 자체를 밟지 않는다&quot;&lt;/b&gt;는 조건 하나로 간선을 끊은 것과 완전히 같은 효과가 난다.&lt;/p&gt;
&lt;div class=&quot;warn-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt;⚠️&lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;이 단순화는 트리에서만 성립한다&lt;/div&gt;
사이클이 있는 일반 그래프라면 b로 우회해서 도달하는 다른 경로가 존재할 수 있다. 그 경우 노드 차단은 간선 차단보다 더 많은 것을 막아버려 결과가 달라진다. 일반 그래프 문제에서는 간선 쌍(a, b)을 양방향으로 검사하는 방식을 써야 안전하다.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&quot;section3-2&quot; class=&quot;my-sub-title&quot; data-ke-size=&quot;size23&quot;&gt;BFS의 핵심: 확인 &amp;rarr; 도장 &amp;rarr; 예약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS에서 큐에 넣는다는 건 &quot;나중에 방문할 것을 예약한다&quot;는 뜻이다. 그래서 &lt;code&gt;visited&lt;/code&gt;의 실제 의미는 &quot;방문 완료&quot;가 아니라 &lt;b&gt;&quot;큐에 들어간 적 있음(예약됨)&quot;&lt;/b&gt;이고, 도장은 큐에 넣는 시점에 찍어야 한다. 순서는 항상 이 세 동작이 한 세트다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;확인&lt;/b&gt; &amp;mdash; &lt;code&gt;!visited[next]&lt;/code&gt; 아직 예약 안 된 노드인지 검사한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도장&lt;/b&gt; &amp;mdash; &lt;code&gt;visited[next] = true&lt;/code&gt; 즉시 예약됨 표시를 남긴다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예약&lt;/b&gt; &amp;mdash; &lt;code&gt;queue.add(next)&lt;/code&gt; 그 다음에 큐에 넣는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;danger-box&quot;&gt;&lt;span class=&quot;box-icon&quot;&gt; &lt;/span&gt;
&lt;div class=&quot;box-body&quot;&gt;
&lt;div class=&quot;box-title&quot;&gt;직접 겪은 실수: 방문 확인을 빼먹으면 무한 루프&lt;/div&gt;
처음 작성한 코드에서 &lt;code&gt;visited[next] = true&lt;/code&gt;로 표시는 했지만 넣기 전에 &lt;b&gt;이미 방문한 노드인지 확인을 안 했다&lt;/b&gt;. 양방향 그래프에서는 노드 1과 2가 서로를 계속 다시 큐에 넣는 핑퐁이 벌어져서, count가 틀리는 정도가 아니라 while문이 영원히 끝나지 않는다. 표시만 하고 확인을 안 하면 표시가 아무 역할을 못 한다는 걸 몸으로 배웠다.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section4&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;4&lt;/span&gt; 전체 코드 (Java)&lt;/h2&gt;
&lt;div class=&quot;code-wrap&quot;&gt;
&lt;div class=&quot;code-header&quot;&gt;
&lt;div class=&quot;code-dots&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;span class=&quot;code-lang&quot;&gt;Java &amp;mdash; Solution.java&lt;/span&gt;&lt;/div&gt;
&lt;pre class=&quot;code-body arduino&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {

    // 여러 메서드에서 함께 쓰기 위해 필드로 선언
    private List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; graph;

    public int solution(int n, int[][] wires) {
        int answer = n; // 어떤 diff도 n 이상이 될 수 없으므로 n으로 초기화

        // 1. 인접 리스트 구성 (인덱스 = 노드 번호, 0번은 버림 칸)
        graph = new ArrayList&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt;= n; i++) {
            graph.add(new ArrayList&amp;lt;&amp;gt;());
        }
        for (int[] wire : wires) {
            graph.get(wire[0]).add(wire[1]);
            graph.get(wire[1]).add(wire[0]); // 무방향이므로 양방향 등록
        }

        // 2. 간선을 하나씩 끊어보며 완전탐색
        for (int[] wire : wires) {
            // wire[0]에서 시작, wire[1] 노드를 차단
            int count = bfs(wire[0], wire[1], n);

            // 3. 두 그룹의 크기 차이로 최솟값 갱신
            int diff = Math.abs(count - (n - count));
            answer = Math.min(answer, diff);
        }

        return answer;
    }

    // start에서 출발하되 blocked 노드로는 이동하지 않는 BFS
    private int bfs(int start, int blocked, int n) {
        boolean[] visited = new boolean[n + 1];
        Queue&amp;lt;Integer&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();

        // 4. 시작 노드를 예약(큐 삽입)하고 도장 찍기
        queue.add(start);
        visited[start] = true;
        int count = 0;

        while (!queue.isEmpty()) {
            int cur = queue.poll();
            count++;

            for (int next : graph.get(cur)) {
                // 5. 차단 노드이거나 이미 예약된 노드면 패스
                if (next == blocked || visited[next]) continue;

                visited[next] = true;
                queue.add(next);
            }
        }

        // 6. start 쪽 컴포넌트의 크기 반환
        return count;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&quot;section5&quot; class=&quot;my-section-title&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span class=&quot;my-section-num&quot;&gt;5&lt;/span&gt; 시간복잡도&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS 한 번은 노드와 간선을 모두 훑으므로 O(V+E) = O(n)이고, 전체는 O(n&amp;sup2;)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n &amp;le; 100이므로 최악에도 1만 번 수준의 연산이라 아주 여유롭다.&lt;/p&gt;
&lt;div class=&quot;table-wrap&quot;&gt;
&lt;table class=&quot;blog-table&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;연산&lt;/th&gt;
&lt;th&gt;복잡도&lt;/th&gt;
&lt;th&gt;비고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;그래프 구성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;간선 n-1개를 양방향 등록&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-blue&quot;&gt;1회&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;BFS 1회&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;컴포넌트 크기 세기&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;여유&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;전체&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;간선 수 &amp;times; BFS&lt;/td&gt;
&lt;td&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;badge-green&quot;&gt;n &amp;le; 100이라 충분&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.8837%; height: 22px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 22px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;잘못된 내용&lt;/span&gt;이 있다면&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;지적&lt;/span&gt;부탁드립니다. 방문해주셔서 감사합니다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;055&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/055.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/BFS (너비 우선 탐색)</category>
      <category>전력망을 둘로 나누기</category>
      <category>전력망을 둘로 나누기 자바</category>
      <category>프로그래머스</category>
      <category>프로그래머스 전력망을 둘로 나누기</category>
      <author>곱마2</author>
      <guid isPermaLink="true">https://minsu092274.tistory.com/194</guid>
      <comments>https://minsu092274.tistory.com/194#entry194comment</comments>
      <pubDate>Fri, 3 Jul 2026 16:19:46 +0900</pubDate>
    </item>
  </channel>
</rss>