<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Binary Journey</title>
    <link>https://binaryjourney.tistory.com/</link>
    <description>Cruella Dev L's Blog</description>
    <language>ko</language>
    <pubDate>Mon, 24 Aug 2026 01:53:37 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>binaryJournalist</managingEditor>
    <image>
      <title>Binary Journey</title>
      <url>https://tistory1.daumcdn.net/tistory/4022385/attach/caa5fecd03be42aba856c9ddcdcf7f44</url>
      <link>https://binaryjourney.tistory.com</link>
    </image>
    <item>
      <title>그래프 -  너비 우선 탐색 순회</title>
      <link>https://binaryjourney.tistory.com/344</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래프(Graph)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프는 &lt;b&gt;정점(Node)&lt;/b&gt; 과 이 정점들을 연결하는 &lt;b&gt;간선(Edge)&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;정점(Node)&lt;/b&gt;: 각각의 지점 또는 데이터를 표현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간선(Edge)&lt;/b&gt;: 정점 간의 연결 관계를 표현&lt;/li&gt;
&lt;/ul&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;무방향 그래프(Undirected Graph)&lt;/b&gt;: 간선에 방향성이 없는 그래프&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방향 그래프(Directed Graph)&lt;/b&gt;: 간선에 방향이 있는 그래프&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 너비 우선 탐색을 할 때는 무방향 또는 방향 모두 가능하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래프 탐색이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프 탐색은 그래프 내의 정점들을 방문하는 알고리즘이다. 주로 사용하는 두 가지 탐색 방식이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;깊이 우선 탐색(Depth-First Search, DFS)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가능한 한 깊이 들어가며 탐색 후 끝에서부터 돌아와 다른 길 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;너비 우선 탐색(Breadth-First Search, BFS)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시작 정점과 가까운 정점부터 차례대로 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;너비 우선 탐색(BFS)의 개념 및 특징&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너비 우선 탐색(BFS)는 &lt;b&gt;큐(Queue)&lt;/b&gt; 라는 자료구조를 사용해 탐색한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;큐&lt;/b&gt;는 &lt;b&gt;먼저 들어간 데이터가 먼저 나오는&lt;/b&gt;(FIFO, First-In-First-Out) 구조를 가진 자료 구조이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;시작 노드를 방문하고 큐에 넣는다.&lt;/li&gt;
&lt;li&gt;큐에서 노드를 하나씩 꺼내면서 꺼낸 노드와 인접한 노드 중 방문하지 않은 노드를 방문하고 큐에 넣는다.&lt;/li&gt;
&lt;li&gt;큐가 빌 때까지 반복한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS는 &lt;b&gt;시작 노드와 가까운 순서대로&lt;/b&gt; 탐색한다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.velog.io/images/polynomeer/post/b8af5260-1a7d-4ebf-8d45-900c0c818ffc/2020-03-30_18-35-52.gif&quot; alt=&quot;bfs&quot; /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;출처: &lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://images.velog.io/images/polynomeer&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://images.velog.io/images/polynomeer&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;너비 우선 탐색(BFS)의 장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최단 경로를 찾을 때 유용하게 사용된다.&lt;/li&gt;
&lt;li&gt;가까운 노드부터 단계별 탐색하기 때문에 모든 노드 방문 여부나 연결 요소 확인에도 사용이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 35: 너비 우선 탐색 순회&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;너비 우선 탐색으로 모든 노드를 순회하는 &lt;code&gt;함수 solution()&lt;/code&gt;을 작성하세요. 시작 노드는 매개변수 start로 주어집니다. graph는 (출발 노드, 도착 노드) 쌍들이 들어 있는 리스트입니다. 반환값은 그래프의 시작 노드부터 모든 노드를 너비 우선 탐색으로 진행한 순서대로 노드가 저장된 리스트 입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 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;노드의 최대 개수는 100개입니다.&lt;/li&gt;
&lt;li&gt;시작 노드부터 시작해서 모든 노드를 방문할 수 있는 경로가 항상 있습니다.&lt;/li&gt;
&lt;li&gt;그래프의 노드는 숫자입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;입출력의 예&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;graph&lt;/th&gt;
&lt;th&gt;start&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;return&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[[1, 2], [1, 3], [2, 4], (2, 5], [3, 6], [3, 7J, [4, 81, [5, 81, [6, 9, [7, 9]]&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;[1, 2, 3, 4, 5, 6, 7, 8, 91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[[1, 3], [3, 4], [3, 5], [5, 2]]&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;[1, 3, 4, 5, 2)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 이 문제는 탐색 순서에 따라 정답이 여러 개일 수 있습니다&lt;/p&gt;
&lt;h3 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;주어진 시작 노드에서 BFS를 수행하여 그래프의 모든 노드를 방문하고 노드 방문 순서를 반환해야 한다.&lt;/li&gt;
&lt;li&gt;입력으로는 그래프를 구성하는 노드 쌍(간선)과 시작 노드(start)가 주어진다. &lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.ArrayDeque;
import java.util.ArrayList;

class Solution {
    // 인접 리스트를 저장하는 ArrayList 배열
    // 각 노드의 인접한 노드 목록을 저장한다.
    private static ArrayList&amp;lt;Integer&amp;gt;[] adjList;

    // 방문 여부를 저장할 boolean 배열
    // 노드를 방문하면 해당 인덱스를 true로 변경
    // 한 번 방문한 노드를 체크해서 다시 방문하지 않도록 함
    private static boolean[] visited;

    // 방문한 노드의 순서를 저장하는 리스트
    private static ArrayList&amp;lt;Integer&amp;gt; answer;

    private static int[] solution(int[][] graph, int start, int n) {
        // 1. 그래프 초기화
        adjList = new ArrayList[n + 1];
        for (int i = 0; i &amp;lt; adjList. length; i++) {
            // 각 노드마다 빈 ArrayList 생성
            adjList[i] = new ArrayList&amp;lt;&amp;gt;();
        }
        for (int[] edge : graph) {
            // 각 노드의 연결 상태 표현
            adjList[edge[0]].add(edge[1]);
        }
        // edge = [1, 2]  &amp;rarr; adjList[1].add(2)
        // edge = [1, 3]  &amp;rarr; adjList[1].add(3)
        // edge = [2, 4]  &amp;rarr; adjList[2].add(4)
        // edge = [3, 5]  &amp;rarr; adjList[3].add(5)
        // edge = [4, 5]  &amp;rarr; adjList[4].add(5)

        // adjList[1] &amp;rarr; [2, 3]
        // adjList[2] &amp;rarr; [4]
        // adjList[3] &amp;rarr; [5]
        // adjList[4] &amp;rarr; [5]
        // adjList[5] &amp;rarr; []

        // 2. 방문 목록 초기화
        visited = new boolean[n + 1];
        answer = new ArrayList&amp;lt;&amp;gt;();

        // 3. 시작 노드에서 너비 우선 탐색 시작
        bfs(start);

        // 4. 결과 리턴
        return answer.stream().mapToInt(Integer::intValue).toArray();
    }

    // bfs
    private static void bfs(int start) {
        // 탐색 순서를 관리하는 큐
        ArrayDeque&amp;lt;Integer&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();
        queue.add(start);
        visited[start] = true;

        while (!queue.isEmpty()) {
            // 큐에서 노드를 꺼내 방문 순서에 추가
            int now = queue.poll();
            answer.add(now);

            // 인접한 노드가 존재 시 방문 + 큐에 추가
            for (int next : adjList[now]) {
                if (!visited[next]) {
                    queue.add(next);
                    visited[next] = true;
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너비 우선 탐색(BFS, Breadth-First Search)은 &lt;b&gt;1959년에 Edward F. Moore&lt;/b&gt;가 처음으로 공식적으로 제안했어.&lt;/p&gt;
&lt;h3 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;b&gt;Edward F. Moore (에드워드 F. 무어)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;미국의 수학자 겸 컴퓨터 과학자&lt;/li&gt;
&lt;li&gt;1959년에 너비 우선 탐색을 소개&lt;/li&gt;
&lt;li&gt;본래 목적은 미로(maze)에서 최단 경로를 찾기 위한 알고리즘을 제시하기 위함이었어.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시 무어는 전자회로의 논리 설계 및 경로 찾기 문제를 해결하기 위해 이 알고리즘을 처음 고안했는데, 이것이 오늘날 우리가 쓰는 &lt;b&gt;BFS의 시초&lt;/b&gt;가 되었어.&lt;/p&gt;
&lt;h3 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;b&gt;&quot;The shortest path through a maze&quot;&lt;/b&gt; (미로에서 최단 경로 찾기, 1959)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;미로 문제를 해결하기 위한 알고리즘으로 BFS 소개&lt;/li&gt;
&lt;li&gt;각 지점에서 가까운 노드를 순차적으로 탐색하는 방식이었어.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  왜 BFS를 만들었을까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시 컴퓨터 과학 초창기엔 효율적인 최단 경로 탐색 알고리즘이 필요했어.&lt;br /&gt;미로나 그래프 같은 구조에서 최단 경로를 빠르게 찾는 문제가 흔히 발생했고, BFS는 이러한 문제를 해결하기 위한 효과적인 접근법이었지.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  BFS의 현재 중요성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘날 BFS는 다음과 같은 다양한 문제에 폭넓게 쓰이고 있어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최단 경로 찾기&lt;/li&gt;
&lt;li&gt;네트워크나 그래프에서 가까운 노드 탐색&lt;/li&gt;
&lt;li&gt;웹 크롤러(인터넷에서 링크를 따라 페이지를 탐색하는 프로그램)&lt;/li&gt;
&lt;li&gt;소셜 네트워크 분석(가까운 친구, 추천 친구 찾기 등)&lt;/li&gt;
&lt;li&gt;미로 문제, 퍼즐 등 게임의 경로 탐색&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>그래프</category>
      <category>너비우선탐색순회</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/344</guid>
      <comments>https://binaryjourney.tistory.com/344#entry344comment</comments>
      <pubDate>Sun, 20 Apr 2025 10:22:09 +0900</pubDate>
    </item>
    <item>
      <title>프로그램은 어떻게 실행될까 - 1</title>
      <link>https://binaryjourney.tistory.com/343</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고도서: &lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000212650856?utm_source=google&amp;amp;utm_medium=cpc&amp;amp;utm_campaign=googleSearch&amp;amp;gt_network=g&amp;amp;gt_keyword=&amp;amp;gt_target_id=dsa-604712360775&amp;amp;gt_campaign_id=9979905549&amp;amp;gt_adgroup_id=132556570510&amp;amp;gad_source=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;컴퓨터 밑바닥의 비밀&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;프로그램의 실행 원리&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로그램 카운터(PC)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 실행할 명령어의 메모리 주소를 저장하는 레지스터&lt;/li&gt;
&lt;li&gt;초기 PC 값은 프로그램 시작 시 운영체제가 설정함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 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;CPU 내부의 임시 저장소&lt;/li&gt;
&lt;li&gt;CPU가 처리할 데이터를 일시적으로 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로그램 실행 과정&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;프로그램의 첫 번째 명령어(main 함수)가 메모리에 저장됨&lt;/li&gt;
&lt;li&gt;해당 명령어의 주소를 PC 레지스터에 기록&lt;/li&gt;
&lt;li&gt;CPU가 PC의 주소를 참조하여 명령어를 실행&lt;/li&gt;
&lt;li&gt;명령어 실행 후 PC가 다음 명령어 주소로 업데이트됨&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CPU와 코어의 개념&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CPU(중앙 처리 장치)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터에서 모든 연산과 명령을 수행하는 핵심 장치&lt;/li&gt;
&lt;li&gt;하나의 CPU 안에는 보통 여러 개의 코어가 존재할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코어(Core)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU 내부의 독립적인 명령어 실행 장치&lt;/li&gt;
&lt;li&gt;각 코어는 독립적으로 명령을 처리할 수 있는 연산 장치&lt;/li&gt;
&lt;li&gt;코어가 많을수록 여러 작업을 동시에 병렬 처리 가능하여 성능이 향상됨&lt;/li&gt;
&lt;li&gt;코어가 많다고 CPU가 여러 개인 것은 아니며, 일반적으로 CPU는 하나이고 그 내부에 여러 개의 코어를 포함하는 형태임&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;운영체제(OS)의 필요성&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 프로그램을 관리하고 실행 순서를 정해줌&lt;/li&gt;
&lt;li&gt;CPU는 한 번에 하나의 작업만 수행할 수 있으며, OS는 작업 간 빠른 전환을 통해 동시 실행을 가능하게 함(멀티태스킹)&lt;/li&gt;
&lt;li&gt;프로그램의 실행 상태(Context)를 관리함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;프로세스와 스레드&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 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;OS가 리소스를 할당하는 기본 단위&lt;/li&gt;
&lt;li&gt;프로세스마다 독립된 메모리 공간이 존재함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 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;/li&gt;
&lt;li&gt;프로세스의 자원을 공유함(코드, 데이터, 힙 공유 가능)&lt;/li&gt;
&lt;li&gt;각 스레드는 독립된 스택을 가짐(지역 변수 관리)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스레드 풀(Thread Pool)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스레드를 미리 생성해두고 요청 시 재사용하여 성능을 최적화함&lt;/li&gt;
&lt;li&gt;개수는 일반적으로 시스템의 코어 개수에 따라 적절히 결정됨&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;CPU는 코어의 수만큼의 작업을 병렬로 동시에 처리할 수 있다. 예를 들어 CPU가 4개의 코어를 가지고 있다면 4개의 작업을 동시에 처리할 수 있다.&lt;br /&gt;&lt;br /&gt;따라서 스레드를 너무 적게 만들면, CPU가 가진 코어의 병렬 처리 능력을 충분히 활용하지 못하게 되고 반대로 너무 많은 스레드를 만들면, 스레드 간 전환(Context Switching)으로 인해 오히려 성능이 떨어지게 된다.&lt;br /&gt;&lt;br /&gt;결국 최적의 성능을 위해서 일반적으로 스레드 풀의 개수는 CPU의 코어 수와 비슷하게 맞추거나, 코어 수의 몇 배 정도로 설정해서 CPU의 병렬 처리 능력을 효율적으로 활용하도록 결정하는 것이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스케줄링(Scheduling)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영체제가 여러 스레드를 관리하고 CPU 자원을 할당하는 과정&lt;/li&gt;
&lt;li&gt;스레드 간 전환 부담을 고려하여 적정 수의 스레드를 유지해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;메모리 영역&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리를 코드, 데이터, 힙, 스택 영역으로 나눈 이유는 메모리의 사용 목적과 접근 특성에 따라 효율적으로 관리하기 위함이다.&lt;br /&gt;&lt;br /&gt;각 영역별로 접근 권한과 데이터의 생명주기가 달라, 이를 구분하여 관리하면 성능 향상과 안정성 확보에 도움이 된다.&lt;br /&gt;&lt;br /&gt;특히 힙과 스택은 각각 메모리 관리 방식을 효율화하기 위해 만들어진 구조로, 스택은 데이터를 차곡차곡 쌓아 LIFO(Last In First Out) 방식으로 관리하고, 힙은 프로그램 실행 중 필요한 만큼 메모리 공간을 실시간으로 할당하거나 해제할 수 있도록 지원한다. 즉, 실행 전 미리 정해진 크기가 아니라, 필요에 따라 유연하게 크기를 조정하여 데이터를 저장할 수 있게 한다.&lt;br /&gt;&lt;br /&gt;힙은 무작위로 데이터를 쌓는다는 의미의 무더기(heap)에서 이름을 따왔고, 스택은 데이터를 쌓아 올린다는 개념에서 이름이 붙여졌다. 스택 영역은 주로 LIFO 방식으로 관리되나, 배열이나 포인터를 이용해 스택 내부의 특정 위치에 직접 접근할 수도 있다. 즉, 스택에 저장된 모든 데이터가 반드시 LIFO 방식으로만 접근되는 것은 아니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코드 영역&lt;/b&gt;: 실행 코드 저장(읽기 전용, 스레드 간 공유)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 영역&lt;/b&gt;: 전역 변수 저장(스레드 간 공유 가능)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;힙 영역&lt;/b&gt;: 동적 할당(malloc 등)을 통한 메모리 관리(공유 가능)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택 영역&lt;/b&gt;: 함수 호출 시 지역 변수 저장(각 스레드 독립적)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;메모리 관리와 malloc&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;malloc&lt;/code&gt;은 메모리를 힙 영역에서 동적으로 할당하고 그 포인터를 반환&lt;/li&gt;
&lt;li&gt;malloc의 이름은 &lt;code&gt;memory allocation(메모리 할당)&lt;/code&gt;의 줄임말로, 힙 영역에서 동적으로 메모리를 할당하는 함수의 역할을 나타냄&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;가상 메모리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물리적 메모리보다 큰 가상 주소 공간을 제공함&lt;/li&gt;
&lt;li&gt;프로그램 간 메모리 보호와 격리를 제공함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;동적/정적 링크&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정적 링크&lt;/b&gt;: 모든 종속 라이브러리가 실행파일에 포함됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 링크&lt;/b&gt;: 프로그램 실행 시 필요한 라이브러리를 로드하여 공유함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스레드 안전성(Thread Safety)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 스레드가 동시에 호출해도 정상적으로 동작하는 코드 특성&lt;/li&gt;
&lt;li&gt;지역 변수(Call by Value)는 스레드 안전&lt;/li&gt;
&lt;li&gt;포인터 등 공유자원은 별도의 동기화(잠금) 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;동기화와 잠금 기법&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;뮤텍스(Mutex)&lt;/b&gt;: 한 번에 하나의 스레드만 접근 가능, 자원을 기다리는 동안 스레드를 대기 상태로 전환하여 CPU를 효율적으로 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스핀락(Spin Lock)&lt;/b&gt;: 짧은 시간 자원을 기다릴 때 반복적으로 상태 확인(CPU를 계속 사용하여 다른 작업을 처리하지 않고 반복적으로 상태를 확인하는 방식)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스핀락은 뮤텍스처럼 한 번에 오직 하나의 스레드만 공유 리소스에 접근 가능&lt;/li&gt;
&lt;li&gt;짧은 대기 시간에서는 효율적이지만 긴 대기 시간이 발생하면 CPU 자원 낭비가 큼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세마포어(Semaphore)&lt;/b&gt;: 제한된 수의 스레드가 공유 리소스 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코루틴(Coroutine)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행을 일시 중지하고 재개 가능&lt;/li&gt;
&lt;li&gt;상태 저장하여 중단된 지점에서 계속 실행 가능(yield)&lt;/li&gt;
&lt;li&gt;코루틴이 일시 중지될 때의 상태는 자체적으로 관리되는 별도의 메모리 공간(주로 별도의 스택이나 힙 영역)에 저장되어, 다시 실행될 때 정확히 중단된 시점부터 이어서 실행할 수 있게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;커널 스레드와 유저 모드&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;커널 스레드&lt;/b&gt;: 운영체제가 관리하는 스레드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유저 모드(User mode)&lt;/b&gt;: 일반 프로그램이 제한된 권한으로 OS 자원에 접근하는 모드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램이 OS 커널의 핵심 자원을 직접 접근하지 않고 제한된 방식으로만 접근&lt;/li&gt;
&lt;li&gt;OS는 커널 모드와 유저 모드로 권한을 나눠 프로그램 오류나 악성 코드로부터 시스템 보호&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;원자성 작업(Atomic Operation)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;나눠질 수 없는 최소 단위 작업&lt;/li&gt;
&lt;li&gt;동시에 접근해도 문제가 발생하지 않도록 보장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;무상태 함수(Stateless Function)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 시 외부 상태 변경 없이 항상 동일한 출력 보장&lt;/li&gt;
&lt;li&gt;스레드 간 동기화 필요 없음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>weekly/컴퓨터 밑바닥의 비밀</category>
      <category>루샤오펑</category>
      <category>컴퓨터밑바닥의비밀</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/343</guid>
      <comments>https://binaryjourney.tistory.com/343#entry343comment</comments>
      <pubDate>Sun, 13 Apr 2025 10:51:52 +0900</pubDate>
    </item>
    <item>
      <title>내가 자주 쓰는 언어의 코드가 실행 파일로 만들어지고, 실행되기까지 어떤 과정을 거칠까</title>
      <link>https://binaryjourney.tistory.com/342</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일러와 링커의 동작 원리는 C 언어와 같은 시스템 언어에서 자주 다루지만, Java와 Kotlin 같은 JVM 언어에서도 유사한 개념이 적용된다. Java/Kotlin 소스 코드는 컴퍼일러에 의해 바이트코드(JVM 명령어 집합)로 변환되고 실행 시에는 JVM이 이 바이트코드를 적재하고 해석, 최적화하여 실제 CPU에서 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중점적으로 살펴볼 부분으로는 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 단계부터 실행 단계까지의 흐름&lt;/li&gt;
&lt;li&gt;컴파일러, 클래스 로더, 바이트 코드 처리(JIT 컴파일러, 인터프리터), 오류 발생 단계, 중간 산출물(.class, .jar), 전통적인 링커 개념이 JVM에서는 어떻게 나타나는지&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 소스 코드 &amp;rarr; 바이트코드, 컴파일 단계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM 바이트코드는 특정 OS나 CPU 아키텍처에 종속적이지 않아 JVM만 설치되어 있으면 어떤 운영체제에서든 동일한 바이트코드(&lt;code&gt;.class&lt;/code&gt;)를 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java/Kotlin 컴파일러는 언어 문법 검증과 바이트코드 생성까지의 역할을 하고 실제 기계어로의 번역은 JVM 실행 시점으로 넘겨둔다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Java&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 소스 파일(&lt;code&gt;Hello.java&lt;/code&gt; 등)은 &lt;code&gt;javac&lt;/code&gt; 컴파일러를 통해 바이트코드로 컴파일된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;컴파일 결과로 &lt;code&gt;.class&lt;/code&gt; 확장자의 클래스 파일이 생성되며 이 파일에 Java 바이트코드가 담겨 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Hello.java&lt;/code&gt; &amp;rarr; 컴파일 &amp;rarr; &lt;code&gt;Hello.class&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 컴파일 시 잘못된 구문이나 자료형 불일치 등의 문제가 있을 시 컴파일러가 &lt;code&gt;컴파일 타임 에러&lt;/code&gt;를 보고하고 &lt;code&gt;.class&lt;/code&gt; 파일은 만들어지지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;컴파일 타임 에러&lt;/code&gt;는 프로그램이 기계어 코드로 변환되는 컴파일 과정 중 발견되는 오류로 존재하지 않는 변수 호출, 문법 오류 시에 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 &lt;code&gt;&quot;Write Once, Run Anywhere&quot;&lt;/code&gt;라는 슬로건은 이 바이트코드와 JVM의 조합을 의미한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Kotlin&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin 코드(&lt;code&gt;Hello.kt&lt;/code&gt; 등)도 Kotlin 전용 컴파일러인 &lt;code&gt;kotlinc&lt;/code&gt;을 통해 JVM 바이트코드로 변환된다. Kotlin 컴파일러도 &lt;code&gt;.class&lt;/code&gt; 파일을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin은 Kotlin-specific metadata를 클래스 파일에 포함하지만 실행 자체는 표준 JVM 바이트코드로 수행된다고 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Kotlin 컴파일러는 Kotlin만의 고유한 언어 기능을 표현&amp;middot;저장하기 위해, &lt;code&gt;.class&lt;/code&gt; 파일 안에 Kotlin 메타데이터를 추가로 기록한다.&lt;/li&gt;
&lt;li&gt;이 메타데이터는 Kotlin이 제공하는 언어적 특징(데이터 클래스, 확장 함수, 코루틴, Null-safety 등)을 제대로 활용하거나 Kotlin 리플렉션에서 원본 Kotlin 코드를 복원, 분석할 때 쓰인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플렉션은 프로그램이 런타임에 자신을 스스로 들여다보고 (클래스, 메서드, 프로퍼티 구조 등을) 조작할 수 있게 하는 기술이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에도 java.lang.reflect 패키지가 있어서 클래스 타입, 메서드 타입, 파라미터 유형 등을 확인할 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin 리플렉션 kotlin.reflect.* 은 여기에 더해 Kotlin만의 추가 정보(데이터 클래스, 기본 파라미터, 널 허용 여부 등)를 런타임에 확인하도록 확장된 형태이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 중간산출물 - &lt;code&gt;.class&lt;/code&gt; 파일과 &lt;code&gt;.jar&lt;/code&gt; 패키지&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;클래스 파일 &lt;code&gt;.class&lt;/code&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 파일은 한 개의 Java/Kotlin 클래스나 인터페이스의 바이트코드를 담은 이진 파일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;code&gt;.class&lt;/code&gt; 파일 내부에는 상수 풀(constant pool), 필드/메서드 정보, 바이트코드 명령어 등이 이진 형식으로 들어 있다.&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;클래스 파일이 실행 파일은 아니지만 JVM이 이해할 수 있는 중간 산출물로 CPU에 독립적인 명령어들의 집합이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자바 아카이브 &lt;code&gt;.jar&lt;/code&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Java ARchive&lt;/code&gt;를 줄여 &lt;code&gt;jar&lt;/code&gt;라고 하며 여러 &lt;code&gt;.class&lt;/code&gt; 파일과 관련 자원(리소스 파일 등)을 하나로 묶은 압축 파일이다. &lt;code&gt;.jar&lt;/code&gt; 는 일종의 ZIP 압축 형식이고 보통 라이브러리나 어플리케이션 배포 시 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.jar&lt;/code&gt; 자체는 실행 가능한 바이너리가 아니라 JVM의 클래스 로더가 필요한 &lt;code&gt;.class&lt;/code&gt; 파일들을 읽어들이기 위한 패키지이다. 일반적인 단순 JAR에는 다수의 &lt;code&gt;.class&lt;/code&gt; 파일이 들어 있을 뿐, &quot;이 중 어디서부터 실행을 시작해야 하는지&quot;에 대한 정보는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순한 JAR 안에는 여러 &lt;code&gt;.class&lt;/code&gt; 파일만 묶여 있을 뿐 &amp;ldquo;이 중 어디서부터 실행을 시작해야 하나?&amp;rdquo;라는 정보가 없다. 그래서 실행 가능한 JAR를 만들려면 JAR에 어떤 클래스의 main 메서드를 프로그램 진입점으로 사용할지를 알려주는 정보가 추가로 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 JAR 내부에 진입점(메인 클래스) 정보를 포함하고 싶다면 Manifest 파일을 사용한다. Manifest 파일은 &lt;code&gt;META-INF/&lt;/code&gt; 디렉터리 아래 위치하는 간단한 텍스트 파일로 JAR 자체에 대한 메타데이터를 정의한다. 여기서 메인 클래스를 지정해주면, 이 JAR는 &quot;실행 가능한 JAR&quot;가 되어, &lt;code&gt;java -jar 파일명.jar&lt;/code&gt;만 입력해도 프로그램이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 가능한 JAR라고 해도 내부적으로는 JVM이 해당 JAR 파일을 열어 &lt;code&gt;.class&lt;/code&gt;들을 찾아 로딩하고 지정된 메인 클래스(&lt;code&gt;main&lt;/code&gt; 메서드)를 실행하는 과정으로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;jar&lt;/code&gt;를 만드는 것은 &lt;code&gt;.class&lt;/code&gt; 파일들을 묶고 메타데이터를 추가하는 것이고 실제 실행 로직은 JVM이 담당한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. JVM에서의 클래스 로딩과 링킹 과정&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;클래스 로더 (Class Loader)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java/Kotlin 코드를 컴파일하여 얻은 &lt;code&gt;.class&lt;/code&gt; 파일은 JVM에 의해 실행 시 적재(load)된다.&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;JVM은 프로그램을 시작할 때 (예: &lt;code&gt;Hello World&lt;/code&gt; 실행 시) 필요한 클래스들을 동적으로 메모리에 적재한다. 이 과정을 담당하는 것이 클래스 로더(Class Loader)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 로더는 컴파일 시가 아닌 런타임에 동적으로 클래스 로딩 및 링크를 수행하므로 필요한 시점까지 클래스를 메모리에 올리지 않아 메모리 효율을 높인다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;계층적인 위임 모델(Delegation Model)&lt;/b&gt;&lt;br /&gt;Java의 클래스 로딩 메커니즘은 하나의 클래스 로더만 쓰는 것이 아니라 &lt;b&gt;Bootstrap &amp;rarr; Extension &amp;rarr; Application&lt;/b&gt; 순으로 이어지는 여러 단계의 로더를 통해 클래스를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 로더는 &amp;ldquo;내가 로딩하기 전에 부모한테 먼저 물어보고 부모가 못 찾으면 그때 내가 로드한다.&amp;rdquo;라는 식의 &lt;b&gt;위임&lt;/b&gt; 방식을 따른다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JVM의 클래스 로더 시스템의 3단계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로딩(Loading)&lt;/li&gt;
&lt;li&gt;링킹(Linking)&lt;/li&gt;
&lt;li&gt;초기화(Initialization)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;링킹&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM이 &lt;code&gt;.class&lt;/code&gt; 파일을 메모리에 로딩한 후 검증(Verify) &amp;rarr; 준비(Preparation) &amp;rarr; 해결(Resolution) &amp;rarr; (초기화) 순으로 처리하는 과정을 통틀어 &lt;b&gt;링킹&lt;/b&gt;이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 전통적인 언어(C/C++ 등)에서 링커가 오브젝트 파일을 결합하면서 기호(함수, 변수 주소)들을 해결하는 과정을 자바가 런타임에 수행한다고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;검증 (Verify)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드된 &lt;code&gt;.class&lt;/code&gt; 파일이 JVM 명세에 적합한지를 검사한다. 파일 형식이 올바른지, 잘못된 바이트코드나 보안 위험 요소가 없는지를 확인한다. 문제 발생 시 &lt;code&gt;VerifyError&lt;/code&gt; 같은 런타임 에러를 발생시키고 실행을 중단한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;준비 (Preparation)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스가 사용할 메모리 자원을 확보하고 static 변수를 기본값으로 초기화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 &lt;code&gt;static int x;&lt;/code&gt;라면 &lt;code&gt;x&lt;/code&gt;는 0으로 초기화되고 객체 생성과 무관하게 클래스 영역에 공간이 마련된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;해결 (Resolution)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 내부에서 사용하는 심벌릭 참조(symbolic reference)를 실제 메모리상의 직접 참조(Direct reference)로 치환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 클래스 &lt;code&gt;A&lt;/code&gt;의 메서드를 호출하는 바이트코드 명령이 있으면, 실행 전에 &lt;code&gt;A&lt;/code&gt; 클래스의 실제 메서드 주소와 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지연 바인딩(lazy binding)&lt;br /&gt;자바는 무조건 이 단계에서 모든 심벌을 한 번에 해결하지 않고 실제 사용 시점에 해결하기도 한다. 그래서 Resolution 단계를 선택적(Optional)이라 부르기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재배치(Relocation)&lt;/b&gt;&lt;br /&gt;C/C++에서 오브젝트 파일을 OS 링커가 재배치하는 것과 유사하지만 자바에서는 JVM이 런타임에 이 작업을 수행하며 바이트코드 자체를 직접 수정하지는 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덕분에 동적 링킹이 가능해져, Java/Kotlin 프로그램은 실행 중 필요한 클래스만 로드하며 잘못된 참조도 실행 시점에 잡아낼 수 있다. 반면 C/C++ 정적 링크는 컴파일/링크 시점에 대부분의 참조를 해소하기 때문에 실행 파일 생성 후에는 고정된 주소로 동작하는 점이 다르다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;초기화 (Initialization)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;준비 단계에서 기본값으로 초기화됐던 static 변수들을 프로그래머가 지정한 값으로 다시 초기화하고, &lt;code&gt;static&lt;/code&gt; 블록이 있다면 이를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 클래스부터 차례대로 초기화를 진행한 뒤 최종적으로 해당 클래스까지 완료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 클래스 초기화가 끝나면 인스턴스 생성이나 &lt;code&gt;static&lt;/code&gt; 메서드 호출 등 해당 클래스를 사용할 준비가 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 바이트코드 실행 - 인터프리터와 JIT 컴파일러&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 로딩과 링킹/초기화가 완료된 Java/Kotlin의 바이트코드는 JVM의 실행 엔진(Execution Engine)에 의해 실행된다.&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;인터프리터(Interpreter)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JIT(Just-In-Time) 컴파일러&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대 JVM(예: HotSpot JVM)은 이 두 방식을 혼합(Hybrid)하여 사용한다. 초기에는 인터프리터로 빠르게 시작하고, 실행 중 성능을 높이기 위해 반복 실행되는 코드를 JIT 컴파일하여 네이티브 기계어로 전환한다.&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;이러한 JIT 기반 구조 덕분에 Java/Kotlin은 컴파일 언어의 성능과 인터프리트 언어의 유연성을 동시에 갖출 수 있고 JVM이 충분히 워밍업된 후에는 C/C++처럼 정적 컴파일된 프로그램만큼의 실행 속도를 낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;인터프리터&lt;/th&gt;
&lt;th&gt;JIT 컴파일러&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;실행 방식&lt;/td&gt;
&lt;td&gt;한 줄씩 해석&lt;/td&gt;
&lt;td&gt;전체 메서드를 기계어로 컴파일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;빠른 시작&lt;/td&gt;
&lt;td&gt;빠른 실행 속도 (반복 시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;단점&lt;/td&gt;
&lt;td&gt;반복 시 느림&lt;/td&gt;
&lt;td&gt;초기 컴파일 비용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;전략&lt;/td&gt;
&lt;td&gt;초기 단계 실행&lt;/td&gt;
&lt;td&gt;반복 시 최적화 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;인터프리터&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터프리터는 바이트코드를 한 줄씩 읽어서 즉시 해석하고 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 바이트코드 명령이 &lt;code&gt;정수 1을 스택에 푸시&lt;/code&gt;라면 JVM은 즉시 CPU에게 &lt;code&gt;1을 레지스터에 로드&lt;/code&gt;하도록 지시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터프리터 방식은 시작 속도가 빠르고 메모리 사용이 적지만 반복 실행되는 코드도 매번 해석해야 하므로 실행 속도가 느릴 수 있는 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM은 프로그램을 빠르게 시작하기 위해 초기에는 인터프리터로 모드로 코드를 실행한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JIT (Just-In-Time) 컴파일러&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JIT 컴파일러는 인터프리터의 단점을 보완하기 위해 도입된 기술로 실행 중인 바이트코드를 감시하여 빈번히 실행되는 부분을 기계어로 컴파일한다​.&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;JIT 컴파일러는 실행 중인 바이트코드를 모니터링하고 자주 반복되는 코드를 기계어(Native Code)로 컴파일하여 캐시에 저장한다.&lt;br /&gt;이후부터는 바이트코드를 해석할 필요 없이 바로 기계어로 실행하므로 성능이 크게 향상된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 어떤 메서드가 수천 번 호출되는 경우 JIT 컴파일러는 해당 메서드를 런타임 중에 기계어로 변환한다. HotSpot JVM은 메서드 호출 횟수, 루프 반복 횟수를 기준으로 JIT 컴파일을 트리거한다. 변환된 기계어는 JVM의 캐시에 저장되며, 동일한 코드를 재실행할 때는 인터프리터를 거치지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;두 단계 컴파일 (Tiered Compilation)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JIT 컴파일러는 자체적으로 두 단계를 거쳐 속도와 최적화 사이의 균형을 맞춘다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;컴파일러&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1단계&lt;/td&gt;
&lt;td&gt;C1 컴파일러&lt;/td&gt;
&lt;td&gt;빠르고 가벼운 최적화 (Quick)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2단계&lt;/td&gt;
&lt;td&gt;C2 컴파일러&lt;/td&gt;
&lt;td&gt;깊은 분석과 고급 최적화 (Aggressive)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM으로 실행 중인 Java 프로그램에서 사용자가&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;System.out.println(&quot;Hello&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 10000번 반복한다면 처음 수백 번 정도는 인터프리터가 매번 바이트코드를 해석하여 &lt;code&gt;println()&lt;/code&gt; 수행한다. 반복 횟수가 누적되면 JVM은 &lt;code&gt;println()&lt;/code&gt; 호출 루틴을 JIT 컴파일한다. 그 이후부터는 해석 없이 기계어 루틴을 직접 호출하므로 실행 속도가 빨라진다.&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;사용자는 JVM 위에서 프로그램을 돌리지만 내부적으로는 성능이 최적화된 기계어(Native Code)가 부분적으로 실행되고 있는 상태다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 컴파일 타임 에러 vs 런타임 에러&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 발생하는 시점에 따라 컴파일 타임 에러와 런타임 에러로 구분한다.​&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;컴파일 에러&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 컴파일하는 단계에서 컴파일러가 감지하는 오류이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java/Kotlin 컴파일러는 소스 코드를 바이트코드로 변환할 때 문법 검사와 정적 타입 체크를 수행한다. 예를 들어 구문 오류(Syntax Error), 타입 불일치(Type Mismatch), 정의되지 않은 변수/메서드 참조 등의 문제가 있으면 컴파일 타임 에러를 보고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일 타임 에러는 개발자가 코드를 잘못 작성한 경우에 컴파일러가 알려주는 오류이고, 런타임 에러는 코드상으로는 문제가 없어 보이지만 실행하면서 발생하는 문제이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;런타임 에러&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램이 컴파일을 정상적으로 마치고 실제 실행되는 중에 발생하는 오류이다.​&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;런타임 에러는 컴파일러 단계에서는 잡아내지 못했던 문제들이 실행 중에 나타나는 것으로 대표적으로 &lt;b&gt;예외(Exception)&lt;/b&gt; 와 &lt;b&gt;오류(Error)&lt;/b&gt; 가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Null pointer 참조 (&lt;code&gt;NullPointerException&lt;/code&gt;), 배열 범위 초과 (&lt;code&gt;ArrayIndexOutOfBoundsException&lt;/code&gt;), 형변환 실패 (&lt;code&gt;ClassCastException&lt;/code&gt;), 사용 중이던 클래스 파일을 찾지 못했을 때의 &lt;code&gt;NoClassDefFoundError&lt;/code&gt; 등이 모두 런타임 에러이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 언급한 바이트코드 검증 실패(VerifyError), 링크 시 ClassNotFoundException 등도 런타임 시점의 오류로 분류된다. 런타임 에러는 프로그램 실행 중에 발생하므로 이들을 적절히 처리(Exception handling)하지 않으면 프로그램이 중단될 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. JVM 언어에서의 링커(Linker) 개념&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 &lt;code&gt;3. JVM에서의 클래스 로딩과 링킹 과정&lt;/code&gt;에서 설명한 링킹(verification, preparation, resolution) 개념을 더 보충하자면, Java/Kotlin 같은 JVM 언어에서의 링킹은 전통적인 컴파일 언어(C/C++)에서의 링커 역할을 JVM이 런타임에 대신 수행하는 방식이라 볼 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전통적인 링커 C/C++ 의 경우&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C/C++ 같은 정적 컴파일 언어에서는 컴파일러가 소스 코드를 기계어로 변환한 &lt;code&gt;.o&lt;/code&gt; 또는 &lt;code&gt;.obj&lt;/code&gt; 오브젝트 파일을 만든 후 링커(Linker)가 이 여러 개의 오브젝트 파일을 하나로 묶는다. 이 과정에서 심벌릭 참조(함수 호출, 변수 주소 등)를 실제 메모리 주소로 치환하여 최종적으로 실행 가능한 단일 실행 파일(executable)을 만들어낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 링킹 작업은 컴파일 이후 실행 이전에 완료되며 링킹이 끝난 뒤에는 모든 심벌이 정적으로 해석된 상태가 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JVM 언어의 링킹: 런타임 링킹&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java/Kotlin에서는 이런 식의 링커 프로그램은 별도로 존재하지 않는다. 대신 JVM이 자체적으로 클래스 로딩 시점에 링킹 작업을 수행한다. 이를 런타임 링킹(runtime linking)이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.class&lt;/code&gt; 파일은 컴파일된 결과물이지만 서로 연결된 상태는 아니다. 실행 시 클래스 로더(Class Loader)가 필요한 클래스를 찾아 동적으로 로드하고 링킹 단계(검증, 준비, 해결)를 거쳐 심벌릭 참조를 해석한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;code&gt;A&lt;/code&gt; 클래스에서 &lt;code&gt;B&lt;/code&gt; 클래스의 메서드를 호출할 경우 컴파일러는 해당 호출을 위한 바이트코드 명령만 생성하고 메서드 주소는 적지 않는다. &lt;code&gt;.class&lt;/code&gt; 파일에는 해당 호출이 심벌(Symbol) 형태로 남아 있으며 실행 시 JVM이 &lt;code&gt;B&lt;/code&gt; 클래스를 로드한 뒤, 해당 메서드 주소를 Resolution 단계에서 연결한다.&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;JVM 링킹은 실행 중에 새로운 클래스를 로드할 수 있어 플러그인 시스템이나 동적 확장 구조가 가능하다. &lt;code&gt;.class&lt;/code&gt; 또는 &lt;code&gt;.jar&lt;/code&gt; 파일만으로 외부 라이브러리를 재컴파일 없이 연동 가능하다. &lt;code&gt;.class&lt;/code&gt;간의 관계는 클래스패스 설정만으로 결합할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플랫폼 독립적인 바이트코드와 JVM 표준 덕분에 링킹 방식이 운영체제나 CPU에 종속되지 않는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전통적 링커는 Windows(COFF), Linux(ELF) 등 OS별 바이너리 포맷을 고려해야 하지만, JVM은 &lt;code&gt;.class&lt;/code&gt;와 &lt;code&gt;.jar&lt;/code&gt;만 해석하면 되므로, OS와 무관하게 동일한 로딩/링킹 방식이 유지된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드 실행부터 JVM 내부 동작까지&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-04-05 오후 10.52.53.png&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;894&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r4LJl/btsM9JYPrO1/WahxlkOIVPyw3TZYKfMvO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r4LJl/btsM9JYPrO1/WahxlkOIVPyw3TZYKfMvO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r4LJl/btsM9JYPrO1/WahxlkOIVPyw3TZYKfMvO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr4LJl%2FbtsM9JYPrO1%2FWahxlkOIVPyw3TZYKfMvO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;507&quot; height=&quot;894&quot; data-filename=&quot;스크린샷 2025-04-05 오후 10.52.53.png&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;894&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>weekly/컴퓨터 밑바닥의 비밀</category>
      <category>컴퓨터밑바닥의비밀</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/342</guid>
      <comments>https://binaryjourney.tistory.com/342#entry342comment</comments>
      <pubDate>Sat, 5 Apr 2025 22:47:40 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코 1.5 5-01] 백준 트리순회로 설명하는 트리 자료구조 &amp;amp; 전&amp;middot;중&amp;middot;후위 순회</title>
      <link>https://binaryjourney.tistory.com/339</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 트리(Tree)란?&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1-1. 왜 트리를 배우나?&lt;/b&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;b&gt;계층적 구조&lt;/b&gt;를 표현하는 대표적인 자료구조이다.&lt;/li&gt;
&lt;li&gt;파일/폴더 구조, HTML DOM, 조직도 등 실제로 많이 볼 수 있는 형태&lt;/li&gt;
&lt;li&gt;코딩 테스트나 면접에서는 &lt;b&gt;트리 순회&lt;/b&gt;나 &lt;b&gt;이진 탐색 트리(BST)&lt;/b&gt; 가 출제된다.&lt;/li&gt;
&lt;li&gt;데이터가 &amp;ldquo;부모-자식&amp;rdquo; 관계로 연결될 때, 굉장히 직관적으로 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1-2. 시각적 예시&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 트리를 그림으로 표현한다면 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;   (A)  &amp;lt;-- 루트 노드
   / \  
 (B) (C)
 / \   \ 
(D)(E) (F)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A는 루트, B는 왼 자식, C는 오른 자식&lt;/li&gt;
&lt;li&gt;B의 왼 자식(D), 오른 자식(E), C의 오른 자식(F)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;부모 &amp;rarr; 자식&lt;/b&gt; 관계가 명확해서, DFS(깊이 우선 탐색)나 BFS(너비 우선 탐색)을 직관적으로 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 백준 1991 트리순회로 이해하는 전&amp;middot;중&amp;middot;후위 순회&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-1. 문제 내용&lt;/b&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;a href=&quot;https://www.acmicpc.net/problem/1991&quot;&gt;백준 1991 트리순회&lt;/a&gt; (트리 순회)&lt;/li&gt;
&lt;li&gt;N개의 노드(알파벳 대문자)가 주어지고, 각 노드의 왼쪽 자식/오른쪽 자식 정보가 주어짐.&lt;/li&gt;
&lt;li&gt;트리를 구성한 뒤, &lt;b&gt;전위 순회&lt;/b&gt;, &lt;b&gt;중위 순회&lt;/b&gt;, &lt;b&gt;후위 순회&lt;/b&gt; 결과를 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예시 입력&lt;/h4&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;7
A B C
B D .
C E F
E . .
F . G
D . .
G . .&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;.&lt;/code&gt;&lt;/b&gt; 은 자식이 없다는 의미&lt;/li&gt;
&lt;li&gt;A의 왼쪽 자식 = B, 오른쪽 자식 = C&lt;/li&gt;
&lt;li&gt;B의 왼쪽 자식 = D, 오른쪽 없음&lt;/li&gt;
&lt;li&gt;C의 왼쪽 자식 = E, 오른쪽 자식 = F &amp;hellip; 이런 식으로 트리를 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-2. 트리 구조&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;    A
   / \
  B   C
 /   / \
D   E   F
         \
          G&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;A&lt;/b&gt;: 루트&lt;/li&gt;
&lt;li&gt;&lt;b&gt;B&lt;/b&gt;: 왼쪽 서브트리의 루트, &lt;b&gt;D&lt;/b&gt;가 B의 왼쪽 자식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;C&lt;/b&gt;: 오른쪽 서브트리의 루트, &lt;b&gt;E&lt;/b&gt;와 &lt;b&gt;F&lt;/b&gt;가 각각 왼/오른쪽 자식, F의 오른쪽 자식이 G&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 전위&amp;middot;중위&amp;middot;후위 순회&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리 순회 방법은 &lt;b&gt;전위(Preorder)&lt;/b&gt;, &lt;b&gt;중위(Inorder)&lt;/b&gt;, &lt;b&gt;후위(Postorder)&lt;/b&gt; 세 가지가 대표적이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;전위(Preorder)&lt;/b&gt;: &lt;code&gt;루트 &amp;rarr; 왼쪽 &amp;rarr; 오른쪽&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제일 먼저 현재 노드를 방문&lt;/li&gt;
&lt;li&gt;트리 복제 등에 자주 쓰임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중위(Inorder)&lt;/b&gt;: &lt;code&gt;왼쪽 &amp;rarr; 루트 &amp;rarr; 오른쪽&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이진 탐색 트리(BST)에서 오름차순 정렬 결과를 얻을 때 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후위(Postorder)&lt;/b&gt;: &lt;code&gt;왼쪽 &amp;rarr; 오른쪽 &amp;rarr; 루트&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식을 다 처리한 뒤 부모를 방문 &amp;rarr; 트리 삭제 시, 혹은 후위 표기법(RPN) 계산 시 편리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  &lt;b&gt;중위 순회는 왜 이진탐색트리에서 오름차순 정렬 결과를 얻을 때 자주 활용될까?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 탐색 트리(Binary Search Tree, 이하 BST)의 &lt;b&gt;중위(Inorder) 순회&lt;/b&gt;가 오름차순 정렬 순서를 얻기 위해 자주 활용되는 이유는 다음과 같은 &lt;b&gt;BST 고유의 성질&lt;/b&gt; 때문이다.&lt;/p&gt;
&lt;h5&gt;&lt;b&gt;BST(Binray Search Tree) 성질&lt;/b&gt;&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BST에서는 각 노드의 &lt;b&gt;왼쪽 서브트리&lt;/b&gt;가 &lt;b&gt;루트 노드&lt;/b&gt;보다 &lt;b&gt;작은 값들&lt;/b&gt;로만, 그리고 &lt;b&gt;오른쪽 서브트리&lt;/b&gt;가 &lt;b&gt;루트 노드&lt;/b&gt;보다 &lt;b&gt;큰 값들&lt;/b&gt;로만 구성된다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;(왼쪽 서브트리) &amp;lt; (루트 노드) &amp;lt; (오른쪽 서브트리)&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;위 규칙이 트리의 모든 노드에 대해 재귀적으로 적용된다.&lt;/p&gt;
&lt;h5&gt;&lt;b&gt;중위 순회(Inorder): Left &amp;rarr; Root &amp;rarr; Right&lt;/b&gt;&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중위 순회 방법에 따라 아래와 같은 순서로 노드를 방문한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;왼쪽 서브트리&lt;/b&gt;를 중위 순회&lt;/li&gt;
&lt;li&gt;&lt;b&gt;루트 노드&lt;/b&gt;를 방문(출력)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오른쪽 서브트리&lt;/b&gt;를 중위 순회&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BST의 왼쪽 하위 트리는 항상 루트보다 작은 값들, 오른쪽 하위 트리는 항상 루트보다 큰 값들이라는 사실과 결합하면,&lt;br /&gt;&lt;b&gt;왼쪽&lt;/b&gt;의 모든 값 &amp;rarr; &lt;b&gt;현재(루트) 값&lt;/b&gt; &amp;rarr; &lt;b&gt;오른쪽&lt;/b&gt;의 모든 값 순으로 방문하게 되어 &lt;b&gt;결과적으로 값은 오름차순&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 백준 1991 트리순회 코드 구현&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리 노드를 간단히 클래스로 표현하거나, &lt;code&gt;HashMap&amp;lt;Character, Node&amp;gt;&lt;/code&gt; 형태로 루트/왼쪽/오른쪽 정보를 저장할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구현 시 유의할 점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력에서 &lt;code&gt;'.'&lt;/code&gt; 문자가 나오면 자식이 없다는 의미&lt;/li&gt;
&lt;li&gt;전위/중위/후위 함수를 각각 재귀로 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {

    // 트리 노드 정보를 저장할 map
    static Map&amp;lt;Character, Node&amp;gt; tree = new HashMap&amp;lt;&amp;gt;();

    public static void main(String[] args) throws IOException {
        // 입력 받기
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine().trim());

        // 입력값으로 트리 구성
        for (int i = 0; i &amp;lt; N; i++) {
            String[] input = br.readLine().split(&quot; &quot;);
            char root = input[0].charAt(0);
            char left = input[1].charAt(0);
            char right = input[2].charAt(0);

            // HashMap에 각 노드를 key로 저장
            // key='A' &amp;rarr; Node(val='A', left=?, right=?)
            tree.putIfAbsent(root, new Node(root));
            // 루트 노드 지정
            Node rootNode = tree.get(root);

            // 왼쪽 자식이 있을 시
            if (left != '.') {
                // HashMap에 각 노드를 key로 저장
                tree.putIfAbsent(left, new Node(left));
                // 왼쪽 자식 노드 지정
                rootNode.left = tree.get(left);
            }

            // 오른쪽 자식이 있을 시
            if (right != '.') {
                // HashMap에 각 노드를 key로 저장
                tree.putIfAbsent(right, new Node(right));
                // 오른쪽 자식 노드 지정
                rootNode.right = tree.get(right);
            }
        }

        // 트리의 루트를 항상 'A'라고 가정 시
        Node rootA = tree.get('A');

        // 전위 순회
        preorder(rootA);
        System.out.println();

        // 중위 순회
        inorder(rootA);
        System.out.println();

        // 후위 순회
        postorder(rootA);
        System.out.println();
    }

    // 노드 클래스 정의
    static class Node {
        char val;
        Node left, right;

        Node(char c) { this.val = c; }
    }

    // 순회는 모두 재귀 호출 이용
    // 전위 순회: Root &amp;rarr; Left &amp;rarr; Right
    static void preorder(Node node) {
        if (node == null) return;
        // Root : 출력
        System.out.print(node.val);
        // Left
        preorder(node.left);
        // Rigth
        preorder(node.right);
    }

    // 중위 순회: Left &amp;rarr; Root &amp;rarr; Right
    static void inorder(Node node) {
        if (node == null) return;
        // Left
        inorder(node.left);
        // Root : 출력
        System.out.print(node.val);
        // Right
        inorder(node.right);
    }

    // 후위 순회: Left &amp;rarr; Right &amp;rarr; Root
    static void postorder(Node node) {
        if (node == null) return;
        // Left
        postorder(node.left);
        // Right
        postorder(node.right);
        // Roodt : 출력
        System.out.print(node.val);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 결과&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;전위&lt;/b&gt;: &lt;code&gt;ABDCEFG&lt;/code&gt; &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중위&lt;/b&gt;: &lt;code&gt;DBAECFG&lt;/code&gt; &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후위&lt;/b&gt;: &lt;code&gt;DBEGFCA&lt;/code&gt; &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 정리&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;트리&lt;/b&gt;: 루트에서 시작해 부모-자식으로 뻗어나가는 계층 구조&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트리 순회&lt;/b&gt;: 전위/중위/후위 모두 DFS, 방문 순서가 조금씩 다름&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추가 참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=i5yHkP1jQmo&quot;&gt;트리 자료구조 by 동빈 나&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/339</guid>
      <comments>https://binaryjourney.tistory.com/339#entry339comment</comments>
      <pubDate>Sun, 2 Mar 2025 10:05:22 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] NestJS 에서도 GracefulShutdown 구현이 가능할까?</title>
      <link>https://binaryjourney.tistory.com/338</link>
      <description>&lt;h1&gt;&lt;b&gt;GracefulShutdown 구현이 가능할까?&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 스터디에서 Graceful Shutdown 에 대해 언급된 적이 있었는데 NestJS 공부하면서 NestJS에서도 구현이 가능한지 궁금해졌다. (당연히 구현이 가능할 것 같다. 요즘에는 거의 필수로 다들 사용하고 있으니까!)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Graceful Shutdown&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Graceful Shutdown은 서버나 애플리케이션이 종료 신호를 받았을 때, 즉시 프로세스를 &amp;lsquo;강제 종료&amp;rsquo;하지 않고 진행 중인 작업(트랜잭션, 요청 처리, 메시지 소비 등)을 안전하게 마무리한 뒤 종료하도록 설계된 기법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring 의 Graceful Shutdown&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring&lt;/b&gt; 환경에서 흔히 볼 수 있는 Graceful Shutdown은 주로 다음과 같은 맥락에서 사용된다&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;마이크로서비스 / 클라우드 환경&lt;/b&gt;&lt;br /&gt;Kubernetes나 Docker Swarm 같은 오케스트레이션 환경에서 애플리케이션을 롤링 업데이트하거나 스케일링할 때, 여러 인스턴스를 &amp;lsquo;빠르게 재시작&amp;rsquo;하거나 &amp;lsquo;종료&amp;rsquo;하는 상황이 자주 발생한다. 이때 진행 중인 요청이 중단되지 않고 마지막까지 성공적으로 수행될 수 있도록 돕는다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Zero-downtime 배포&lt;/b&gt;&lt;br /&gt;무중단 배포를 위해 새 버전 인스턴스를 기동하고, 구 버전 인스턴스를 종료할 때 연결된 클라이언트나 처리 중인 요청이 완결되길 기다리는 방식이다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자원 정리&lt;/b&gt;&lt;br /&gt;DB 커넥션 풀, 외부 API 세션, 메시지 큐, 쓰레드 풀 등의 리소스를 안전하게 해제해야 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서도 Graceful Shutdown을 적용하게 된 이유는 애플리케이션 서버(예: Tomcat, Undertow)가 강제 종료가 아닌 &amp;lsquo;유예 기간(Grace Period)&amp;rsquo;을 두고, 받던 요청을 천천히 마무리한 뒤 자원을 정리해 종료해주는 구조를 제공하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring에서의 Graceful Shutdown 구현 개념&lt;/b&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;b&gt;서버 레벨&lt;/b&gt;&lt;br /&gt;Spring Boot 2.x부터 &lt;code&gt;server.shutdown=graceful&lt;/code&gt; 옵션(실험적 기능)으로 설정할 수 있었다. 이 설정을 통해 Spring Boot 내장 서버(Tomcat 등)는 종료 신호(SIGTERM 등)를 받으면 새로운 연결 수용을 중단하고 현재 처리 중인 요청들을 모두 처리 완료할 때까지 대기한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;애플리케이션 레벨&lt;/b&gt;&lt;br /&gt;코드 차원에서는 &lt;code&gt;DisposableBean&lt;/code&gt; 인터페이스나 &lt;code&gt;@PreDestroy&lt;/code&gt; 같은 어노테이션을 활용해 종속 자원을 정리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;NestJS에서도 Graceful Shutdown이 가능한지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS 역시 &lt;b&gt;애플리케이션 레벨에서 종료 신호를 감지&lt;/b&gt;해 필요한 마무리 작업을 수행할 수 있도록 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원리는 Spring과 크게 다르지 않으며, NestJS는 내부적으로 &lt;b&gt;Shutdown Hooks&lt;/b&gt;라는 개념을 통해 이를 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS 개발 팀이 이 기능을 도입한 이유는 마이크로서비스, 서버리스, 컨테이너 환경에서의 안정적인 배포와 무중단 연동을 위해서다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 서버가 종료될 때 &lt;b&gt;DB 커넥션, 메시지 큐, 스트리밍 세션 등의 리소스를 안전하게 정리&lt;/b&gt;하기 위해 Graceful Shutdown은 필수적인 흐름이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;NestJS에서 Graceful Shutdown 구현 방법&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;어플리케이션 부트스트랩에서 Shutdown Hooks 활성화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;enableShutdownHooks()&lt;/code&gt;를 통해 Node 프로세스가 &lt;code&gt;SIGTERM&lt;/code&gt;, &lt;code&gt;SIGINT&lt;/code&gt; 같은 신호를 받을 때 NestJS가 내부적으로 모든 종료 관련 인터페이스를 호출하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 종료 신호를 감지하고 NestJS 종료 훅을 트리거
  app.enableShutdownHooks();

  await app.listen(3000);
}
bootstrap();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;종료 처리를 위한 라이프사이클 인터페이스 구현&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;OnApplicationShutdown&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BeforeApplicationShutdown&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OnModuleDestroy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;라이프사이클
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;종료 훅이 발생하면, NestJS는 등록된 모든 &lt;code&gt;onApplicationShutdown&lt;/code&gt; 메서드를 순차적으로 호출한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;signal&lt;/code&gt;에는 실제로 받은 시그널(&lt;code&gt;SIGTERM&lt;/code&gt; 등)이 문자열로 들어오므로, 로깅 등에 활용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BeforeApplicationShutdown&lt;/code&gt;은 실제 애플리케이션이 완전히 종료되기 직전에 호출되며, &lt;code&gt;OnModuleDestroy&lt;/code&gt;는 모듈이 제거될 때 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;code&gt;OnApplicationShutdown&lt;/code&gt; 인터페이스를 구현하면 다음과 같이 된다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;import { Injectable, OnApplicationShutdown } from '@nestjs/common';

@Injectable()
export class SomeService implements OnApplicationShutdown {
  onApplicationShutdown(signal?: string) {
    // 여기서 DB 연결 종료, 메시지 큐 연결 해제 등의 로직 수행
    console.log(`Received shutdown signal: ${signal}`);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  시그널, Signal&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;시그널(Signal)&lt;/b&gt; 은 운영체제(OS)가 프로세스에 보내는 일종의 소식(이벤트)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;NestJS에서 Graceful Shutdown을 이야기할 때 자주 등장하는 시그널로는 &lt;code&gt;SIGTERM&lt;/code&gt;, &lt;code&gt;SIGKILL&lt;/code&gt;, 그리고 &lt;code&gt;SIGINT&lt;/code&gt; 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 시그널들은 서버 프로세스가 종료 또는 중단되어야 할 때 중요한 역할을 한다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SIGTERM&lt;/b&gt;&lt;br /&gt;- 운영체제가 프로세스에 &amp;ldquo;종료하라&amp;rdquo;라고 요청하는 &lt;b&gt;일반적인 종료 시그널&lt;/b&gt;이다.&lt;br /&gt;- 프로세스는 이 시그널을 받았을 때, 종료 절차를 실행하거나 (처리 로직을 등록해 놓았다면) 무시하는 등의 동작을 선택할 수 있다.&lt;br /&gt;- &lt;code&gt;SIGTERM&lt;/code&gt; 시그널을 받을 때, NestJS에서는 &lt;code&gt;app.enableShutdownHooks()&lt;/code&gt;로 설정된 로직을 실행하고, &lt;code&gt;OnApplicationShutdown&lt;/code&gt; 인터페이스를 통해 종료 준비(데이터베이스 연결 해제, 메시지 큐 정리 등)를 수행할 수 있다.&lt;br /&gt;- &lt;b&gt;Graceful Shutdown&lt;/b&gt;을 구현하기에 적합한 시그널이다.&lt;br /&gt;- 흔히 컨테이너가 종료되면, 오케스트레이션 툴(Kubernetes 등)에서 &lt;span style=&quot;background-color: #e6f5ff; color: #333333; text-align: left;&quot;&gt;SIGTERM&lt;/span&gt;을 먼저 보내고, 일정 시간(예: 30초~60초)이 지난 뒤 프로세스가 종료되지 않으면 `SIGKILL`을 보낸다.&lt;br /&gt;- 이를 &amp;ldquo;&lt;b&gt;Termination&amp;nbsp;Grace&amp;nbsp;Period&lt;/b&gt;&amp;rdquo;라고 부른다. 이 시간 안에 애플리케이션이 &lt;span style=&quot;background-color: #e6f5ff; color: #333333; text-align: left;&quot;&gt;SIGTERM&lt;/span&gt;을 처리해 종료해야 무중단이 보장된다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SIGKILL&lt;/b&gt;&lt;br /&gt;- &amp;ldquo;즉시 종료&amp;rdquo;를 의미하는 &lt;b&gt;강제 종료 시그널&lt;/b&gt;로, 프로세스가 이 시그널을 받으면 &lt;b&gt;바로 종료&lt;/b&gt;된다.&lt;br /&gt;- 프로세스가 이 시그널을 수신하면 &lt;b&gt;어떤 종료 처리 로직도 실행할 수 없다&lt;/b&gt;.&lt;br /&gt;- 운영체제에서 가장 강력한 방식으로 프로세스를 죽이는 시그널이다.&lt;br /&gt;- 대개 &lt;code&gt;kill -9&lt;/code&gt; 명령처럼, 수동으로 강제 종료가 필요할 때 사용된다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SIGINT&lt;/b&gt;&lt;br /&gt;- 터미널에서 &lt;b&gt;Ctrl + C&lt;/b&gt;를 눌렀을 때 프로세스에 보내지는 시그널이다.&lt;br /&gt;- 일반적으로 &amp;ldquo;인터럽트(Interrupt) 신호&amp;rdquo;라고 한다.&lt;br /&gt;- Node.js 애플리케이션에서도 이를 받아서 종료 로직을 수행할 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;3&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;종료 프로세스에서 고려해야 할 요소&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DB 트랜잭션&lt;/b&gt;&lt;br /&gt;진행 중인 트랜잭션이 중단되지 않도록, 커밋 혹은 롤백을 모두 안전하게 마무리한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지 큐(Kafka, RabbitMQ 등)&lt;/b&gt;&lt;br /&gt;메시지를 재큐잉하거나, 처리 완료 시점을 보장해야 한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일 및 메모리 자원&lt;/b&gt;&lt;br /&gt;파일 핸들, 캐시 저장소 등도 정리한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;헬스 체크&lt;/b&gt;&lt;br /&gt;Kubernetes와 같은 환경에서 종료 직전에 readiness probe 상태를 &amp;lsquo;unhealthy&amp;rsquo;로 바꿔주는 방식도 같이 고려할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;활용 사례&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;컨테이너 오케스트레이션(Kubernetes, Docker Swarm)&lt;/b&gt;&lt;br /&gt;무중단 롤링 업데이트와 스케일링 시, 종료 훅을 통해 안전하게 인스턴스를 내려 효율적 운영이 가능하다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CI/CD 무중단 배포&lt;/b&gt;&lt;br /&gt;API 서버가 요청을 처리 중일 때, 새 버전을 띄우고 구 버전을 종료하는 과정에서 모든 요청이 원활히 마무리된다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마이크로서비스&lt;/b&gt;&lt;br /&gt;여러 서비스가 상호 연동되어 있을 때, 한 서비스가 종료되더라도 남은 작업을 정상 종료하고 네트워크 연결을 끊을 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;장단점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터 일관성 보장&lt;/b&gt;&lt;br /&gt;요청이나 트랜잭션이 도중에 끊기지 않아 데이터 무결성을 지킬 수 있다.&lt;br /&gt;DB 연결, 파일 핸들, 스레드 풀 등의 자원 누수를 방지할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;안정적 운영&lt;/b&gt;&lt;br /&gt;모니터링, 로깅, 알림 시스템과 결합해 예측 가능한 종료 시나리오를 만들 수 있다.&lt;br /&gt;종료 시점을 제어할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유연성&lt;/b&gt;&lt;br /&gt;NestJS나 Spring 모두 각자 필요한 로직(커넥션 해제, 세션 정리 등)을 커스터마이징해 넣을 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;복잡도 증가&lt;/b&gt;&lt;br /&gt;서비스 규모가 커질수록 종료 훅마다 처리해야 할 로직이 늘어나며, 단계별로 꼼꼼히 챙겨야 한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시간 지연&lt;/b&gt;&lt;br /&gt;진행 중인 작업을 마무리하기 위해 종료 시간을 늘리는 경우, 과도하게 긴 시간이 소요될 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실수 가능성&lt;/b&gt;&lt;br /&gt;모든 자원을 빠짐없이 정리하지 않으면 결국 리소스 누수나 트랜잭션 충돌 같은 문제가 발생할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;참고자료&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nestjs.com/fundamentals/lifecycle-events&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NestJS 공식문서 - Lifecycle Events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/2.6.0/reference/htmlsingle/#boot-features-graceful-shutdown&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring Boot 문서 - Graceful Shutdown (server.shutdown)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/sjk5766/nestjs-graceful-shutdown-fc20a225f081&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NestJS Graceful Shutdown&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS와 Spring 모두 애플리케이션의 안정성과 무중단 배포를 위해 Graceful Shutdown을 필수 기능으로 지원한다. 올바른 종료 과정을 설계하면, 운영 환경에서 예기치 못한 문제를 줄이고 사용자 경험을 향상시킬 수 있다.&lt;/p&gt;</description>
      <category>NestJS</category>
      <category>Graceful shutdown</category>
      <category>nestjs</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/338</guid>
      <comments>https://binaryjourney.tistory.com/338#entry338comment</comments>
      <pubDate>Thu, 27 Feb 2025 13:42:42 +0900</pubDate>
    </item>
    <item>
      <title>[Prisma] User `db` was denied access on the database `db`.</title>
      <link>https://binaryjourney.tistory.com/337</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 발견 과정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nest 스터디 중 발생한 오류다. 공부할 것도 많은데 오류가 아주 꼬리에 꼬리를 물고 발생하였다 &amp;zwj;♀️&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트코드 실행 중에&lt;br /&gt;&lt;code&gt;The table User does not exist in the current database. PrismaClientKnownRequestError:&lt;/code&gt;&lt;br /&gt;에러가 발생하였다. &lt;code&gt;prisma&lt;/code&gt; 데이터베이스 생성을 지나친 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령어로 시도하였다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;pnpm prisma migrate dev --name init
# 또는
npx prisma migrate dev --name init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 또 부딪히게 된 오류.&lt;/p&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;Error: P3014

Prisma Migrate could not create the shadow database. Please make sure the database user has permission to create databases. Read more about the shadow database (and workarounds) at https://pris.ly/d/migrate-shadow

Original error: Error code: P1010

User `nest` was denied access on the database `nestdb`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 오류는 &lt;b&gt;Prisma&lt;/b&gt;가 &lt;b&gt;Shadow Database&lt;/b&gt;(마이그레이션에 사용되는 임시 DB)를 생성하려고 시도하는 과정에서, &lt;b&gt;&lt;code&gt;nest&lt;/code&gt; 사용자&lt;/b&gt;에게 &lt;b&gt;데이터베이스 생성 권한&lt;/b&gt; 이 없어서 발생한 문제였다. 모든 문제의 원인!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gpt 에게 물어보니 docker로 띄운 mariaDB 컨테이너 내부 쉘에서 &lt;code&gt;nest&lt;/code&gt;사용자에게 권한을 줘야 한다고 하였다. 이 과정이 굉장히 길었다. 나와 같은 문제를 겪은 사람이 어딘가 고군분투를 하고 있지 않을까 싶어 도움을 주고자 글을 쓰게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 해결과정&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;User `nest` was denied access on the database `nestdb`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 오류 상세 내용을 살펴 보면 &lt;code&gt;nest&lt;/code&gt; 계정이 &lt;b&gt;CREATE DATABASE&lt;/b&gt; 권한이 없는 상태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해답은 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 권한을 만들어주면 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(하지만 난 간단한 길을 여러 삽질을 통해 가야 했다,,)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Docker 환경에서 mariaDB 컨테이너 접근&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;code&gt;Docker&lt;/code&gt; 컨테이너를 이용하여 mariaDB에 접속했다. 그래서 mariaDB 컨테이너에 접근해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;docker exec -it nest-mariadb bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어를 터미널에 입력하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;julia&quot;&gt;&lt;code&gt;root@컨테이너ID:/# &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 계정정보와 함께 도커 컨테이너 내부의 리눅스 셸로 변경될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.1 mariaDB(혹은 MySQL) 클라이언트 설치 후 사용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;code&gt;mariaDB&lt;/code&gt; DB 클라이언트를 설치한 적이 있다면 아래 1.1 과정을 생략하고 2번으로 넘어가면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 설치한 적이 없어서 삽질을 몇 번이나 더 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지가 &lt;code&gt;Debian/Ubuntu&lt;/code&gt; 계열인지 &lt;code&gt;Alpine&lt;/code&gt; 계열인지에 따라 명령이 다르다고 한다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# Debian/Ubuntu 계열일 경우
apt-get update &amp;amp;&amp;amp; apt-get install mariadb-client -y

# Alpine 계열인 경우
apk update &amp;amp;&amp;amp; apk add mariadb-client&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 &lt;code&gt;Debian/Ubuntu&lt;/code&gt; 계열이라 하고 그래서 &lt;code&gt;Debian/Ubuntu&lt;/code&gt; 계열의 명령어를 썼는데 잘 설치 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 끝나면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Get:&lt;/code&gt; 번호 어쩌구 로그들이 줄줄이 뜨다가 아래와 같은 예쁜 로그가 올라올 것이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Fetched 28.0 MB in 24s (1174 kB/s)                                                                                                                                                                                                
Reading package lists... Done
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
mariadb-client is already the newest version (1:11.7.2+maria~ubu2404).
mariadb-client set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 19 not upgraded.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.2 클라이언트 설치 확인&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;which mariadb
# 또는
which mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어로 설치가 됐는지 확인하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셸에 &lt;code&gt;/usr/bin/mariadb&lt;/code&gt; 혹은 &lt;code&gt;/usr/bin/mysql&lt;/code&gt;이 출력된다면 설치가 성공적으로 끝난 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. DB 접속 후 권한 부여&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.1 DB 접속&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어!!!! DB에 접속해보자.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;mariadb -u root -p
# 비밀번호 입력 (docker-compose.yml에 지정한 root PW, 예: root1234)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비밀번호 입력란이 나온다면 님은 반은 성공한 거임&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;Enter password: # docker-compose.yml 에서 설정했던 root 사용자의 비밀번호를 입력한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비밀번호 입력 후 아래와 같은 내용이 출력된다면 DB CLI 접속에 성공한 것이다!!!!&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 7
Server version: 11.7.2-MariaDB-ubu2404 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.2 권한 부여&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MariaDB 프롬프트에 아래 SQL문을 입력하면 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;;(세미콜론)&lt;/code&gt; 은 빼먹지 말고 반드시 입력해야 한다!&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# 접속 후 MariaDB 프롬프트에서:
GRANT ALL PRIVILEGES ON *.* TO 'nest'@'%';
FLUSH PRIVILEGES;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 종료&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MariaDB 프롬프트에서 나오려면 &lt;code&gt;exit&lt;/code&gt; 을 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 내부 셸에서 나오는 것도 똑같이 &lt;code&gt;exit&lt;/code&gt; 입력이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기다리고 기다려온 코드를 터미널에 입력해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740562389926&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm prisma migrate dev --name init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과물&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740562431136&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource &quot;db&quot;: MySQL database &quot;nestdb&quot; at &quot;localhost:3306&quot;

Applying migration `20250226092036_init`

The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20250226092036_init/
    └─ migration.sql

Your database is now in sync with your schema.

✔ Generated Prisma Client (v6.4.1) to ./node_modules/.pnpm/@prisma+client@6.4.1_prisma@6.4.1_typescript@5.7.3__typescript@5.7.3/node_modules/@prisma/client in 37ms&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아름답다. 아름다와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마치며&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 코드도 잘 동작한다. 감동의 눈물 좔좔..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 내용일 수도 있겠지만 나 같이 고생하는 분이 없길 바라며 글을 마친다,, 저처럼 삽질하지 마시고 얼른 이 글 검색해서 시간을 아끼세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 해봤는데 안된다면,,&lt;br /&gt;혹시 docker desktop 컨테이너가 정지 된 건 아닌지 한 번 더 확인해보자.&lt;/p&gt;</description>
      <category>Issue</category>
      <category>docker</category>
      <category>mariadb</category>
      <category>prisma</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/337</guid>
      <comments>https://binaryjourney.tistory.com/337#entry337comment</comments>
      <pubDate>Wed, 26 Feb 2025 18:29:51 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 4-08] 카드2</title>
      <link>https://binaryjourney.tistory.com/336</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;4&lt;/span&gt;&lt;/span&gt;회 모임 on-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.02.15)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://www.acmicpc.net/problem/2164&quot;&gt;백준 - 카드2&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N장의 카드가 있다. 각각의 카드는 차례로 1부터 N까지의 번호가 붙어 있으며, 1번 카드가 제일 위에, N번 카드가 제일 아래인 상태로 순서대로 카드가 놓여 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다음과 같은 동작을 카드가 한 장 남을 때까지 반복하게 된다. 우선, 제일 위에 있는 카드를 바닥에 버린다. 그 다음, 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 N=4인 경우를 생각해 보자. 카드는 제일 위에서부터 1234 의 순서로 놓여있다. 1을 버리면 234가 남는다. 여기서 2를 제일 아래로 옮기면 342가 된다. 3을 버리면 42가 되고, 4를 밑으로 옮기면 24가 된다. 마지막으로 2를 버리고 나면, 남는 카드는 4가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N이 주어졌을 때, 제일 마지막에 남게 되는 카드를 구하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원형 큐를 사용한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카드를 다시 아래로 보내는 것, 카드가 한 장 남을 때까지 반복한다는 내용 때문이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이 과정에서 해당 알고리즘을 어떻게 코드로 구현하려 했나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈러 연산은 이용하지 않고 deque, enque를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;15분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;입력&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 줄에 정수 N(1 &amp;le; N &amp;le; 500,000)이 주어진다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;출력&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 줄에 남게 되는 카드의 번호를 출력한다.&lt;/p&gt;
&lt;h5&gt;예제 입력1&lt;/h5&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;6&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;예제 출력&lt;/h5&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;solution() {
    // 1234 -&amp;gt; 342 -&amp;gt; 24 -&amp;gt; 4
    // 1234567 - &amp;gt; 345672 -&amp;gt; 56724 -&amp;gt; 7246 -&amp;gt; 462 -&amp;gt; 26 -&amp;gt; 6

    // 첫번째 deque
    // 두번째 deque 후 enque
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(bufferedReader.readLine(), &quot; &quot;);
        String answer = null;

        int n = Integer.parseInt(st.nextToken());

        ArrayDeque&amp;lt;Integer&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; n; i++) {
            queue.add(i + 1);
        }

        // 1234 -&amp;gt; 342 -&amp;gt; 24 -&amp;gt; 4
        // 1234567 - &amp;gt; 345672 -&amp;gt; 56724 -&amp;gt; 7246 -&amp;gt; 462 -&amp;gt; 26 -&amp;gt; 6
        while (queue.size() &amp;gt; 1) {
            queue.poll();
            if (!queue.isEmpty()) {
                queue.add(queue.poll());
            }
        }

        System.out.println(queue.poll());
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/336</guid>
      <comments>https://binaryjourney.tistory.com/336#entry336comment</comments>
      <pubDate>Fri, 21 Feb 2025 14:11:20 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 4-07] 요세푸스 문제</title>
      <link>https://binaryjourney.tistory.com/335</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;4&lt;/span&gt;&lt;/span&gt;회 모임 on-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.02.15)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://www.acmicpc.net/problem/1158&quot;&gt;백준 - 요세푸스 문제&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요세푸스 문제는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번부터 N번까지 N명의 사람이 원을 이루면서 앉아있고, 양의 정수 K(&amp;le; N)가 주어진다. 이제 순서대로 K번째 사람을 제거한다. 한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나간다. 이 과정은 N명의 사람이 모두 제거될 때까지 계속된다. 원에서 사람들이 제거되는 순서를 (N, K)-요세푸스 순열이라고 한다. 예를 들어 (7, 3)-요세푸스 순열은 &amp;lt;3, 6, 2, 7, 5, 1, 4&amp;gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N과 K가 주어지면 (N, K)-요세푸스 순열을 구하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원형 큐를 적용한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;원을 이루면서 앉아있다.&quot;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이 과정에서 해당 알고리즘을 어떻게 코드로 구현하려 했나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈러 연산은 사용하지 않고 deque, enque를 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;풀이&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이 시간&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;15분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;입력&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 &amp;le; K &amp;le; N &amp;le; 5,000)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;출력&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제와 같이 요세푸스 순열을 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h5&gt;예제 입력1&lt;/h5&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;7 3&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;예제 출력1&lt;/h5&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;lt;3, 6, 2, 7, 5, 1, 4&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution(n, k) {
    // 1234567 -&amp;gt; 456712 -&amp;gt; 71245 -&amp;gt; 4571 -&amp;gt; 145
    // enque, deque 활용
    // k번째 수는 deque만 그 외는 deque 후 enque
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(bufferedReader.readLine(), &quot; &quot;);
        StringBuilder answer = new StringBuilder(&quot;&amp;lt;&quot;);

        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());

        ArrayDeque&amp;lt;Integer&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; n; i++) {
            queue.add(i + 1);
        }

        // 1234567 -&amp;gt; 456712 -&amp;gt; 71245 -&amp;gt; 4571 -&amp;gt; 145
        int count = 1;
        int front;
        while (!queue.isEmpty()) {
            front = queue.poll();
            if (count == k) {
                answer.append(front);
                if (!queue.isEmpty()) {
                    answer.append(&quot;, &quot;);
                }
                count = 1;
                continue;
            }
            queue.add(front);
            count++;
        }

        answer.append(&quot;&amp;gt;&quot;);
        System.out.println(answer);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/335</guid>
      <comments>https://binaryjourney.tistory.com/335#entry335comment</comments>
      <pubDate>Fri, 21 Feb 2025 14:08:49 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 4-05] 진료 순서 정하기</title>
      <link>https://binaryjourney.tistory.com/334</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;4&lt;/span&gt;&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.02.15)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120835&quot;&gt;프로그래머스 - 진료 순서 정하기&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외과의사 머쓱이는 응급실에 온 환자의 응급도를 기준으로 진료 순서를 정하려고 합니다. 정수 배열 &lt;code&gt;emergency&lt;/code&gt;가 매개변수로 주어질 때 응급도가 높은 순서대로 진료 순서를 정한 배열을 return하도록 solution 함수를 완성해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 큐 사용 생각을 못했다^^..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 우선순위 큐를 알고 적용함&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;응급도가 높은 순서대로 진료 순서를 정한 배열을 return하도록&lt;/code&gt; 라는 문장에서 힌트를 얻었다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이 과정에서 해당 알고리즘을 어떻게 코드로 구현하려 했나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;PriorityQueue&lt;/code&gt; 자료형을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;5분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&gt;
&lt;h5&gt;제한사항&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중복된 원소는 없습니다.&lt;/li&gt;
&lt;li&gt;1 &amp;le; &lt;code&gt;emergency&lt;/code&gt;의 길이 &amp;le; 10&lt;/li&gt;
&lt;li&gt;1 &amp;le; &lt;code&gt;emergency&lt;/code&gt;의 원소 &amp;le; 100&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;입출력 예&lt;/h5&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;emergency&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[3, 76, 24]&lt;/td&gt;
&lt;td&gt;[3, 1, 2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[1, 2, 3, 4, 5, 6, 7]&lt;/td&gt;
&lt;td&gt;[7, 6, 5, 4, 3, 2, 1]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[30, 10, 23, 6, 100]&lt;/td&gt;
&lt;td&gt;[2, 4, 3, 5, 1]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution(emergency) {
    // sort 한 다음에 index별로 반환~~~
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution(emergency) {
    // 우선 순위 큐에 emergency 넣기
    // 우선 순위 큐에서 원소 빼면서 rank 매기기
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.Collectors;

class Solution {
    public int[] solution(int[] emergency) {
        return Arrays.stream(emergency)
            .map(i -&amp;gt; Arrays.stream(emergency).boxed()
                 .sorted(Comparator.reverseOrder())
                 .collect(Collectors.toList()).indexOf(i) + 1)
            .toArray();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public int[] solution(int[] emergency) {
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());
        for (int i = 0; i &amp;lt; emergency.length ; i++) {
            pq.add(emergency[i]);
        }

        int rank = 1;
        int[] answer = new int[emergency.length];

        while (!pq.isEmpty()) {
            int front = pq.poll();
            for (int i = 0; i &amp;lt; emergency.length; i++) {
                if (emergency[i] == front &amp;amp;&amp;amp; answer[i] == 0) {
                    answer[i] = rank++;
                    break;
                }
            }
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;복기하기&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;답안과 나의 풀이를 비교해보세요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천을 가장 많이 받은 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Solution {
    public int[] solution(int[] emergency) {
        int[] answer = new int[emergency.length];

        for(int i = 0; i &amp;lt; answer.length; i++){
            if(answer[i] != 0){
                continue;
            }
            int idx = 1;
            for(int j = 0; j &amp;lt; answer.length; j++){
                if(emergency[i] &amp;lt; emergency[j]){
                    idx++;
                }
            }
            answer[i] = idx;
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선순위 큐를 사용하지 않고 정렬을 활용하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;요약하기&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제공된 자료구조를 잘 활용하자!&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/334</guid>
      <comments>https://binaryjourney.tistory.com/334#entry334comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:56:49 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 4-03] 문자열 밀기</title>
      <link>https://binaryjourney.tistory.com/333</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;4&lt;/span&gt;&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.02.15)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120921&quot;&gt;프로그래머스 - 문자열 밀기&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 &quot;hello&quot;에서 각 문자를 오른쪽으로 한 칸씩 밀고 마지막 문자는 맨 앞으로 이동시키면 &quot;ohell&quot;이 됩니다. 이것을 문자열을 민다고 정의한다면 문자열 &lt;code&gt;A&lt;/code&gt;와 &lt;code&gt;B&lt;/code&gt;가 매개변수로 주어질 때, &lt;code&gt;A&lt;/code&gt;를 밀어서 &lt;code&gt;B&lt;/code&gt;가 될 수 있다면 밀어야 하는 최소 횟수를 return하고 밀어서 &lt;code&gt;B&lt;/code&gt;가 될 수 없으면 -1을 return 하도록 solution 함수를 완성해보세요.&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;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;30분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&gt;
&lt;h5&gt;제한사항&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0 &amp;lt; &lt;code&gt;A&lt;/code&gt;의 길이 = &lt;code&gt;B&lt;/code&gt;의 길이 &amp;lt; 100&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;는 알파벳 소문자로 이루어져 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;입출력 예&lt;/h5&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&quot;hello&quot;&lt;/td&gt;
&lt;td&gt;&quot;ohell&quot;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;apple&quot;&lt;/td&gt;
&lt;td&gt;&quot;elppa&quot;&lt;/td&gt;
&lt;td&gt;-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;atat&quot;&lt;/td&gt;
&lt;td&gt;&quot;tata&quot;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;abc&quot;&lt;/td&gt;
&lt;td&gt;&quot;abc&quot;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5&gt;입출력 예 설명&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #1&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;hello&quot;를 오른쪽으로 한 칸 밀면 &quot;ohell&quot;가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #2&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;apple&quot;은 몇 번을 밀어도 &quot;elppa&quot;가 될 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #3&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;atat&quot;는 오른쪽으로 한 칸, 세 칸을 밀면 &quot;tata&quot;가 되므로 최소 횟수인 1을 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #4&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;abc&quot;는 밀지 않아도 &quot;abc&quot;이므로 0을 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution(A, B) {
    // while 문 사용
        // A와 회전된 문자열 비교
            // - 같을 시 횟수 반환
        // B 회전
        // 횟수++
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;import java.util.Arrays;

class Solution {
    public int solution(String A, String B) {
        int lenA = A.length();
        char[] chars = B.toCharArray();
        char[] rotate = new char[lenA];
        int answer = 0;
        while (answer &amp;lt; lenA) {
            if (A.equals(String.valueOf(chars))) break;
            for (int i = 0; i &amp;lt; lenA; i++) {
                rotate[i] = chars[(i + 1) % lenA];
            }
            answer++;
            chars = Arrays.copyOfRange(rotate, 0, lenA);
        }
        return lenA == answer ? -1 : answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Arrays.copyOfRange&lt;/code&gt; 사용이 성능적으로 비효율적인 것 같아 리팩토링을 진행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.ArrayDeque;

class Solution {
    public int solution(String A, String B) {
        int lenA = A.length();
        StringBuilder sb = new StringBuilder(B);

        for (int i = 0; i &amp;lt; lenA; i++) {
            if (A.equals(sb.toString())) return i;
            sb.insert(lenA, sb.charAt(0));
            sb.delete(0, 1);
        }
        return -1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sb.delete&lt;/code&gt;가 &lt;code&gt;sb.insert&lt;/code&gt;보다 먼저 작성되길 바랐지만 그렇게 할 경우 &lt;code&gt;sb.chartAt&lt;/code&gt; 코드에서 &lt;code&gt;IndexOutOfRange&lt;/code&gt; 예외가 발생하여 이렇게 작성하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;복기하기&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;답안과 나의 풀이를 비교해보세요&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Solution {
    public int solution(String A, String B) {
        String tempB = B.repeat(3);
        return tempB.indexOf(A);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬의 경우 나도 이런 식으로 풀었는데 자바는 이렇게 풀기 싫었다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/333</guid>
      <comments>https://binaryjourney.tistory.com/333#entry333comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:53:18 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 4-02] 배열 회전시키기</title>
      <link>https://binaryjourney.tistory.com/332</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;4&lt;/span&gt;&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.02.15)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120844&quot;&gt;프로그래머스 - 배열 회전시키기&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정수가 담긴 배열 &lt;code&gt;numbers&lt;/code&gt;와 문자열 &lt;code&gt;direction&lt;/code&gt;가 매개변수로 주어집니다. 배열 &lt;code&gt;numbers&lt;/code&gt;의 원소를 &lt;code&gt;direction&lt;/code&gt;방향으로 한 칸씩 회전시킨 배열을 return하도록 solution 함수를 완성해주세요.&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;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원형 큐를 사용하였다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 설명에서 왼쪽, 혹은 오른쪽으로 회전한다는 말을 보고 원형 큐가 적합하다고 판단하였다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이 과정에서 해당 알고리즘을 어떻게 코드로 구현하려 했나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈러 연산을 사용한다.&lt;/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;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;20분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&gt;
&lt;h5&gt;제한사항&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3 &amp;le; &lt;code&gt;numbers&lt;/code&gt;의 길이 &amp;le; 20&lt;/li&gt;
&lt;li&gt;&lt;code&gt;direction&lt;/code&gt;은 &quot;left&quot; 와 &quot;right&quot; 둘 중 하나입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5&gt;입출력 예&lt;/h5&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;numbers&lt;/th&gt;
&lt;th&gt;direction&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[1, 2, 3]&lt;/td&gt;
&lt;td&gt;&quot;right&quot;&lt;/td&gt;
&lt;td&gt;[3, 1, 2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[4, 455, 6, 4, -1, 45, 6]&lt;/td&gt;
&lt;td&gt;&quot;left&quot;&lt;/td&gt;
&lt;td&gt;[455, 6, 4, -1, 45, 6, 4]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5&gt;입출력 예 설명&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #1&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;numbers&lt;/code&gt; 가 [1, 2, 3]이고 &lt;code&gt;direction&lt;/code&gt;이 &quot;right&quot; 이므로 오른쪽으로 한 칸씩 회전시킨 [3, 1, 2]를 return합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution(int[] numbers, String direction) {
    // numbers를 두 번 반복하는 배열 생성

    // 시작 지점
    // - left 일 경우 1부터
    // - right일 경우 -1 부터 -&amp;gt; 원형 큐이므로 (n-1)

    // 시작 지점으로부터 n개만큼 잘라 배열 리턴
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution(int[] numbers, String direction) {
    // 배열 생성

    // 시작 지점
    // - left 일 경우 1부터
    // - right일 경우 -1 부터 -&amp;gt; 원형 큐이므로 (n-1)

    // 배열[i] = numbers[(시작 지점 + i) % n]
    // 배열 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.Arrays;

class Solution {
    public int[] solution(int[] numbers, String direction) {
        int n = numbers.length;
        int[] answer = new int[n * 2];
        for (int i = 0; i &amp;lt; n * 2; i++) {
            answer[i] = numbers[i % n];
        }
        return Arrays.copyOfRange(answer, direction.equals(&quot;right&quot;) ? n - 1 : 1, direction.equals(&quot;right&quot;) ? 2 * n - 1 : n + 1);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2차 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Solution {
    public int[] solution(int[] numbers, String direction) {
        int n = numbers.length;
        int[] answer = new int[n];
        int point = direction.equals(&quot;right&quot;) ? n - 1 : 1;
        for (int i = 0; i &amp;lt; n; i++) {
            answer[i] = numbers[(point + i) % n];
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;복기하기&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;답안과 나의 풀이를 비교해보세요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천 가장 많이 받은 풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

class Solution {
    public int[] solution(int[] numbers, String direction) {
        List&amp;lt;Integer&amp;gt; list = Arrays.stream(numbers).boxed().collect(Collectors.toList());

        if (direction.equals(&quot;right&quot;)) {
            list.add(0, list.get(list.size() - 1));
            list.remove(list.size() - 1);
        } else {
            list.add(list.size(), list.get(0));
            list.remove(0);
        }
        return list.stream().mapToInt(Integer::intValue).toArray();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제공되는 자료구조를 잘 활용하는 것도 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/332</guid>
      <comments>https://binaryjourney.tistory.com/332#entry332comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:50:19 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 4-01] 공 던지기</title>
      <link>https://binaryjourney.tistory.com/331</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.02.15)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120843&quot;&gt;프로그래머스 - 공 던지기&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머쓱이는 친구들과 동그랗게 서서 공 던지기 게임을 하고 있습니다. 공은 1번부터 던지며 오른쪽으로 한 명을 건너뛰고 그다음 사람에게만 던질 수 있습니다. 친구들의 번호가 들어있는 정수 배열 &lt;code&gt;numbers&lt;/code&gt;와 정수 &lt;code&gt;K&lt;/code&gt;가 주어질 때, &lt;code&gt;k&lt;/code&gt;번째로 공을 던지는 사람의 번호는 무엇인지 return 하도록 solution 함수를 완성해보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등차수열을 사용한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제한사항 보면 &quot;&lt;code&gt;numbers&lt;/code&gt;는 1부터 시작하며 번호는 순서대로 올라&quot; 가기 때문에 1부터 간격이 2씩 증가하는 등차수열임을 알 수 있다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;5분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h5&gt;제한사항&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2 &amp;lt; &lt;code&gt;numbers&lt;/code&gt;의 길이 &amp;lt; 100&lt;/li&gt;
&lt;li&gt;0 &amp;lt; &lt;code&gt;k&lt;/code&gt; &amp;lt; 1,000&lt;/li&gt;
&lt;li&gt;&lt;code&gt;numbers&lt;/code&gt;의 첫 번째와 마지막 번호는 실제로 바로 옆에 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;numbers&lt;/code&gt;는 1부터 시작하며 번호는 순서대로 올라갑니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;입출력 예&lt;/h5&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;numbers&lt;/th&gt;
&lt;th&gt;k&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[1, 2, 3, 4]&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[1, 2, 3, 4, 5, 6]&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[1, 2, 3]&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #1&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1번은 첫 번째로 3번에게 공을 던집니다.&lt;/li&gt;
&lt;li&gt;3번은 두 번째로 1번에게 공을 던집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제한사항 보면 &quot;&lt;code&gt;numbers&lt;/code&gt;는 1부터 시작하며 번호는 순서대로 올라&quot; 가기 때문에 1부터 간격이 2씩 증가한 k번째 수를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Solution {
    public int solution(int[] numbers, int k) {
        // 등차수열 (a + (n - 1) * d)
        return 1 + (k - 1) * 2 % numbers.length;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;복기하기&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;답안과 나의 풀이를 비교해보세요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천을 가장 많이 받은 풀이도 등차수열을 이용했다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Solution {
    public int solution(int[] numbers, int k) {
        return (k-1)*2 % numbers.length+1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;요약하기&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큐를 사용해야 하는데 사용 안 함..!&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/331</guid>
      <comments>https://binaryjourney.tistory.com/331#entry331comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:43:56 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 2-04] 과제는 끝나지 않아!</title>
      <link>https://binaryjourney.tistory.com/330</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.01.19)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://www.acmicpc.net/problem/17952&quot;&gt;백준 - 과제는 끝나지 않아!&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성애는 이번 학기에 전공을 정말 많이 듣는다. 이로 인해 거의 매일을 과제를 하면서 보내고 있다. 그런데도 과제가 줄어들 기미가 보이지 않는데, 바로 분단위로 과제가 추가되고 있기 때문이다. 다행히 과제 제출 기한은 학기가 끝날 때까지이다. 너무나도 많은 과제를 하다가 미쳐버린 성애는 아래와 같은 규칙으로 과제를 해 나가고 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;과제는 가장 최근에 나온 순서대로 한다. 또한 과제를 받으면 바로 시작한다.&lt;/li&gt;
&lt;li&gt;과제를 하던 도중 새로운 과제가 나온다면, 하던 과제를 중단하고 새로운 과제를 진행한다.&lt;/li&gt;
&lt;li&gt;새로운 과제가 끝났다면, 이전에 하던 과제를 이전에 하던 부분부터 이어서 한다. (성애는 기억력이 좋기 때문에 아무리 긴 시간이 지나도 본인이 하던 부분을 기억할 수 있다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성애는 과제를 받자마자 이 과제가 몇 분이 걸릴지 정확하게 알 수 있고, 성애가 제출한 과제는 무조건 만점을 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성애는 이번 학기에 자기가 받을 과제 점수를 예상해보고 싶다. 하지만 과제 점수를 예상하는 지금도 과제가 추가되고 있기에 여유를 부릴 수가 없다. 여러분이 성애가 받을 과제 점수를 구해주자!&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;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;과제 class 만들어서 해보는 건 어떨까.&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00:00&lt;/td&gt;
&lt;td&gt;00:35&lt;/td&gt;
&lt;td&gt;35분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 줄에 이번 학기가 몇 분인지를 나타내는 정수 N이 주어진다. (1 &amp;le; N &amp;le; 1,000,000)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 줄부터 N줄 동안은 학기가 시작하고 N분째에 주어진 과제의 정보가 아래의 두 경우 중 하나로 주어진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 A T: 과제의 만점은 A점이고, 성애가 이 과제를 해결하는데 T분이 걸린다. A와 T는 모두 정수이다. (1 &amp;le; A &amp;le; 100, 1 &amp;le; T &amp;le; 1,000,000)&lt;/li&gt;
&lt;li&gt;0: 해당 시점에는 과제가 주어지지 않았다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;3
1 100 3
0
0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성애가 받을 과제 점수를 출력한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;100&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1분째: 100점짜리 과제 1이 주어지고 이 과제를 하는데 3분이 걸린다. 과제를 받자마자 시작했으므로 과제 1이 끝나는데는 이제 2분 남았다.&lt;/li&gt;
&lt;li&gt;2분째: 새로운 과제가 주어지지 않았으므로 과제 1을 이어서 한다.&lt;/li&gt;
&lt;li&gt;3분째: 새로운 과제가 주어지지 않았으므로 과제 1을 이어서 한다. 이 시점에 과제 1이 끝나서 100점을 획득한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution() {
    // 1. N분 입력 받기
    // 2. 스택 생성
    // 3. 문제 있을 시 원래 있던 시간에 -1분 처리하고 스택에 담기
    // 4. 문제 없을 시 스택 top -1분 처리하기
    // 5. 0분일 시 점수+, 스택에서 꺼내기
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.util.Stack;  
import java.util.StringTokenizer;  

public class Extra03IHateHomework {  
    public static void main(String[] args) throws IOException {  
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));  
        StringTokenizer st;  
        int N = Integer.parseInt(bufferedReader.readLine());  
        Stack&amp;lt;Homework&amp;gt; stack = new Stack&amp;lt;&amp;gt;();  
        int answer = 0;  
        for (int i = 0; i &amp;lt; N; i++) {  
            st  = new StringTokenizer(bufferedReader.readLine());  
            int code = Integer.parseInt(st.nextToken());  
            if (code == 1) {  
                int score = Integer.parseInt(st.nextToken());  
                int duration = Integer.parseInt(st.nextToken());
                stack.push(new Homework(score, duration - 1));  
            } else {  
                if (!stack.isEmpty()) {  
                    Homework homework = stack.peek();  
                    homework.doHomework();  
                }  
            }  
            if (!stack.isEmpty() &amp;amp;&amp;amp; 0 == stack.peek().getDuration()) {  
                answer += stack.pop().getScore();  
            }  
        }  
        System.out.println(answer);  
    }  

    public static class Homework {  
        private int score;  
        private int duration;  

        public Homework(int score, int duration) {  
            this.score = score;  
            this.duration = duration;  
        }  
        public int getScore() {  
            return this.score;  
        }  
        public int getDuration() {  
            return this.duration;  
        }  
        public void doHomework() {  
            this.duration--;  
        }    }  
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;굉장히 마음에 들지 않아!&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/330</guid>
      <comments>https://binaryjourney.tistory.com/330#entry330comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:37:38 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 2-05] 막대기</title>
      <link>https://binaryjourney.tistory.com/329</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.01.19)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://www.acmicpc.net/problem/17608&quot;&gt;백준 - 막대기&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림처럼 높이만 다르고 (같은 높이의 막대기가 있을 수 있음) 모양이 같은 막대기를 일렬로 세운 후, 왼쪽부터 차례로 번호를 붙인다. 각 막대기의 높이는 그림에서 보인 것처럼 순서대로 6, 9, 7, 6, 4, 6 이다. 일렬로 세워진 막대기를 오른쪽에서 보면 보이는 막대기가 있고 보이지 않는 막대기가 있다. 즉, 지금 보이는 막대기보다 뒤에 있고 높이가 높은 것이 보이게 된다. 예를 들어, 그림과 같은 경우엔 3개(6번, 3번, 2번)의 막대기가 보인다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://upload.acmicpc.net/a2ebef22-157f-4059-9bdd-6a0662b81698/-/crop/675x304/47,12/-/preview/&quot; alt=&quot;graph&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 막대기에 대한 높이 정보가 주어질 때, 오른쪽에서 보아서 몇 개가 보이는지를 알아내는 프로그램을 작성하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택을 사용한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 가까운, 혹은 가장 최근의 값을 비교할 때 스택이 용이하다.&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;17:45&lt;/td&gt;
&lt;td&gt;17:56&lt;/td&gt;
&lt;td&gt;11분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 줄에는 막대기의 개수를 나타내는 정수 N (2 &amp;le; N &amp;le; 100,000)이 주어지고 이어지는 N줄 각각에는 막대기의 높이를 나타내는 정수 h(1 &amp;le; h &amp;le; 100,000)가 주어진다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;6
6
9
7
6
4
6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽에서 N개의 막대기를 보았을 때, 보이는 막대기의 개수를 출력한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;3&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;soltion() {
    // 1. 막대기 개수 int N 받기
    // 2. 스택 생성
    for (int i = 0; i &amp;lt; N; i++) {
        // 3. 막대기 높이 int h 받기
        while (스택에 값 있고 h &amp;gt; top 일때) {
            stack.pop();
        }

        if (스택이 비어있거나 h &amp;lt; top 이면) {
            stack.push(h);
        }
    }
    System.out.println(stack.size());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(bufferedReader.readLine());
        Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; N; i++) {
            int h  = Integer.parseInt(bufferedReader.readLine());
            while (!stack.isEmpty() &amp;amp;&amp;amp; h &amp;gt; stack.peek()) {
                stack.pop();
            }
            if (stack.isEmpty() || h &amp;lt; stack.peek()) {
                stack.push(h);
            }
        }
        System.out.println(stack.size());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;요약하기&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이게 바로 모노토닉 스택..!&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/329</guid>
      <comments>https://binaryjourney.tistory.com/329#entry329comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:33:41 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 2-02] 같은 숫자는 싫어</title>
      <link>https://binaryjourney.tistory.com/328</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.01.19)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12906&quot;&gt;프로그래머스 - 같은 숫자는 싫어&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 arr가 주어집니다. 배열 arr의 각 원소는 숫자 0부터 9까지로 이루어져 있습니다. 이때, 배열 arr에서 연속적으로 나타나는 숫자는 하나만 남기고 전부 제거하려고 합니다. 단, 제거된 후 남은 수들을 반환할 때는 배열 arr의 원소들의 순서를 유지해야 합니다. 예를 들면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;arr = [1, 1, 3, 3, 0, 1, 1] 이면 [1, 3, 0, 1] 을 return 합니다.&lt;/li&gt;
&lt;li&gt;arr = [4, 4, 4, 3, 3] 이면 [4, 3] 을 return 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 arr에서 연속적으로 나타나는 숫자는 제거하고 남은 수들을 return 하는 solution 함수를 완성해 주세요.&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;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택을 사용합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이 과정에서 해당 알고리즘을 어떻게 코드로 구현하려 했나요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택을 사용하여 top 과 같은 값은 지나가고 다른 값은 스택에 담습니다.&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;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;18:18&lt;/td&gt;
&lt;td&gt;18:24&lt;/td&gt;
&lt;td&gt;6분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열 arr의 크기 : 1,000,000 이하의 자연수&lt;/li&gt;
&lt;li&gt;배열 arr의 원소의 크기 : 0보다 크거나 같고 9보다 작거나 같은 정수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;arr&lt;/th&gt;
&lt;th&gt;answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[1,1,3,3,0,1,1]&lt;/td&gt;
&lt;td&gt;[1,3,0,1]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[4,4,4,3,3]&lt;/td&gt;
&lt;td&gt;[4,3]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution(int[] arr) {
    // 1. 스택 생성
    // 2. 스택에 없을 시 담음
    // 3. 스택에 있는 값 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.Stack;

public class Solution {
    public int[] solution(int[] arr) {
        Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();
        for (int n : arr) {
            if (stack.isEmpty() || n != stack.peek()) {
                stack.push(n);
            }
        }

        int[] answer = new int[stack.size()];
        for (int i = answer.length - 1; i &amp;gt;= 0; i--) {
            answer[i] = stack.pop();
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/328</guid>
      <comments>https://binaryjourney.tistory.com/328#entry328comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:28:58 +0900</pubDate>
    </item>
    <item>
      <title>[테코테코1.5 2-01] 컨트롤 제트</title>
      <link>https://binaryjourney.tistory.com/327</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt; &lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/tecoteco-study/tecoteco-coding-study&quot;&gt;테코테코 시즌 1.5&lt;/a&gt;&lt;span&gt; 2&lt;/span&gt;회 모임 off-site 문제 풀이입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;(2025.01.19)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/120853&quot;&gt;프로그래머스 - 컨트롤 제트&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자와 &quot;Z&quot;가 공백으로 구분되어 담긴 문자열이 주어집니다. 문자열에 있는 숫자를 차례대로 더하려고 합니다. 이 때 &quot;Z&quot;가 나오면 바로 전에 더했던 숫자를 뺀다는 뜻입니다. 숫자와 &quot;Z&quot;로 이루어진 문자열 &lt;code&gt;s&lt;/code&gt;가 주어질 때, 머쓱이가 구한 값을 return 하도록 solution 함수를 완성해보세요.&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;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택 사용 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;Z&quot;가 나오면 바로 전에 더했던 숫자를 뺀다는 것을 봐서 바로 직전에 쌓은 top 을 제거하는 것으로 이해했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이 과정에서 해당 알고리즘을 어떻게 코드로 구현하려 했나요?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Z 만나면 top pop&lt;/li&gt;
&lt;li&gt;stack 의 값 모두 더하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;16:13&lt;/td&gt;
&lt;td&gt;16:22&lt;/td&gt;
&lt;td&gt;9분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;le; &lt;code&gt;s&lt;/code&gt;의 길이 &amp;le; 200&lt;/li&gt;
&lt;li&gt;-1,000 &amp;lt; &lt;code&gt;s&lt;/code&gt;의 원소 중 숫자 &amp;lt; 1,000&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;는 숫자, &quot;Z&quot;, 공백으로 이루어져 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;에 있는 숫자와 &quot;Z&quot;는 서로 공백으로 구분됩니다.&lt;/li&gt;
&lt;li&gt;연속된 공백은 주어지지 않습니다.&lt;/li&gt;
&lt;li&gt;0을 제외하고는 0으로 시작하는 숫자는 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;는 &quot;Z&quot;로 시작하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;의 시작과 끝에는 공백이 없습니다.&lt;/li&gt;
&lt;li&gt;&quot;Z&quot;가 연속해서 나오는 경우는 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5&gt;&lt;b&gt;입출력 예&lt;/b&gt;&lt;/h5&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;s&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&quot;1 2 Z 3&quot;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;10 20 30 40&quot;&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;10 Z 20 Z 1&quot;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;10 Z 20 Z&quot;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;-1 -2 -3 Z&quot;&lt;/td&gt;
&lt;td&gt;-3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5&gt;&lt;b&gt;입출력 예 설명&lt;/b&gt;&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #1&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;본문과 동일합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #2&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;10 + 20 + 30 + 40 = 100을 return 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 예 #3&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;10 Z 20 Z 1&quot;에서 10 다음 Z, 20 다음 Z로 10, 20이 지워지고 1만 더하여 1을 return 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;solution() {
    // 1. 스택 생성
    // 2. String s split
    // 3. for 문
    for (s) {
        // 4. z 만나면 pop()
    }
    return stack의 합
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.Stack;
class Solution {
    public int solution(String s) {
        Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();
        String[] array = s.split(&quot; &quot;);
        for (String a : array) {
            if (a.equals(&quot;Z&quot;)) {
                if (!stack.isEmpty()) stack.pop();
            } else {
                stack.push(Integer.parseInt(a));
            }
        }

        int answer = 0;
        while (!stack.isEmpty()) {
            answer += stack.pop();
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/테코테코1.5(2025)</category>
      <category>테코테코</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/327</guid>
      <comments>https://binaryjourney.tistory.com/327#entry327comment</comments>
      <pubDate>Fri, 21 Feb 2025 13:21:55 +0900</pubDate>
    </item>
    <item>
      <title>[코딩테스트합격자되기-자바편] 문제17. 카드 뭉치</title>
      <link>https://binaryjourney.tistory.com/324</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;  해당 풀이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000212576322&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코딩 테스트 합격자되기 - 자바편&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 발췌된 내용을 바탕으로 작성되었습니다.&lt;/blockquote&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/159994&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로그래머스 - 카드 뭉치&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코니는 영어 단어가 적힌 카드 뭉치 두 개를 선물로 받았습니다. 코니는 다음과 같은 규칙으로 카드에 적힌 단어들을 사용해 원하는 순서의 단어 배열을 만들 수 있는지 알고 싶습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원하는 카드 뭉치에서 카드를 순서대로 한 장씩 사용합니다.&lt;/li&gt;
&lt;li&gt;한 번 사용한 카드는 다시 사용할 수 없습니다.&lt;/li&gt;
&lt;li&gt;카드를 사용하지 않고 다음 카드로 넘어갈 수 없습니다.&lt;/li&gt;
&lt;li&gt;기존에 주어진 카드 뭉치의 단어 순서는 바꿀 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 첫 번째 카드 뭉치에 순서대로 [&quot;i&quot;, &quot;drink&quot;, &quot;water&quot;], 두 번째 카드 뭉치에 순서대로 [&quot;want&quot;, &quot;to&quot;]가 적혀있을 때 [&quot;i&quot;, &quot;want&quot;, &quot;to&quot;, &quot;drink&quot;, &quot;water&quot;] 순서의 단어 배열을 만들려고 한다면 첫 번째 카드 뭉치에서 &quot;i&quot;를 사용한 후 두 번째 카드 뭉치에서 &quot;want&quot;와 &quot;to&quot;를 사용하고 첫 번째 카드뭉치에 &quot;drink&quot;와 &quot;water&quot;를 차례대로 사용하면 원하는 순서의 단어 배열을 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열로 이루어진 배열 &lt;code&gt;cards1&lt;/code&gt;, &lt;code&gt;cards2&lt;/code&gt;와 원하는 단어 배열 &lt;code&gt;goal&lt;/code&gt;이 매개변수로 주어질 때, &lt;code&gt;cards1&lt;/code&gt;과 &lt;code&gt;cards2&lt;/code&gt;에 적힌 단어들로 &lt;code&gt;goal&lt;/code&gt;를 만들 있다면 &quot;Yes&quot;를, 만들 수 없다면 &quot;No&quot;를 반환하는 &lt;code&gt;solution()&lt;/code&gt; 함수를 완성하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐를 사용하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FIFO 이므로 큐를 사용해야 한다.&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;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;09:56&lt;/td&gt;
&lt;td&gt;10:21&lt;/td&gt;
&lt;td&gt;25분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;le; &lt;code&gt;cards1&lt;/code&gt;의 길이, &lt;code&gt;cards2&lt;/code&gt;의 길이 &amp;le; 10
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;le; &lt;code&gt;cards1[i]&lt;/code&gt;의 길이, &lt;code&gt;cards2[i]&lt;/code&gt;의 길이 &amp;le; 10&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cards1&lt;/code&gt;과 &lt;code&gt;cards2&lt;/code&gt;에는 서로 다른 단어만 존재합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;2 &amp;le; &lt;code&gt;goal&lt;/code&gt;의 길이 &amp;le; &lt;code&gt;cards1&lt;/code&gt;의 길이 + &lt;code&gt;cards2&lt;/code&gt;의 길이
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;le; &lt;code&gt;goal[i]&lt;/code&gt;의 길이 &amp;le; 10&lt;/li&gt;
&lt;li&gt;&lt;code&gt;goal&lt;/code&gt;의 원소는 &lt;code&gt;cards1&lt;/code&gt;과 &lt;code&gt;cards2&lt;/code&gt;의 원소들로만 이루어져 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cards1&lt;/code&gt;, &lt;code&gt;cards2&lt;/code&gt;, &lt;code&gt;goal&lt;/code&gt;의 문자열들은 모두 알파벳 소문자로만 이루어져 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;cards1&lt;/th&gt;
&lt;th&gt;cards2&lt;/th&gt;
&lt;th&gt;goal&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[&quot;i&quot;, &quot;drink&quot;, &quot;water&quot;]&lt;/td&gt;
&lt;td&gt;[&quot;want&quot;, &quot;to&quot;]&lt;/td&gt;
&lt;td&gt;[&quot;i&quot;, &quot;want&quot;, &quot;to&quot;, &quot;drink&quot;, &quot;water&quot;]&lt;/td&gt;
&lt;td&gt;&quot;Yes&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[&quot;i&quot;, &quot;water&quot;, &quot;drink&quot;]&lt;/td&gt;
&lt;td&gt;[&quot;want&quot;, &quot;to&quot;]&lt;/td&gt;
&lt;td&gt;[&quot;i&quot;, &quot;want&quot;, &quot;to&quot;, &quot;drink&quot;, &quot;water&quot;]&lt;/td&gt;
&lt;td&gt;&quot;No&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;solution() {
    for (g: goal) {
        if (cards1.peek() == g) {
            cards1.poll()
        } else if (cards2.peek() == g) {
            cards2.poll()
        } else {
            return &quot;No&quot;
        }
    }
    return &quot;Yes&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public String solution(String[] cards1, String[] cards2, String[] goal) {
        Queue&amp;lt;String&amp;gt; cardsX = new ArrayDeque&amp;lt;&amp;gt;(Arrays.asList(cards1));
        Queue&amp;lt;String&amp;gt; cardsY = new ArrayDeque&amp;lt;&amp;gt;(Arrays.asList(cards2));

        for (String g : goal) {
            if (!cardsX.isEmpty() &amp;amp;&amp;amp; g.equals(cardsX.peek())) {
                cardsX.poll();
            } else if (!cardsY.isEmpty() &amp;amp;&amp;amp; g.equals(cardsY.peek())) {
                cardsY.poll();
            } else {
                return &quot;No&quot;;
            }
        }
        return &quot;Yes&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;복기하기&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;저자 권장 시간&lt;/th&gt;
&lt;th&gt;권장 시간 복잡도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;40분&lt;/td&gt;
&lt;td&gt;O(N)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;답안과 나의 풀이를 비교해보세요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.util.ArrayDeque;
import java.util.Arrays;

class Solution {
    public String solution(String[] cards1, String[] cards2, String[] goal) {
        ArrayDeque&amp;lt;String&amp;gt; cardsDeque1 = new ArrayDeque&amp;lt;&amp;gt;(Arrays.asList(cards1));
        ArrayDeque&amp;lt;String&amp;gt; cardsDeque2 = new ArrayDeque&amp;lt;&amp;gt;(Arrays.asList(cards2));
        ArrayDeque&amp;lt;String&amp;gt; goalDeque = new ArrayDeque&amp;lt;&amp;gt;(Arrays.asList(goal));

        while (!goalDeque.isEmpty()) {
            if (!cardsDeque1.isEmpty() &amp;amp;&amp;amp; cardsDeque1.peekFirst().equals(goalDeque.peekFirst())) {
                cardsDeque1.peekFirst();
                goalDeque.peekFirst();
            } else if (!cardsDeque2.isEmpty() &amp;amp;&amp;amp; cardsDeque2.peekFirst().equals(goalDeque.peekFirst())) {
                cardsDeque2.peekFirst();
                goalDeque.peekFirst();
            } else {
                break;
            }
        }

        return goalDeque.isEmpty() ? &quot;Yes&quot; : &quot;No&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;요약하기&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추천 많이 받은 풀이처럼 큐 클래스 쓰지 않고 인덱스로만 풀고 싶었는데..!!!&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/코딩테스트합격자되기-자바편</category>
      <category>코딩테스트합격자되기</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/324</guid>
      <comments>https://binaryjourney.tistory.com/324#entry324comment</comments>
      <pubDate>Thu, 30 Jan 2025 10:37:21 +0900</pubDate>
    </item>
    <item>
      <title>I/O 란 무엇인가?</title>
      <link>https://binaryjourney.tistory.com/323</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 자격증 시험을 준비하면서 &lt;b&gt;SQLP&lt;/b&gt; 교재에서 &quot;디스크 I/O, 파일 단위 I/O, 블록 단위 I/O&quot;라는 개념을 접했다. 사실 CS 관련 서적을 보면 I/O라는 용어는 흔히 등장하지만, 나는 그동안 &quot;I/O&quot;라고 읽고 그냥 지나쳤다. 하지만 정확히 무엇을 의미하는지 제대로 이해하고 싶어졌다. 이제라도 확실히 알아두는 게 중요할 것 같아 블로그에 정리해 보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&quot;기억보다는 기록을!&quot;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;I/O의 기본 개념&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터는 내부적으로 연산을 수행하는 &lt;b&gt;CPU&lt;/b&gt;(중앙처리장치)와 데이터를 저장하는 &lt;b&gt;메모리&lt;/b&gt;(RAM, HDD, SSD)로 이루어져 있다. 하지만 이 내부 시스템만으로는 외부 세계와 정보를 주고받을 수 없기 때문에 &lt;b&gt;입출력 장치(I/O 장치)&lt;/b&gt;가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;I/O란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O(Input/Output, 입출력)은 데이터를 입력받고 출력하는 과정을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;입력(Input)&lt;/b&gt;: 사용자가 데이터를 입력하거나 외부에서 데이터를 가져오는 작업
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 키보드 입력, 마우스 클릭, 센서 데이터, 파일 읽기, 네트워크 수신 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;출력(Output)&lt;/b&gt;: 입력된 데이터를 가공하여 사용자나 다른 시스템으로 보내는 작업
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 화면 출력, 프린터 인쇄, 스피커 소리 출력, 파일 저장, 네트워크 전송 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;I/O 장치&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터와 데이터를 주고받는 장치는 모두 &lt;b&gt;I/O 장치&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;입력 장치 (Input)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;출력 장치 (Output)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;보드,&amp;nbsp;마우스,&amp;nbsp;마이크,&amp;nbsp;터치스크린,&amp;nbsp;카메라,&amp;nbsp;스캐너&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;모니터,&amp;nbsp;프린터,&amp;nbsp;스피커,&amp;nbsp;LED&amp;nbsp;디스플레이&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;I/O의 동작 방식&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터에서 I/O는 &lt;b&gt;CPU&lt;/b&gt;와 &lt;b&gt;메모리&lt;/b&gt; 사이에서 데이터를 주고받는 방식으로 작동한다.&lt;br /&gt;CPU가 직접 I/O 장치와 데이터를 주고받을 수도 있지만, &lt;b&gt;버퍼(Buffer)&lt;/b&gt;를 활용하여 데이터를 저장하고 처리하는 방식이 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O 작업은 속도가 느려 CPU가 직접 처리하면 비효율적이므로, &lt;b&gt;DMA(Direct Memory Access)&lt;/b&gt; 같은 기법을 사용해 CPU 개입을 줄이기도 한다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt; I/O 의 종류&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O는 단순한 입력과 출력이 아니라 &lt;b&gt;다양한 방식과 최적화 기법&lt;/b&gt;이 존재한다.&lt;br /&gt;디스크, 파일, 네트워크, 메모리 등 여러 I/O 타입이 있으며, 각기 다른 방식으로 최적화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 디스크 I/O&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HDD나 SSD에서 데이터를 읽고 쓰는 작업을 의미한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 파일 저장, 데이터베이스 읽기/쓰기, OS 페이징&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화 방법&lt;/b&gt;: SSD 사용, 캐싱, 버퍼링, RAID, 압축 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  &lt;b&gt;RAID(Redundant Array of Independent Disks)&lt;/b&gt;란?&lt;br /&gt;&lt;br /&gt;RAID는 여러 개의 디스크를 하나의 논리적 장치로 묶어 성능을 향상하거나 데이터 보호를 강화하는 기술이다.&lt;br /&gt;&lt;br /&gt;속도를 높이거나 장애 발생 시 데이터를 보호하기 위해 여러 개의 디스크를 조합하는 방법이라고 생각하면 된다.&lt;br /&gt;&lt;br /&gt;주로 더 빠른 읽기/쓰기 속도의 성능 향상, 하드디스크 고장 시 데이터 손실 방지의 장애 대비(데이터 보호), 디스크를 하나처럼 사용 가능한 스토리지 용량 확장이 목적이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 파일 I/O&lt;/b&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;예: 로그 파일 기록, 설정 파일 읽기, CSV 파일 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화 방법&lt;/b&gt;: 비동기 처리, 파일 압축, 메모리 매핑(mmap)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  &lt;b&gt;메모리 매핑(Memory-Mapped Files, mmap)&lt;/b&gt;이란?&lt;br /&gt;&lt;br /&gt;파일을 디스크에서 직접 읽지 않고 메모리(RAM)에 매핑하여 빠르게 접근하는 방식이다.&lt;br /&gt;&lt;br /&gt;- 대용량 파일을 한 번에 로드하지 않고 필요한 부분만 로드할 수 있다. (Lazy Loading)&lt;br /&gt;- OS가 자동으로 캐싱하여 속도가 빠르다.&lt;br /&gt;- 다만 RAM을 많이 사용하므로 주의가 필요하다.&lt;br /&gt;&lt;br /&gt;데이터베이스, IPC(프로세스 간 통신), 영상 스트리밍 등에 활용된다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 네트워크 I/O&lt;/b&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;예: 웹 API 호출, FTP 파일 전송, 채팅 메시지 송수신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화 방법&lt;/b&gt;: 비동기 I/O, Keep-Alive, 로드 밸런싱, 캐싱&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  &lt;b&gt;Keep-Alive&lt;/b&gt;란?&lt;br /&gt;&lt;br /&gt;네트워크 연결을 일정 시간 동안 유지하여 TCP 연결을 재사용하는 방식이다.&lt;br /&gt;&lt;br /&gt;- HTTP 요청 시 새로운 TCP 연결을 만들면 오버헤드가 크다.&lt;br /&gt;- Keep-Alive를 사용하면 웹사이트 로딩 속도와 API 응답 시간이 빨라진다.&lt;br /&gt;- Connection: keep-alive 헤더를 추가하여 활성화할 수 있다. (HTTP/1.1부터 기본 활성화)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 메모리 I/O&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU와 RAM 간 데이터 이동을 의미하며, 휘발성 메모리(RAM)는 데이터를 디스크로 이동할 수도 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: CPU 연산 처리, OS 페이지 캐시, 데이터 버퍼링&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화 방법&lt;/b&gt;: 메모리 캐시, DMA(Direct Memory Access)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 장치 I/O&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;최적화 방법&lt;/b&gt;: 버퍼링, 인터럽트 기반 처리, DMA&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 그래픽 I/O&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU(Graphics Processing Unit)와 데이터를 주고받는 작업을 의미한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 게임 렌더링, 3D 그래픽, 동영상 재생&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적화 방법&lt;/b&gt;: GPU 가속, VRAM(비디오 메모리) 활용, 다이렉트 렌더링&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt; I/O 의 세부 개념&lt;/b&gt;&lt;/h2&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;직렬 I/O &amp;amp; 병렬 I/O&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 60px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%; height: 20px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%; height: 20px;&quot;&gt;&lt;b&gt;직렬 I/O (Serial I/O)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%; height: 20px;&quot;&gt;&lt;b&gt;병렬 I/O (Parallel I/O)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%; height: 20px;&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%; height: 20px;&quot;&gt;데이터를 &lt;b&gt;한 비트씩&lt;/b&gt; 순차적으로 전송&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%; height: 20px;&quot;&gt;데이터를 &lt;b&gt;여러 비트씩&lt;/b&gt; 동시에 전송&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%; height: 20px;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%; height: 20px;&quot;&gt;UART(시리얼 통신), USB, 블루투스&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%; height: 20px;&quot;&gt;프린터 포트(구형), PCI Express, 메모리 버스&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;블록 I/O &amp;amp; 문자 I/O&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 60px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%;height: 20px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%;height: 20px;&quot;&gt;&lt;b&gt;블록 I/O (Block I/O)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%;height: 20px;&quot;&gt;&lt;b&gt;블록 I/O (Block I/O)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%;height: 20px;&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%;height: 20px;&quot;&gt;데이터를 &lt;b&gt;고정된 크기 블록 단위&lt;/b&gt;로 읽고 씀&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%;height: 20px;&quot;&gt;데이터를 &lt;b&gt;한 글자(바이트) 단위&lt;/b&gt;로 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%;height: 20px;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%;height: 20px;&quot;&gt;디스크 I/O, 데이터베이스&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%;height: 20px;&quot;&gt;터미널 입력, 키보드 타이핑&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;동기 I/O &amp;amp; 비동기 I/O&lt;/b&gt;&lt;/h3&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;table style=&quot;border-collapse: collapse; width: 100%; height: 60px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%;height: 20px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%;height: 20px;&quot;&gt;&lt;b&gt;동기 I/O (Synchronous I/O)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%;height: 20px;&quot;&gt;&lt;b&gt;비동기 I/O (Asynchronous I/O)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%;height: 20px;&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%;height: 20px;&quot;&gt;작업이 끝날 때까지 &lt;b&gt;기다림&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%;height: 20px;&quot;&gt; 요청 후 &lt;b&gt;다른 작업을 수행&lt;/b&gt; 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.6589%;height: 20px;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.1937%;height: 20px;&quot;&gt;일반적인 파일 읽기/쓰기 (read(), write())&lt;/td&gt;
&lt;td style=&quot;width: 44.1473%;height: 20px;&quot;&gt;async/await 기반 네트워크 요청, DB 비동기 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그동안 막연하게 지나쳤던 &lt;b&gt;I/O&lt;/b&gt; 개념을 정리해 보았다.&lt;br /&gt;파일, 네트워크, 디스크 등 다양한 I/O 방식이 있으며,&lt;br /&gt;&lt;b&gt;최적화 방법&lt;/b&gt;도 각기 다르다는 점이 흥미롭다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 CS 서적에서 &lt;b&gt;I/O&lt;/b&gt;가 나오면 가볍게 지나치지 않고, 좀 더 깊이 있게 이해할 수 있을 것 같다.  &lt;/p&gt;</description>
      <category>daily/CS QnA</category>
      <category>CS</category>
      <category>I/O</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/323</guid>
      <comments>https://binaryjourney.tistory.com/323#entry323comment</comments>
      <pubDate>Wed, 29 Jan 2025 21:54:27 +0900</pubDate>
    </item>
    <item>
      <title>[코딩테스트합격자되기-자바편] 문제16. 기능 개발</title>
      <link>https://binaryjourney.tistory.com/322</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;  해당 풀이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000212576322&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코딩 테스트 합격자되기 - 자바편&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 발췌된 내용을 바탕으로 작성되었습니다.&lt;/blockquote&gt;
&lt;h1 style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42586&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로그래머스- 기능개발&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다.&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;progresses&lt;/code&gt;와 각 작업의 개발 속도가 적힌 정수 배열 &lt;code&gt;speeds&lt;/code&gt;가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 반환하도록 &lt;code&gt;solution()&lt;/code&gt; 함수를 완성하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 알고리즘을 적용하려 했나요?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계수정렬 사용했다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;적용 근거는 무엇인가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간은 계속 흐르므로 이는 인덱스를 이용하면 된다고 생각하였고 해당 인덱스에 끝나는 기능이 몇 개인지 알면 되기 때문에 계수정렬이 적합하다고 판단하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;12:11&lt;/td&gt;
&lt;td&gt;12:45&lt;/td&gt;
&lt;td&gt;34분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업의 개수(&lt;code&gt;progresses&lt;/code&gt;, &lt;code&gt;speeds&lt;/code&gt;의 배열의 길이)는 100개 이하입니다.&lt;/li&gt;
&lt;li&gt;작업 진도는 100 미만의 자연수입니다.&lt;/li&gt;
&lt;li&gt;작업 속도는 100 이하의 자연수입니다.&lt;/li&gt;
&lt;li&gt;배포는 하루에 한 번만 할 수 있으며, 하루의 끝에 이루어진다고 가정합니다. 예를 들어 진도율이 95%인 작업의 개발 속도가 하루에 4%라면 배포는 2일 뒤에 이루어집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;progresses&lt;/th&gt;
&lt;th&gt;speeds&lt;/th&gt;
&lt;th&gt;return&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;[93, 30, 55]&lt;/td&gt;
&lt;td&gt;[1, 30, 5]&lt;/td&gt;
&lt;td&gt;[2, 1]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[95, 90, 99, 99, 80, 99]&lt;/td&gt;
&lt;td&gt;[1, 1, 1, 1, 1, 1]&lt;/td&gt;
&lt;td&gt;[1, 3, 2]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;입출력 예 설명&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입출력 예 #1&lt;/b&gt;&lt;br /&gt;첫 번째 기능은 93% 완료되어 있고 하루에 1%씩 작업이 가능하므로 7일간 작업 후 배포가 가능합니다.&lt;br /&gt;두 번째 기능은 30%가 완료되어 있고 하루에 30%씩 작업이 가능하므로 3일간 작업 후 배포가 가능합니다. 하지만 이전 첫 번째 기능이 아직 완성된 상태가 아니기 때문에 첫 번째 기능이 배포되는 7일째 배포됩니다.&lt;br /&gt;세 번째 기능은 55%가 완료되어 있고 하루에 5%씩 작업이 가능하므로 9일간 작업 후 배포가 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 7일째에 2개의 기능, 9일째에 1개의 기능이 배포됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입출력 예 #2&lt;/b&gt;&lt;br /&gt;모든 기능이 하루에 1%씩 작업이 가능하므로, 작업이 끝나기까지 남은 일수는 각각 5일, 10일, 1일, 1일, 20일, 1일입니다. 어떤 기능이 먼저 완성되었더라도 앞에 있는 모든 기능이 완성되지 않으면 배포가 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 5일째에 1개의 기능, 10일째에 3개의 기능, 20일째에 2개의 기능이 배포됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;solution(progresses, speeds) {
    Queue&amp;lt;Integer&amp;gt; days = LinkedList&amp;lt;&amp;gt;();
    day = 0;
    index = 0;

    while (index != progresses.length) {
        if (progresses[index] &amp;gt;= 100) {
            days[day]++;
            index++;
        } else {
            for (progress : progresses) {
                progress += speeds[index];
            }
            day++;
        }
    }
    return days 중 1 이상인 값들의 모음
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public int[] solution(int[] progresses, int[] speeds) {
        int[] days = new int[101];
        int day = 0;
        int index = 0;

        while (index != progresses.length) {
            if (progresses[index] &amp;gt;= 100) {
                days[day]++;
                index++;
            } else {
                for (int i = 0; i &amp;lt; progresses.length; i++) {
                    progresses[i] += speeds[i];
                }
                day++;
            }
        }
        return Arrays.stream(days).filter(i -&amp;gt; i &amp;gt; 0).toArray();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;복기하기&lt;/b&gt;&lt;/h1&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;저자 권장 시간&lt;/th&gt;
&lt;th&gt;권장 시간 복잡도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;40분&lt;/td&gt;
&lt;td&gt;O(N)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;답안과 나의 풀이를 비교해보세요&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.ArrayDeque;
import java.util.Queue;

class Solution {
    public int[] solution(int[] progresses, int[] speeds) {
        Queue&amp;lt;Integer&amp;gt; answer = new ArrayDeque&amp;lt;&amp;gt;();

        int n = progresses.length;
        // 1. 각 작업의 배포 가능일 계산
        int[] daysLeft = new int[n];
        for (int i = 0;i &amp;lt; n;i++) {
            daysLeft[i] = (int) Math.ceil((100.0 - progresses[i]) / speeds[i]);
        }

        int count = 0; // 배포될 작업 수의 카운트
        int maxDay = daysLeft[0]; // 현재 배포될작업 중 가장 늦게 배포될 작업의 가능일

        for (int i = 0; i &amp;lt; n;i++) {
            if (daysLeft[i] &amp;lt;= maxDay) { // 배포 가능일이 가장 늦은 배포일보다 빠르면
                count++;
            } else { // 배포 예정일이 기준 배포일보다 느리면
                answer.add(count);
                count = 1;
                maxDay = daysLeft[i];
            }
        }

        answer.add(count); // 마지막으로 카운트된 작업들으르 함께 배포

        return answer.stream().mapToInt(Integer::intValue).toArray();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;요약하기&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최다 추천 풀이도 계수정렬로 풀었다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/코딩테스트합격자되기-자바편</category>
      <category>코딩테스트합격자되기</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/322</guid>
      <comments>https://binaryjourney.tistory.com/322#entry322comment</comments>
      <pubDate>Wed, 29 Jan 2025 14:54:05 +0900</pubDate>
    </item>
    <item>
      <title>[코딩테스트합격자되기-자바편] 문제15. 요세푸스 문제</title>
      <link>https://binaryjourney.tistory.com/321</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;  해당 풀이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000212576322&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코딩 테스트 합격자되기 - 자바편&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 발췌된 내용을 바탕으로 작성되었습니다.&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;N&lt;/code&gt;명의 사람이 원 혀앹로 서 있습니다. 각 사람은 1부터 &lt;code&gt;N&lt;/code&gt;까지 번호표를 갖고 있습니다. 그리고 임의의 숫자 &lt;code&gt;K&lt;/code&gt;가 주어졌을 때 다음과 같이 사람을 없앱니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 유대인 역사가인 플라비우스 요세푸스가 만든 문제입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1번 번호표를 가진 사람을 기준으로 &lt;code&gt;K&lt;/code&gt;번째 사람을 없앱니다&lt;/li&gt;
&lt;li&gt;없앤 사람 다음 사람을 기준으로 하고 다시 &lt;code&gt;K&lt;/code&gt;번째 사람을 없앱니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;N&lt;/code&gt;과 &lt;code&gt;K&lt;/code&gt;가 주어질 때 마지막에 살아있는 사람의 번호를 반환하는 &lt;code&gt;solution()&lt;/code&gt;함수를 구현해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;기록하기&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  어디까지 생각해봤는지 단계적으로 기록해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;풀이 시간&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시작 시각&lt;/th&gt;
&lt;th&gt;종료 시각&lt;/th&gt;
&lt;th&gt;총 소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;23:09&lt;/td&gt;
&lt;td&gt;23:23&lt;/td&gt;
&lt;td&gt;14분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약 사항 파악 &amp;amp; 테스트 케이스 작성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;N&lt;/code&gt;과 &lt;code&gt;K&lt;/code&gt;는 1 이사 1000 이하의 자연수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력값 분석&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  입력값을 분석하면 문제에서 요구하는 알고리즘의 시간 복잡도를 간접적으로 파악할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;N&lt;/th&gt;
&lt;th&gt;K&lt;/th&gt;
&lt;th&gt;return&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의사 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 동작 중심으로 작성하는 것이 중요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드는 문제 해결 순서로 작성합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  의사 코드를 충분히 테스트해봅니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;solution(N, K) {
    int answer = 1;
    // 큐 생성
    Queue&amp;lt;Integer&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();

    // 큐 채워넣기
    for (int i = 1;i &amp;lt;= N;i++) {
        queue.add(i);
    }

    int counter = 1;
    while (!queue.isEmpty()) {
        int first = queue.poll();
        if (counter == K) {
            answer = first;
            counter = 1;
        } else {
            queue.add(first);
            counter++;
        }
    }
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public static int solution(int N, int K) {  
    int answer = 1;  

    Queue&amp;lt;Integer&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();  

    for (int i = 1; i &amp;lt;= N; i++) {  
        queue.add(i);  
    }  
    int counter = 1;  
    while (!queue.isEmpty()) {  
        int first = queue.poll();  
        if (counter == K) {  
            answer = first;  
            counter = 1;  
        } else {  
            queue.add(first);  
            counter++;  
        }  
    }  
    return answer;  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;복기하기&lt;/b&gt;&lt;/h1&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;저자 권장 시간&lt;/th&gt;
&lt;th&gt;권장 시간 복잡도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;30분&lt;/td&gt;
&lt;td&gt;O(N*K)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;답안과 나의 풀이를 비교해보세요&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public static int solution(int N, int K) {  
    Queue&amp;lt;Integer&amp;gt; deque = new ArrayDeque&amp;lt;&amp;gt;();
    // 1부터 N까지의 번호를 deque에 추가
    for (int i = 1; i &amp;lt;= N; i++) {  
        deque.addLast(i);  
    }

    // 2. deque에 하나의 요소가 남을 때까지 반복
    while (deque.size() &amp;gt; 1) {
        // 3. K번째 요소를 찾기 위해 앞에서부터 제거하고 뒤에 추ㅏ
         for (int i = 0; i &amp;lt; K; i++) {
            deque.addLast(deque.pollFirst());
        }
        // 4. K번째 요소 ㅔ거
        deque.pollFirst();
    }
    // 5. 마지막으로 남은 요소 반환
    return deque.pollFirst();  
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내거 정확도도 맞는지 모르겠다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;요약하기&lt;/b&gt;&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;N&lt;/code&gt;은 전체 사람 수, &lt;code&gt;K&lt;/code&gt;는 제거된 사람의 번호이다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;K-1&lt;/code&gt;번 poll하고 1번 add 하는 동작을 N번 반복하므로 최종 시간 복잡도는 O(N*K)이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/코딩테스트합격자되기-자바편</category>
      <category>코딩테스트합격자되기</category>
      <author>binaryJournalist</author>
      <guid isPermaLink="true">https://binaryjourney.tistory.com/321</guid>
      <comments>https://binaryjourney.tistory.com/321#entry321comment</comments>
      <pubDate>Wed, 29 Jan 2025 14:49:36 +0900</pubDate>
    </item>
  </channel>
</rss>