<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>haing3_3.log</title>
        <link>https://velog.io/</link>
        <description>따뜻한 시선으로 세상을 변화시키는 데이터사이언티스트</description>
        <lastBuildDate>Thu, 03 Sep 2026 16:03:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>haing3_3.log</title>
            <url>https://velog.velcdn.com/images/haing3_3/profile/66c361b7-cd9d-41d2-b150-16914e0e76da/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. haing3_3.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/haing3_3" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[CV] CNN/딥러닝 기초]]></title>
            <link>https://velog.io/@haing3_3/CV-CNN%EB%94%A5%EB%9F%AC%EB%8B%9D-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@haing3_3/CV-CNN%EB%94%A5%EB%9F%AC%EB%8B%9D-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Thu, 03 Sep 2026 16:03:16 GMT</pubDate>
            <description><![CDATA[<p>classification, segmentation의 목적으로 활용이 되는 CNN</p>
<ul>
<li>kernel, filter, feature map 
pixel-feature 간 좌표 매핑은 CNN의 Feature Map</li>
</ul>
<h1 id="cnn"><strong>CNN</strong></h1>
<ul>
<li>convolutional, activation, pooling, fully connected layer를 포함한 여러 레어어 구성 </li>
<li>입력 데이터 -&gt; 기능 추출하고 feed forward process로 예측한다. </li>
</ul>
<p>convolutional layer: 입력 데이터의 로컬 영역에 filter 적용 </p>
<p>activation layer: 네트워크에 비선형성 도입 </p>
<p>pooling layer: 데이터의 공간 차원을 줄임 </p>
<p>fully connected layer: 이전 레이어의 출력을 기반으로 최종 예측 수행 </p>
<h1 id="kernel-filter-정리">Kernel, filter 정리</h1>
<ul>
<li>Kernel~=filter 은 convolutional 연산에 사용되는 작은 숫자 행렬이다. 이미지의 특성 기능과 패턴 감지하도록 설계 </li>
<li>kernel에 의해 감지된 기능의 존재의 결과를 feature map이라 한다. </li>
</ul>
<p><strong>feature map</strong>은 특징을 나타내는 3차원 텐서로 이미지와 filter와 convolutional 연산을 한 결과에 activation layer을 거쳐 ReLU와 같은 비선형 활성화 함수를 통과 시킨 결과물까지 포함한다.  </p>
<ul>
<li>필터 1개와 convolution을 수행하면 2차원 행렬 (H,W) 맵이 1장 나온다. </li>
<li>실제 CNN에서 여러개의 필터를 동시에 적용하므로, 일반적으로 feature map은 (C, H,W) 형태의 3차원 텐서가 된다. 각 채널 1장 1장이 특정 필터가 추출한 개별 특징 맵이다. </li>
</ul>
<p>만약 filter가 가장자리를 감지하도록 설계된 경우, 강도가 높은 gradient가 있는 이미지 영역을 강조해 표시한다. CNN은 여러 필터를 병렬로 사용해 이미지에서 다양한 유형의 기능을 감지하고, 이러한 필터에서 생성된 feature map을 쌓아 다음 계층에 대한 입력을 형성한다. 필터의 가중치는 훈련 중 학습되어 CNN이 이미지의 중요한 특징을 자동으로 감지할 수 있도록한다. </p>
<p>피처 맵은 이미지에서 필터를 슬라이드 하고, 이미지의 항목과 필터의 항목을 요소별로 곱하고, 해당 컨볼루션 작업의 출력이 되는 합계를 취하여 생성. </p>
<p>활성화 맵은 활성화 함수를 통해 전달된 피처 맵. 
활성화 함수는 네트워크에 비선형성을 도입하기 위해 각 컨볼루션 연산의 출력에 적용되는 비선형 함수. 
활성화 함수의 목적은 네트워크에 <strong>비선형성을 도입하</strong>여 <strong>입력과 출력 간의 복잡한 관계</strong>를 모델링할 수 있도록 하는 것. 
모델에 일부 정규화를 추가하여 과적합을 줄이는 데 도움이 된다. </p>
<p>ReLU(rectified linear unit) 활성화 함수는 모든 음수 값을 0으로 설정해 feature map에서 음수 활성화를 억제한다. activation map은 네트워크 다음 계층에 대한 입력으로 사용되고, convolution, activation, pooling process가 반복된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 20일차] 1205 ]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-20%EC%9D%BC%EC%B0%A8-1205</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-20%EC%9D%BC%EC%B0%A8-1205</guid>
            <pubDate>Fri, 05 Dec 2025 08:40:56 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-1316-그룹단위체커"><a href="https://www.acmicpc.net/problem/1316">백준 1316 그룹단위체커</a></h2>
<pre><code class="language-java">package boj_silver.p1316_그룹단위체커;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

public class Main {
    public static void main(String[] args) throws IOException {
        int cnt = 0;
        BufferedReader br  = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        for (int i = 0; i&lt; N ; i++) {
            String line = br.readLine();
            Set&lt;Character&gt; set = new HashSet&lt;&gt;();
            boolean isTrue = true;

            for (int j = 0; j &lt; line.length(); j++) {
                char c = line.charAt(j);
                //이전 문자와 다르면
                if (j &gt; 0 &amp;&amp; c != line.charAt(j - 1)) {
                    //이미 나온 문자인지 확인
                    if (set.contains(c)) {
                        isTrue = false;
                        break;
                    }
                }//if
                set.add(c);
            }
            if (isTrue) cnt++;
        }
        System.out.println(cnt);
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 19일차] 1202]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-19%EC%9D%BC%EC%B0%A8-1202</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-19%EC%9D%BC%EC%B0%A8-1202</guid>
            <pubDate>Tue, 02 Dec 2025 05:52:28 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-11866-요세푸스-문제-0">[백준 11866 요세푸스 문제 0]</h2>
<blockquote>
<h3 id="아이디어">아이디어</h3>
</blockquote>
<p>👿 *<em>핵심 파악 *</em>
    - 한줄 요약: 원형으로 앉은 N명에서 K번째마다 제거해 순서 구하기 
    - 입력: N(사람 수), K(제거 간격)
    - 출력: 제거된 순서 &lt;a, b, c, ...&gt; 형식</p>
<p>🧻 *<em>문제 분류 *</em></p>
<ul>
<li>알고리즘: 구현, 큐 회전 </li>
<li>자료구조: Queue(ArrayDeque) </li>
<li>시간 복잡도: O(n*k) -&gt; N명 제거해 각각 k-1번 회전 </li>
</ul>
<p>💡*<em>아이디어 및 의사코드 *</em> </p>
<pre><code>Queue에 1~N 넣기 

반복 ( 큐가 빌때까지 ) : 
    //K-1명을 앞에서 빼서 뒤로 보내기 
    K-1번 반복: 
        poll()하고 offer() 
    //K번째 사람 제거 
    poll()해서 결과에 추가 </code></pre><p>✅ <strong>예외상황</strong> </p>
<ul>
<li>마지막 원소 쉼표 처리 </li>
</ul>
<hr>
<pre><code class="language-java">package boj_silver.p11866_요세푸스;

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        //이중 연결 리스트로 해야하나? -&gt; 결국 생각 못함 -&gt;  원형 큐는 poll()하고 offer()하는 연산
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        StringBuilder sb =  new StringBuilder();

        //Queue에 1~N 넣기
        Queue&lt;Integer&gt; q = new ArrayDeque&lt;&gt;();
        for (int i = 1; i&lt;=n; i++){
            q.offer(i);
        }// N = 7일때 q = {1,2,3,4,5,6,7}

        sb.append(&quot;&lt;&quot;);

        while(!q.isEmpty()){
            //k-1명을 앞에서 뒤로 보내기
            for (int i =0; i&lt; k-1; i++){
                q.offer(q.poll());
            }
            sb.append(q.poll());
            //마지막이 아니면 , 추가
            if(!q.isEmpty()){
                sb.append(&quot;, &quot;);
            }
        }
        sb.append(&quot;&gt;&quot;);
        System.out.println(sb);

        sc.close();

    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 18일차] 1201]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-18%EC%9D%BC%EC%B0%A8-1201</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-18%EC%9D%BC%EC%B0%A8-1201</guid>
            <pubDate>Tue, 02 Dec 2025 04:42:50 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-4179-불"><a href="https://www.acmicpc.net/problem/4179">백준 4179 불</a></h2>
<p>소요시간 : 90분..</p>
<blockquote>
<p> <strong>아이디어</strong> </p>
</blockquote>
<ul>
<li><p><strong>핵심</strong> : 지훈이가 불보다 먼저 움직여서 가장 자리로 탈출 가능한가? </p>
</li>
<li><p><strong>문제 분류</strong>
a. 최단 거리 / 시간 -&gt; bfs 알고리즘 
b. 불과 사람이 동시에 이동 -&gt; 멀티 bfs</p>
</li>
<li><p>*<em>알고리즘 설계 *</em>
```</p>
</li>
</ul>
<ol>
<li>입력 받기 </li>
</ol>
<ul>
<li>지도 입력하며, J, F 위치 저장 </li>
<li>fireTime, exitTime 배열 -1로 초기화 </li>
</ul>
<ol start="2">
<li>불 BFS 실행 </li>
</ol>
<ul>
<li>모든 F 위치 큐에 넣고 시작 </li>
<li>4방향 탐색하며, fireTime[nx][ny] 갱신 </li>
<li>벽(#)은 지나갈 수 없음 </li>
</ul>
<ol start="3">
<li>지훈 bfs 실행 </li>
</ol>
<ul>
<li>J위치에서 시작 </li>
<li>4 방향 탐색하며: 
  a. 범위 벗어나면 탈출 성공 -&gt; 시간 출력하고 종료 
  b. 벽이거나 이미 방문 -&gt; continue
  c. 불이 먼저 도착 -&gt; contonue 
  d. 갈 수 있으면 큐에 추가 </li>
<li>큐가 비면 -&gt; IMPOSSIBLE </li>
</ul>
<ol start="4">
<li>출력 </li>
</ol>
<h2 id="">``</h2>
<pre><code class="language-java">package boj_gold.p4179_불;

//미로 문제 이구만
// 경계 설정이 잘 되야겠구만
// 아이디어: 불과 지훈이의 bfs 모두 돌려얗.ㅁ
// 불의 bfs를 먼저 돌려야함 ( 지훈이의 이동에 영향 안받음)
// 각칸에 불이 전파되는 시간을 구한다.
// 지훈이의 bfs를 돌려 이동시킨다.
    // 지훈이보다 먼저 불이 도달한 공간에는 방문할 수 없다.
    // 불이 특정 공간에 도달하는 시간 &lt;= 지훈이가 특정 공간에 도달하는 시간
// 지훈이가 배열의 범위를 벗어나면, 탈출 성공
// 배열의 범위 못벗어나면, 탈출 실패 -&gt; impossible 출력

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Answer {
    static int n, m;
    static char[][] maps;

    static int[][] fireTime; //불이 각 칸에 도달하는 시간
    static int[][] exitTime; //지훈이가 도달하는 시간


    static Queue&lt;int[]&gt; q1;
    static Queue&lt;int[]&gt; q2;

    static boolean[][] visited;
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};

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

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        fireTime = new int[n][m];
        exitTime = new int[n][m];
        q1 = new LinkedList&lt;&gt;();
        q2 = new LinkedList&lt;&gt;();

        maps = new char[n][m];


        //입력 받기 #은 0으로 생각, J는 이동 F는 불이어서 bfs로 퍼짐 // 만약 탈출되지 않으면 Impossible 출력
        // . 은  1로 생각
        for (int i = 0; i &lt; n; i++) {
            String line = br.readLine();
            for (int j = 0; j &lt; m; j++) {
                maps[i][j] = line.charAt(j);
                //시간 초기화 하기
                fireTime[i][j] = -1;
                exitTime[i][j] = -1;
                //불 인덱스 추가
                if (maps[i][j] == &#39;F&#39;) {
                    //불의 인덱스 추가
                    q1.offer(new int[]{i, j});
                    fireTime[i][j] = 0; //불 시작점은 시간 0
                } else if (maps[i][j] == &#39;J&#39;) {
                    q2.offer(new int[]{i, j});
                    exitTime[i][j] = 0; //초기화
                }
            }
        }//입력 받기

        // 불에 대한 bfs
        while (!q1.isEmpty()) {
            int[] cur = q1.poll();
            int x = cur[0];
            int y = cur[1];
            for (int i = 0; i &lt; 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                // 경계 벗어나면 x
                if (nx &lt; 0 || nx &gt;= n || ny &lt; 0 || ny &gt;= m) continue;
                //불이 먼저 오면 안됨
                if (fireTime[nx][ny] &gt;= 0 || maps[nx][ny] == &#39;#&#39;) continue;
                fireTime[nx][ny] = fireTime[x][y] + 1;
                q1.offer(new int[]{nx, ny});
            }
        }
        //지훈이 bfs
        while (!q2.isEmpty()) {
            int[] cur = q2.poll();
            int x = cur[0];
            int y = cur[1];
            for (int i = 0; i &lt; 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                //범위 벗어나면 탈출
                if (nx &lt; 0 || nx &gt;= n || ny &lt; 0 || ny &gt;= m) {
                    System.out.println(exitTime[x][y] + 1);
                    return;
                }
                if (exitTime[nx][ny] &gt;= 0 || maps[nx][ny] == &#39;#&#39;) continue;
                //불의 전파 시간이 더 먼저 오면
                // 불이 오는 칸이면 비교 fireTime == -1이면 불이 안오는 칸 -&gt; 안전

                if (fireTime[nx][ny]!= -1 &amp;&amp; fireTime[nx][ny] &lt;= exitTime[x][y] + 1) continue;
                exitTime[nx][ny] = exitTime[x][y] + 1;
                q2.offer(new int[]{nx, ny});
            }
        }
        System.out.println(&quot;IMPOSSIBLE&quot;);

    }//main


}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring MVC 1편] Sec4. Servlet, JSP, MVC 패턴 ]]></title>
            <link>https://velog.io/@haing3_3/Spring-MVC-1%ED%8E%B8-Sec4.-Servlet-JSP-MVC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@haing3_3/Spring-MVC-1%ED%8E%B8-Sec4.-Servlet-JSP-MVC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Thu, 27 Nov 2025 04:58:16 GMT</pubDate>
            <description><![CDATA[<h1 id="1-회원-관리-웹-애플리케이션-요구사항">1. 회원 관리 웹 애플리케이션 요구사항</h1>
<h2 id="핵심-기능">핵심 기능</h2>
<ul>
<li><strong>회원 저장</strong></li>
<li><strong>회원 목록 조회</strong></li>
</ul>
<h2 id="회원-정보-domain-model">회원 정보 (Domain Model)</h2>
<ul>
<li>이름 (<code>username</code>)</li>
<li>나이 (<code>age</code>)</li>
<li>도메인 객체: <code>Member</code></li>
<li>저장소: <code>MemberRepository</code> (메모리 저장소)</li>
</ul>
<h2 id="저장소-요구사항">저장소 요구사항</h2>
<ul>
<li><p><strong>싱글톤 패턴 적용</strong></p>
<ul>
<li>순수 서블릿 환경에서는 스프링이 없으므로 직접 싱글톤 생성</li>
<li><code>private static final MemberRepository instance = new MemberRepository();</code></li>
<li><code>public static MemberRepository getInstance()</code></li>
</ul>
</li>
</ul>
<h2 id="테스트-코드">테스트 코드</h2>
<ul>
<li>저장소는 메모리 기반이므로 테스트 간 영향 제외 필요</li>
<li>테스트 종료 후 store 초기화</li>
</ul>
<pre><code class="language-java">@AfterEach
void afterEach() {
    memberRepository.clearStore();
}</code></pre>
<hr>
<h1 id="2-servlet-기반-회원-관리-웹-애플리케이션">2. Servlet 기반 회원 관리 웹 애플리케이션</h1>
<p>Servlet으로 직접 HTML을 생성하며 웹 기능 구현.</p>
<h2 id="2-1-회원-등록-폼-제공-memberformservlet">2-1. 회원 등록 폼 제공 (MemberFormServlet)</h2>
<ul>
<li>사용자에게 <code>&lt;form&gt;</code> 페이지 제공</li>
<li>단순히 JSP 없이 HTML 문자열을 직접 만들어 응답</li>
</ul>
<h2 id="2-2-회원-저장-membersaveservlet">2-2. 회원 저장 (MemberSaveServlet)</h2>
<ul>
<li>HttpServletRequest에서 파라미터 조회
<code>String username = request.getParameter(&quot;username&quot;)</code></li>
<li>Member 객체 생성 → <code>memberRepository.save(member)</code></li>
<li>HTML 응답을 <strong>직접 문자열로 작성</strong>해 동적으로 출력</li>
</ul>
<p>→ <strong>HTML을 자바 코드로 직접 작성해야 해서 유지보수 매우 어려움</strong></p>
<h2 id="2-3-회원-목록-조회-memberlistservlet">2-3. 회원 목록 조회 (MemberListServlet)</h2>
<ul>
<li><code>List&lt;Member&gt; members = memberRepository.findAll()</code></li>
<li>반복문(for)을 돌면서 HTML 테이블을 자바 코드로 생성</li>
</ul>
<hr>
<h2 id="템플릿-엔진-등장-배경">템플릿 엔진 등장 배경</h2>
<p>Servlet은 HTML과 Java 코드가 섞여 복잡하고 유지보수성이 떨어짐.</p>
<p>→ HTML은 HTML대로, 동적 데이터는 템플릿 엔진에서 바꾸도록 개선</p>
<ul>
<li>JSP, Thymeleaf, Freemarker 등 등장</li>
<li>스프링 MVC에서는 JSP보다 Thymeleaf를 더 권장</li>
</ul>
<hr>
<h1 id="3-jsp로-회원-관리-웹-애플리케이션-구현">3. JSP로 회원 관리 웹 애플리케이션 구현</h1>
<p>JSP는 HTML 중심이며, 필요한 부분만 Java 코드로 삽입 가능.</p>
<h3 id="기본-문법">기본 문법</h3>
<ul>
<li>JSP 파일 선언
<code>&lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&gt;</code></li>
<li>import
<code>&lt;%@ page import=&quot;hello.servlet.domain.member.MemberRepository&quot; %&gt;</code></li>
<li>자바 코드 삽입
<code>&lt;% ... %&gt;</code></li>
<li>값 출력
<code>&lt;%= member.getUsername() %&gt;</code></li>
</ul>
<p>JSP를 통해 <strong>HTML 중심 코드 작성 + 필요한 곳만 Java 삽입</strong>이 가능해짐.</p>
<p>하지만 JSP도 여전히 문제:</p>
<ul>
<li>JSP 안에 비즈니스 로직이 섞임</li>
<li>Repository 접근 코드가 그대로 노출</li>
<li>유지보수 어려움</li>
</ul>
<hr>
<h1 id="4-servlet--jsp로-mvc-패턴-도입">4. Servlet + JSP로 MVC 패턴 도입</h1>
<p>비즈니스 로직과 화면 렌더링을 분리하기 위한 구조가 <strong>MVC 패턴</strong></p>
<hr>
<h2 id="4-1-mvc-구조">4-1. MVC 구조</h2>
<h3 id="model">Model</h3>
<ul>
<li>화면(View)에 전달할 데이터를 담는 역할</li>
<li>Servlet에서는 <code>request.setAttribute(&quot;key&quot;, value)</code> 사용</li>
</ul>
<h3 id="view">View</h3>
<ul>
<li>JSP</li>
<li>HTML 출력에 집중</li>
<li>JSP에서는 <code>${}</code> EL 문법 제공</li>
</ul>
<h3 id="controller">Controller</h3>
<ul>
<li>HttpServletRequest/Response 사용</li>
<li>비즈니스 로직 호출, 결과를 Model에 담아 View로 전달</li>
<li>View 호출: <code>request.getRequestDispatcher(viewPath).forward(req, resp)</code></li>
</ul>
<hr>
<h2 id="4-2-mvc에서-redirect와-forward-차이">4-2. MVC에서 redirect와 forward 차이</h2>
<h3 id="forward">Forward</h3>
<ul>
<li>서버 내부에서 JSP 또는 다른 Servlet을 호출</li>
<li>브라우저 주소창 URL <strong>변경 없음</strong></li>
</ul>
<h3 id="redirect">Redirect</h3>
<ul>
<li>브라우저에게 다시 요청하라고 응답</li>
<li>주소창 URL <strong>변경됨</strong></li>
<li>POST-Redirect-GET 패턴에 자주 사용</li>
</ul>
<hr>
<h1 id="5-mvc-패턴-구현-핵심-흐름">5. MVC 패턴 구현 핵심 흐름</h1>
<h2 id="5-1-등록-폼-controller">5-1. 등록 폼 Controller</h2>
<ul>
<li><code>/WEB-INF/views/new-form.jsp</code> 호출</li>
<li><code>WEB-INF</code> 내부 파일은 외부 URL 직접 접근 불가 → Controller를 반드시 거쳐야 함</li>
</ul>
<h2 id="5-2-회원-저장-controller">5-2. 회원 저장 Controller</h2>
<ul>
<li>폼 데이터 조회</li>
<li>Member 저장</li>
<li>request.setAttribute()로 View에 데이터 전달</li>
<li>결과 JSP forward</li>
</ul>
<h2 id="5-3-회원-목록-controller">5-3. 회원 목록 Controller</h2>
<ul>
<li><code>List&lt;Member&gt;</code> 조회 후 request에 저장</li>
<li>JSP에서 JSTL <code>&lt;c:forEach&gt;</code> 로 반복 렌더링</li>
</ul>
<p>JSTL 예:</p>
<pre><code class="language-jsp">&lt;c:forEach var=&quot;item&quot; items=&quot;${members}&quot;&gt;
    &lt;tr&gt;
        &lt;td&gt;${item.id}&lt;/td&gt;
        &lt;td&gt;${item.username}&lt;/td&gt;
        &lt;td&gt;${item.age}&lt;/td&gt;
    &lt;/tr&gt;
&lt;/c:forEach&gt;</code></pre>
<hr>
<h1 id="6-mvc-패턴의-한계">6. MVC 패턴의 한계</h1>
<p>컨트롤러와 뷰는 분리되었지만 여전히 다음 문제가 존재함.</p>
<h3 id="1-view-호출-코드-중복">1) View 호출 코드 중복</h3>
<ul>
<li><code>dispatcher.forward()</code> 반복</li>
<li>viewPath 반복
<code>/WEB-INF/views/</code> + viewName + <code>.jsp</code></li>
</ul>
<h3 id="2-httpservletrequestresponse-의존">2) HttpServletRequest/Response 의존</h3>
<ul>
<li>컨트롤러가 서블릿 API에 강하게 결합됨</li>
<li>테스트 코드 작성 어려움</li>
</ul>
<h3 id="3-공통-로직-처리-어려움">3) 공통 로직 처리 어려움</h3>
<ul>
<li>각 컨트롤러마다 중복되는 로직(로그, 인증, 예외 처리 등) 존재</li>
<li>이를 공통 처리하려면 별도 도구 필요</li>
</ul>
<hr>
<h2 id="7-front-controller-패턴-mvc-프레임워크의-핵심">7. Front Controller 패턴 (MVC 프레임워크의 핵심)</h2>
<p>위 문제를 해결하기 위해 등장한 패턴.</p>
<ul>
<li><strong>모든 요청은 FrontController(Servlet) 한 곳으로 들어온다</strong></li>
<li>공통 로직은 FrontController에서 처리</li>
<li>실제 비즈니스 처리는 각 컨트롤러로 위임</li>
<li>스프링 MVC의 DispatcherServlet이 이 패턴 기반</li>
</ul>
<p>→ 이를 기반으로 하면 우리가 <strong>직접 작은 MVC 프레임워크를 만들 수도 있다.</strong></p>
<hr>
<h1 id="✨-핵심-요약">✨ 핵심 요약</h1>
<ol>
<li>Servlet만 사용하면 HTML을 Java 코드로 생성해야 하므로 유지보수 최악</li>
<li>JSP 도입 → HTML 중심 코딩 가능해졌지만 비즈니스 로직 섞이는 문제 존재</li>
<li>MVC 패턴 → Controller, View, Model 분리</li>
<li>하지만 MVC 구조에서도 forward/viewPath 중복, 공통 기능 처리 어려움</li>
<li>Front Controller(DispatcherServlet)로 모든 문제 해결
→ 스프링 MVC는 이를 기반으로 만든 완성형 구조</li>
</ol>
<hr>
<h3 id="출처">출처</h3>
<blockquote>
</blockquote>
<ul>
<li><a href="https://www.inflearn.com/courses/lecture?courseId=326674&amp;type=LECTURE&amp;unitId=71178&amp;subtitleLanguage=ko">김영한의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 17일차] 1127]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-17%EC%9D%BC%EC%B0%A8-1127</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-17%EC%9D%BC%EC%B0%A8-1127</guid>
            <pubDate>Thu, 27 Nov 2025 00:59:17 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-15649-n과m1"><a href="https://www.acmicpc.net/problem/15649">백준 15649 N과M(1)</a></h2>
<blockquote>
<p><strong>중복 없는 순열</strong> </p>
</blockquote>
<ul>
<li>index를 기준으로 인덱스가 m이 되는 순간 출력한다. </li>
<li>선택할 배열에 숫자를 넣으면서 index+1을 담은 변수로 재귀 호출을 한 뒤, boolean 배열을 다시 false로 백트래킹한다. </li>
</ul>
<pre><code class="language-java">import java.util.Scanner;

public class Main {
    static boolean[] isSelected;
    static int[] select;
    static int n, m ;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //1부터 n까지 중복없이 m개를 고른 수열
        //n = 3, m = 2
        n = scan.nextInt();
        m = scan.nextInt();
        select = new int[m];
        isSelected = new boolean[n];


        combi(0);//index
    }
    static void combi(int index){
        StringBuilder sb = new StringBuilder();
        if (index&gt;=m){
            //출력
            for (int i = 0; i&lt;m; i++){
                sb.append(select[i]).append(&quot; &quot;);
            }
            System.out.println(sb);
            return;
        }

        for (int i=0; i&lt;n; i++){
            if(!isSelected[i]){
                //select[index]
                select[index] = i+1;
                isSelected[i] = true;
                combi(index+1);
                isSelected[i] = false;
            }
        }


    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 16일차] 1126]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-16%EC%9D%BC%EC%B0%A8-1126</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-16%EC%9D%BC%EC%B0%A8-1126</guid>
            <pubDate>Thu, 27 Nov 2025 00:54:49 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-1417-국회의원-선거"><a href="https://www.acmicpc.net/problem/1417">백준 1417 국회의원 선거</a></h2>
<blockquote>
<p><strong>아이디어</strong></p>
</blockquote>
<ul>
<li>다솜밖에 없는 경우 출력 </li>
<li>다솜 제외하고, 정렬한후 마지막 인덱스부터 비교하면서, 1표씩 가져오기 (다솜이가 많을때 break문으로 빠져나옴) </li>
</ul>
<pre><code class="language-java">import java.util.Arrays;
import java.util.Scanner;

public class Main {
    //배열에 저장하자
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n= scan.nextInt();

        int som = scan.nextInt();
        if(n==1){
            System.out.println(0);
            return;
        }

        int[] candi = new int[n-1];

        for (int i = 0; i &lt;n-1; i++) {
            candi[i] = scan.nextInt(); //1번이 많아야함. 그럼 일단 정렬해보고.
        }
        int cnt =0;
        //비교해서 정렬해야하나
        while(true){
            //다솜이 1등 될때까지 반복
            Arrays.sort(candi);
            int maxIdx = n-2; //마지막 인덱스
            if (som &gt; candi[maxIdx]){
                break;
            }
            //가장 많이 득표한 후보 1표 가져오기
            candi[maxIdx]--;
            som++;
            cnt++;
        }
        System.out.println(cnt);


    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring MVC 1편] Sec3. Servlet ]]></title>
            <link>https://velog.io/@haing3_3/Spring-MVC-1%ED%8E%B8-Sec3.-Servlet</link>
            <guid>https://velog.io/@haing3_3/Spring-MVC-1%ED%8E%B8-Sec3.-Servlet</guid>
            <pubDate>Wed, 26 Nov 2025 06:38:25 GMT</pubDate>
            <description><![CDATA[<h1 id="11-hello-서블릿">11. Hello 서블릿</h1>
<p>스프링 부트 환경에서도 톰캣을 별도로 설치하지 않아도 서블릿을 사용할 수 있다.
스프링 부트는 <strong>내장 톰캣(Embedded Tomcat)</strong>을 내장하고 있기 때문이며,
서블릿을 등록하면 자동으로 서블릿 컨테이너가 초기화된다.</p>
<h2 id="111-스프링-부트-서블릿-환경-구성">11.1 스프링 부트 서블릿 환경 구성</h2>
<p><strong>@WebServlet</strong> 애노테이션을 통해 서블릿 등록 가능.</p>
<ul>
<li><strong>name</strong>: 서블릿 이름</li>
<li><strong>urlPatterns</strong>: 어떤 URL을 서블릿과 매핑할지 결정</li>
</ul>
<p>예시:</p>
<pre><code class="language-java">@WebServlet(name = &quot;helloServlet&quot;, urlPatterns = &quot;/hello&quot;)
public class HelloServlet extends HttpServlet { ... }</code></pre>
<p>Spring Boot는 <strong>@ServletComponentScan</strong>이 붙은 패키지에서 @WebServlet 등을 자동 스캔해준다.</p>
<h3 id="httpservletrequest-활용">HttpServletRequest 활용</h3>
<pre><code class="language-java">String username = request.getParameter(&quot;username&quot;);</code></pre>
<p>→ GET 쿼리 파라미터, POST form 모두 이 방식으로 조회 가능.</p>
<h3 id="톰캣-내부-요청-로그-보기">톰캣 내부 요청 로그 보기</h3>
<pre><code class="language-properties">logging.level.org.apache.coyote.http11=trace</code></pre>
<p>→ HTTP 요청/응답이 내부에서 어떻게 처리되는지 확인할 수 있다.</p>
<hr>
<h2 id="112-서블릿-컨테이너-동작-방식-핵심">11.2 서블릿 컨테이너 동작 방식 핵심</h2>
<ul>
<li><strong>WAS(톰캣)는 Http 요청이 오면 Request/Response 객체를 만들어 서블릿에게 전달한다.</strong></li>
<li>개발자는 서블릿 내부에서 요청 객체를 조회하면서 응답을 작성한다.</li>
<li>WAS는 서블릿이 만든 Response 내용을 바탕으로 HTTP 응답 메시지를 최종 조립하여 클라이언트에게 보낸다.</li>
</ul>
<p>즉, <strong>WAS는 HTTP 요청/응답 메시지를 대신 만들어주고</strong>,
서블릿은 그 안의 <strong>비즈니스 로직을 실행하는 코드</strong>이다.</p>
<hr>
<h2 id="113-welcome-페이지-추가">11.3 welcome 페이지 추가</h2>
<p>static 폴더에 <code>index.html</code>을 두면 자동으로 welcome 페이지로 매핑된다.</p>
<hr>
<h1 id="12-httpservletrequest">12. HttpServletRequest</h1>
<h2 id="121-역할">12.1 역할</h2>
<p>HTTP 메시지를 개발자가 직접 파싱하지 않도록
서블릿 컨테이너가 <strong>HTTP 요청 메시지를 해석하여</strong>
start-line, header, body 정보를 <strong>HttpServletRequest 객체에 담아 제공</strong>한다.</p>
<p>즉, <strong>HTTP 스펙을 더 쉽게 사용하도록 만들어주는 추상화 계층</strong>이다.</p>
<hr>
<h2 id="122-http-요청-메서드-예시">12.2 Http 요청 메서드 예시</h2>
<pre><code>POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded

username=kim&amp;age=20</code></pre><p>request 객체는 다음과 같은 정보 조회를 지원한다.</p>
<ul>
<li><code>request.getMethod()</code></li>
<li><code>request.getRequestURL()</code>, <code>getRequestURI()</code></li>
<li><code>request.getHeader(&quot;Host&quot;)</code></li>
<li><code>request.getParameter(&quot;username&quot;)</code></li>
</ul>
<hr>
<h3 id="부가기능--임시-저장소">부가기능 – 임시 저장소</h3>
<p><strong>요청 단위로 유지되는 저장소 기능</strong></p>
<pre><code class="language-java">request.setAttribute(&quot;key&quot;, value);
request.getAttribute(&quot;key&quot;);</code></pre>
<p>Filter → Controller 등 여러 계층에서 데이터를 공유할 때 유용하다.</p>
<hr>
<h3 id="세션-관리-기능">세션 관리 기능</h3>
<p><code>request.getSession()</code>을 통해 세션 생성/조회 가능
→ 로그인, 장바구니 등 사용자 상태 유지에 사용</p>
<hr>
<h3 id="핵심">핵심</h3>
<blockquote>
<p><strong>HttpServletRequest와 HttpServletResponse는 HTTP 메시지를 다루기 쉽게 도와주는 도구일 뿐이다.</strong>
따라서 <strong>HTTP 메시지 구조(start-line, header, body)를 정확히 이해하는 것</strong>이 더 중요하다.</p>
</blockquote>
<hr>
<h2 id="123-기본-사용법-확인">12.3 기본 사용법 확인</h2>
<p>요청 라인(start-line) 및 header를 읽는 예:</p>
<pre><code>request.getMethod() = GET
request.getProtocol() = HTTP/1.1
request.getRequestURL() = http://localhost:8080/request-header
request.getRequestURI() = /request-header
request.getQueryString() = null
request.isSecure() = false</code></pre><hr>
<h2 id="http-요청-데이터-종류">HTTP 요청 데이터 종류</h2>
<p>서버로 데이터를 전달하는 방식은 3가지이다.</p>
<h3 id="1-get--쿼리-파라미터">1) GET – 쿼리 파라미터</h3>
<ul>
<li>URL 뒤에 <code>?username=hello&amp;age=20</code></li>
<li>message body 없음</li>
<li>검색, 필터링에 자주 사용</li>
</ul>
<h3 id="2-post--html-form">2) POST – HTML Form</h3>
<ul>
<li>Content-Type: <code>application/x-www-form-urlencoded</code></li>
<li>message body 안에 <code>key=value&amp;key2=value2</code> 형태</li>
<li>회원가입, 로그인 등 form 기반 요청</li>
</ul>
<h3 id="3-http-message-bodyraw-body">3) HTTP Message Body(raw body)</h3>
<ul>
<li>JSON, XML, text 등</li>
<li>Content-Type: <code>application/json</code> 등</li>
<li>API 서버에서 가장 많이 쓰는 방식</li>
</ul>
<hr>
<h1 id="19-httpservletresponse">19. HttpServletResponse</h1>
<h2 id="191-기본-사용법">19.1 기본 사용법</h2>
<p>서버가 클라이언트에게 <strong>HTTP 응답 메시지를 작성해서 보내는 객체</strong></p>
<h3 id="http-응답-메시지-구성-요소">HTTP 응답 메시지 구성 요소</h3>
<ol>
<li><p><strong>status line</strong></p>
<ul>
<li><code>response.setStatus(200)</code></li>
</ul>
</li>
<li><p><strong>header</strong></p>
<ul>
<li><code>response.setHeader(&quot;Content-Type&quot;, &quot;text/plain&quot;)</code></li>
</ul>
</li>
<li><p><strong>body</strong></p>
<ul>
<li><code>response.getWriter().write(&quot;ok&quot;)</code></li>
</ul>
</li>
</ol>
<hr>
<h2 id="편의-기능">편의 기능</h2>
<ul>
<li>Content-Type 지정
<code>response.setContentType(&quot;text/html&quot;)</code></li>
<li>Character Encoding
<code>response.setCharacterEncoding(&quot;utf-8&quot;)</code></li>
<li>쿠키 생성
<code>response.addCookie(cookie)</code></li>
<li>리다이렉트
<code>response.sendRedirect(&quot;/new-url&quot;)</code></li>
</ul>
<hr>
<h2 id="192-http-응답-데이터-형태">19.2 Http 응답 데이터 형태</h2>
<h3 id="1-단순-텍스트">1) 단순 텍스트</h3>
<pre><code class="language-java">response.getWriter().write(&quot;Hello&quot;);</code></pre>
<h3 id="2-html-응답">2) HTML 응답</h3>
<pre><code class="language-java">response.setContentType(&quot;text/html&quot;);
response.getWriter().write(&quot;&lt;html&gt;...&lt;/html&gt;&quot;);</code></pre>
<h3 id="3-json-응답">3) JSON 응답</h3>
<pre><code class="language-java">response.setContentType(&quot;application/json&quot;);
response.getWriter().write(objectMapper.writeValueAsString(obj));</code></pre>
<p>※ <code>application/json</code>은 charset 파라미터를 지원하지 않으므로,
문자 인코딩은 response의 CharacterEncoding으로 지정한다.</p>
<hr>
<h1 id="✨-서블릿-핵심-요약">✨ 서블릿 핵심 요약</h1>
<ol>
<li><p><strong>서블릿은 WAS 내부에서 실행되는 자바 클래스</strong>
→ HTTP 요청/응답을 처리하기 위한 기반 기술</p>
</li>
<li><p><strong>HttpServletRequest는 HTTP 요청 메시지를 자동으로 파싱하여 제공</strong>
→ 쿼리 파라미터, header, body, 세션 등</p>
</li>
<li><p><strong>HttpServletResponse는 HTTP 응답 메시지를 쉽게 생성하도록 도와줌</strong></p>
</li>
<li><p><strong>GET/POST 차이의 본질은 데이터 전달 위치 (URL vs Body)</strong></p>
</li>
<li><p><strong>JSON 기반 API는 Message Body를 직접 읽고 객체로 변환하여 사용</strong></p>
</li>
</ol>
<hr>
<h3 id="출처">출처</h3>
<blockquote>
</blockquote>
<ul>
<li><a href="https://www.inflearn.com/courses/lecture?courseId=326674&amp;type=LECTURE&amp;unitId=71178&amp;subtitleLanguage=ko">김영한의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술</a></li>
<li><a href="https://sigridjin.medium.com/servletcontainer%EC%99%80-springcontainer%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%B8%EA%B0%80-626d27a80fe5">ServletContainer와 SpringContainer는 무엇이 다른가?</a>
Controller 1개는 어떻게 수십 만개의 요청을 처리하는가 </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 15일차] 1125]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-15%EC%9D%BC%EC%B0%A8-1125</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-15%EC%9D%BC%EC%B0%A8-1125</guid>
            <pubDate>Tue, 25 Nov 2025 10:39:33 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-10282-해킹"><a href="https://www.acmicpc.net/problem/10282">백준 10282 해킹</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>입력 : 테스트 케이스 T만큼 반복하고, n: 컴퓨터 개수 / d: 간선개수 / c: 시작 번호 </li>
<li>자료 구조 ArrayList<Node>[] list로 각 1부터..n까지의 list 초기화 시켜야함 ! </li>
<li>간선 입력 </li>
<li>dist거리 선언하고, max_value로 초기화 -&gt;dist[c] =0으로 초기화 </li>
<li>PriorityQueue<Node> pq 선언하고 오름차순 정렬 
pq.offer(new Node(c, 0));//거리 w를 0으로 초기화 </li>
<li><pre><code>//while(큐가 빌때까지): 
    Node cur = pq.poll()l; //현재 노드 빼내오기
    int curV = cur.v; //현재 정점
    int curD = cur.w; //현재 거리 
//이미 처리된 노드이면 continue 
//현재 노드와 연결된 간선 탐색 
    //누적 거리 
    // 더 짧은 노드 발견하면 갱신하고, 새로운 노드 큐에 넣기 </code></pre></li>
</ul>
<p>  코드 </p>
<pre><code class="language-java">package boj_gold.p10282_해킹;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

class Node{
    int v;
    int w;

    public Node(int v, int w){
        this.v = v;
        this.w =w;
    }
}
public class Main {
    static int[] dist;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int T = Integer.parseInt(st.nextToken());
        StringBuilder sb = new StringBuilder();

        for(int i = 0; i &lt; T; i++){
            st = new StringTokenizer(br.readLine());
            int n = Integer.parseInt(st.nextToken());// 컴퓨터 개수
            int d = Integer.parseInt(st.nextToken()); //간선 개수
            int c =  Integer.parseInt(st.nextToken()); //시작 번호

            ArrayList&lt;Node&gt;[] list = new ArrayList[n+1];
            //그래프 초기화
            for (int j= 1; j&lt;=n; j++){
                list[j] = new ArrayList&lt;&gt;();
            }
            //간선 입력
            for (int j = 0; j&lt; d; j++){
                st = new StringTokenizer(br.readLine());
                int v = Integer.parseInt(st.nextToken());
                int u = Integer.parseInt(st.nextToken());
                int w = Integer.parseInt(st.nextToken());
                list[u].add(new Node(v,w));
            }

            // 입력받기
            //각 dist초기화하기
            dist = new int[n+1];
            Arrays.fill(dist, Integer.MAX_VALUE);  //dist 초기화한후 min으로 업데이트 한다.
            //처음 값 초기화
            dist[c] = 0;

            //prioirty Queue로 가중치 오름추순 정렬
            PriorityQueue&lt;Node&gt; pq = new PriorityQueue&lt;&gt;((a,b)-&gt; a.w-b.w);
            pq.offer(new Node(c, 0)); //거리를 0으로 초기화

            //pq가 빌때까지 반복
            while(!pq.isEmpty()){
                //큐
                Node cur = pq.poll();
                int curV = cur.v; //현재 정점
                int curD = cur.w; //현재 거리

                //이미 처리된 노드이면 continue
                if (curD &gt; dist[curV]){
                    continue;
                }
                //현재 노드와 연결된 간선 탐색
                for (Node next: list[curV]){
                    int nextV = next.v;
                    int nextD = curD + next.w; //누적 거리

                    //더 짧은 노드 발견하면 갱신
                    if(nextD &lt; dist[nextV]){
                        dist[nextV] = nextD;
                        pq.offer(new Node(nextV, nextD));
                    }
                }
            }//while
            //출력을 해야하는데: 감염된 컴퓨터 수와 마지막 감염 시간
            int cnt= 0;
            int time = 0; //마지막 감염 시간

            for (int j = 1; j &lt;=n; j++){
                //dist가 업데이트가 된 것
                if (dist[j] != Integer.MAX_VALUE){
                    cnt++;
                    time = Math.max(time, dist[j]);
                }
            }//for
            sb.append(cnt).append(&quot; &quot;).append(time).append(&quot;\n&quot;);




         }//for 
        System.out.println(sb);


    }
}

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 14일차] 1124]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-14%EC%9D%BC%EC%B0%A8-1124</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-14%EC%9D%BC%EC%B0%A8-1124</guid>
            <pubDate>Mon, 24 Nov 2025 05:34:37 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-1753-최단경로"><a href="https://www.acmicpc.net/problem/1753">백준 1753 최단경로</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>간선을 저장하는 자료구조는 ArrayList[] list를 만들고, Edge class의 객체를 생성한다. </li>
<li>Edge 클래스는 도착점과 가중치가 저장된다. </li>
<li>dist[] 배열로 최소값 저장 
```</li>
</ul>
<ol>
<li>dist 배열 선언 및 초기화 (Max value로 초기화) </li>
<li>우선순위 큐 선언 (가중치 기준 오름차순) </li>
<li>시작점을 pq에 넣기 (시작점, 거리)</li>
<li>다익스트라 알고리즘 </li>
</ol>
<ul>
<li>while (pq가 빌때까지): 
  //pq에서 현재 노드 꺼내기 
  //이미 처리된 노드면 continue
  if(현재까지의 거리 &gt;  현재 거리) continue; 
  //현재 노드와 연결된 모든 간선 탐색 
  //더 짧으면 갱신 </li>
</ul>
<pre><code>



```java
    static int V, E, K;
    static ArrayList&lt;Edge&gt;[] graph; //전역 변수
    static StringBuilder sb;

    public static void main(String[] args) throws IOException{
        input();
        solution(K);

    }
    static void solution(int start){//bfs처럼 생각
        //1. 거리 배열 선언 및 초기화
        int[] dist = new int[V+1];
        //dist를 무한대로 초기화
        Arrays.fill(dist, Integer.MAX_VALUE);
        //dist[start] = 0
        dist[start] =0;

        //2. 우선순위 큐 선언( 가중치 기준 오름차순)
        PriorityQueue&lt;Edge&gt; pq = new PriorityQueue&lt;&gt;((a,b)-&gt; a.w- b.w);

        //시작점 pq에 넣기
        pq.offer(new Edge(start, 0)); //번호: start, 거리: 0

        //출력
        while(!pq.isEmpty()){
            Edge cur = pq.poll();
            int curN = cur.v; //현재 정점
            int curD = cur.w; //현재 거리
            //이미 처리된 노드이면 continue ( 더 짧은 경로로 이미 갱신)
            if (curD &gt; dist[curN]){
                continue;
            }
            //현재 노드와 연결된 간선 탐색
            for (Edge next: graph[curN]){
                int nextN = next.v;
                int nextD = curD + next.w;
                //더 짧은 경로 발견하면 갱신
                if(nextD &lt; dist[nextN]){
                    dist[nextN] = nextD;
                    pq.offer(new Edge(nextN, nextD));
                }

            }
        }//while
        //출력
        sb = new StringBuilder();
        for (int i = 1; i &lt;= V; i++){
            if(dist[i] ==Integer.MAX_VALUE){
                sb.append(&quot;INF\n&quot;);
            }else{
                sb.append(dist[i]).append(&quot;\n&quot;);
            }
        }
        System.out.println(sb);

    }</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 13일차] 1121]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-13%EC%9D%BC%EC%B0%A8-1121</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-13%EC%9D%BC%EC%B0%A8-1121</guid>
            <pubDate>Mon, 24 Nov 2025 01:09:34 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-1654-랜선-자르기"><a href="https://www.acmicpc.net/problem/1654">백준 1654 랜선 자르기</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>처음에 이분탐색인지 모르겠음. </li>
<li>의사코드 <pre><code>left = 1, right = max(랜선들) 
while(left &lt;=right): 
  mid = (left+right) / 2
  if(mid로 잘랐을때 개수가 N이상이면): //길이를 늘려야함 
      answer = mid; //저장 
      left = mid+1; 
  else: 
      right= mid -1; </code></pre></li>
</ul>
<pre><code class="language-java">package boj_silver.p1654_랜선자르기;

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int ans;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int k = scan.nextInt(); int n = scan.nextInt();
        //k개 입력 받기
        //랜선 길이가 최대 2^32 - 1이므로 long 사용
        long[] arr = new long[k];
        for (int i = 0; i &lt; k; i++) {
            arr[i] = scan.nextLong();
        }
        long left = 1;
        long right = 0;
        //최댓값
        for (int i = 0; i &lt; k; i++) {
            right = Math.max(right, arr[i]);
        }
        long ans = 0;

        while(left&lt;=right){
            long mid = (left+right)/ 2;
            //돌면서
            long sum = 0;
            for (int i = 0; i&lt; k; i++){
                sum += arr[i] / mid;
            }
            if(sum&gt;=n){
                ans = mid;
                left = mid+1;
            }else{
                right = mid-1;
            }
        }//while
        System.out.println(ans);

    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 12일차] 1120 ]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-12%EC%9D%BC%EC%B0%A8-1120</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-12%EC%9D%BC%EC%B0%A8-1120</guid>
            <pubDate>Fri, 21 Nov 2025 02:26:03 GMT</pubDate>
            <description><![CDATA[<h2 id="1--백준-2579-계단오르기">1.  <a href="https://www.acmicpc.net/problem/2579">백준 2579 계단오르기</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>dp[n]까지 점화식 만들고, dp[n]출력 </li>
<li>점화식: <code>dp[i] = Math.max(dp[i-3] + stairs[i-1] + stairs[i] , dp[i-2] + stairs[i]);</code></li>
</ul>
<pre><code class="language-java">package boj_silver.p2579_계단오르기;

import java.util.Scanner;

public class Review1 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int[] stairs = new int[n+1];
        for (int i = 1; i&lt;=n; i++){
            stairs[i] = scan.nextInt();
        }
        //dp 초기화
        int [] dp = new int[n+1];
        //만약 계단이 적다면 !
        dp[0] = 0;
        if (n&gt;=1){
            dp[1] = stairs[1];
        }
        if(n&gt;=2){
            dp[2] =  stairs[1] + stairs[2];
        }
        if (n&gt;=3){
            //dp 식
            for (int i = 3; i&lt;=n; i++){
                dp[i] = Math.max(dp[i-3] + stairs[i-1] + stairs[i], dp[i-2] + stairs[i]);
            }

        }
        System.out.println(dp[n]);


    }
}
</code></pre>
<h3 id="bottom-up-dp-내-방식-개선">Bottom-Up DP (내 방식 개선)</h3>
<pre><code class="language-java">int[] dp = new int[n+1]; 
dp[1] =stairs[1]; 
if(n&gt;=2) dp[2] = stairs[1] + stairs[2];
for (int i = 3; i&lt;=n;i++){
    dp[i] = Math.max(
        dp[i-2] + stairs[i], //2칸 점프 
        dp[i-3] + stairs[i-1] + stairs[i] //1칸씩 2번 
    );
}//for     </code></pre>
<p>*<em>일반적이고 이해하기 쉽다. 단점은 배열 사용으로 메모리가 O(n) *</em> </p>
<h3 id="top-down-dp-재귀--메모이제이션">Top-Down DP (재귀 + 메모이제이션)</h3>
<pre><code class="language-java">static Integer[] dp; //null 체크 위해 Integer 사용 
public static void main(String[] args) {
    dp[0]= 0; 
    dp[1] = stairs[1]; 
    if(n&gt;=2) dp[2]= stairs[1] + stairs[2]; 
    System.out.println(solve(n)); 
}//main

static int solve(int n){
    //이미 계산된것 건너뛰기 
    if(dp[n]!=null) return dp[n]; 

    dp[n]= Math.max(
        solve(n-2) + stairs[n], 
        solve(n-3)+ stairs[n-1] + stairs[n]
    ); 
    return dp[n]; 
}//solve: 재귀 </code></pre>
<h2 id="2-백준-1259-팰린드롬수">2. <a href="https://www.acmicpc.net/problem/1259">백준 1259 팰린드롬수</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>처음에는 queue로 해서 앞에 있는것과 peek를 비교해서 양 옆을 제거하고 싶었으나 마지막에 들어온 것 제거하는 방법 모름 =&gt; //Deque 사용하면 양쪽 삽입 삭제 가능 </li>
<li>그래서 그냥 배열로 받아 양쪽 비교하고, 안맞는 즉시 flag = false로 하고 바로 break함. <pre><code class="language-java">package boj_bronze.p1259_팰린드롬수;
</code></pre>
</li>
</ul>
<p>import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;</p>
<p>public class Main {
    public static void main(String[] args)throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            String str = br.readLine();
            //종료
            if(str.equals(&quot;0&quot;)){
                return;
            }
            //char로 바꾸기 !
            Character[] chars = new Character[str.length()];
            for (int i = 0; i &lt; str.length(); i++) {
                chars[i] = str.charAt(i);
            }
            int n = chars.length;
            boolean flag = true;</p>
<pre><code>        for(int i = 0; i&lt; n; i++){
            if (chars[i]  != chars[n-i-1]){
                //하는 순간 바로 flag = false
                flag = false;
                break;
            }
        }
        if(flag){
            System.out.println(&quot;yes&quot;);
        }else{
            System.out.println(&quot;no&quot;);
        }



    }//while 입력 받기


}</code></pre><p>}</p>
<pre><code>** 내방법의 시간 복잡도와 공간 복잡도는 O(n)이다. 투 포인터로 사용하면 공간 복잡도는 O(1)로 효율적으로 구현할 수 있다. 추가 메모리 없이 charAt()만 사용한다. 
```java
//main 메서드 
while(true){
    String str = br.readLine(); 
    if(str.equals(&quot;0&quot;)) break; //0들어오면 바로 입력 종료 

    //함수 적용해서 팰린드롬수가 맞으면, yes 아니면 no출력한다. 
    sb.append(isPalindrom(str) ? &quot;yes&quot; :&quot;no&quot;).append(&quot;\n&quot;);     
}//while 
//출력 
System.out.print(sb); 

//isPalindrom함수 
static boolean isPalindrome(String s){
    int l = 0; int r = s.length()-1; 

    while(l&lt;r){
        if(s.charAt(l++) !=s.charAt(r--)){
            return false; 
        }
    }//whie
    return true; 
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 11일차] 1119]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-11%EC%9D%BC%EC%B0%A8-1119</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-11%EC%9D%BC%EC%B0%A8-1119</guid>
            <pubDate>Thu, 20 Nov 2025 00:33:57 GMT</pubDate>
            <description><![CDATA[<h2 id="1--백준-11650-좌표-정렬하기">1.  <a href="https://www.acmicpc.net/problem/11650">백준 11650 좌표 정렬하기</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>정렬 -&gt; Comparator를 람다식으로 표현하기 -&gt; ```Arrays.sort(xy, (a, b) -&gt; {
  if (a[0] != b[0]) {<pre><code>  return a[0] - b[0];</code></pre>  } else {<pre><code>  return a[1] - b[1];</code></pre>  }
});```</li>
<li>추가적 방법 
(삼항 연산자) 
<code>Arrays.sort(xy, (a,b)-&gt; a[0] !=b[0] ? a[0]- b[0] : a[1]-b[1]</code>
(Compator 메서드 체이닝)
<code>Arrays.sort(xy, Comparator.comparingInt(int[] a) -&gt; a[0]).thenComparingInt(a-&gt; a[1]));</code></li>
</ul>
<pre><code class="language-java">package boj_silver.p11650_좌표정렬;
import java.io.*;
import java.util.*;

//좌표정렬: x-&gt; y
public class Review2 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        int n = Integer.parseInt(br.readLine());
        int[][] xy = new int[n][2];

        for (int i = 0; i&lt;n; i++){
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            xy[i][0] = a;
            xy[i][1] = b;
        }
        Arrays.sort(xy, (a,b) -&gt; {
            if (a[0] !=b[0]) {
                return a[0] - b[0];
            }else{
                return a[1] - b[1];
            }
        });
        for (int[] num: xy){
            int a = num[0];
            int b = num[1];
            System.out.println(a + &quot; &quot; + b);
        }
        br.close();
        //정렬

    }

}</code></pre>
<h2 id="2-프로그래머스-lv1-k번째-수">2. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/42748">프로그래머스 lv1. k번째 수</a></h2>
<blockquote>
<p><strong>아이디어</strong> 
문제: array의 i번째~j번째 까지 자르고 정렬하고 k번째 있는 수 구하기 </p>
</blockquote>
<ul>
<li>배열 복사 후 정렬해야함. <code>int[] tmp = Arrays.copyOfRange(array, s-1, e);</code></li>
<li>리스트에 tmp[k-1] 추가한다. </li>
<li>리스트를 Array로 바꿈 <code>list.stream().mapToInt(Integer::intValue).toArray();</code></li>
</ul>
<h3 id="stream-기초-문법-및-예시-코드">Stream() 기초 문법 및 예시 코드</h3>
<p>Stream API는 collection, array등의 데이터를 다루기 위한 함수형 프로그래밍 방식을 제공한다. 기능을 구현하지 않고, 선언형으로 컬랙션 형을 처리할 수 있다. (반복문, 조건문) </p>
<h4 id="문법-구조">문법 구조</h4>
<blockquote>
<p>생성하기 - 가공하기 - 결과 만들기 </p>
</blockquote>
<pre><code class="language-java">List&lt;String&gt; fruits = Arrays.asList(&quot;apple&quot;, &quot;banana&quot;, &quot;apple&quot; &quot;orange&quot;, &quot;kiwi&quot;, &quot;watermelon&quot;); 

//1. filter()로 원하는요소 출력하기 
fruits.stream() //stream 생성 
    .filter(fruit-&gt; fruit.startwiith(&quot;a&quot;)) //가공하기 
    .forEach(System.out::println);  //결과 만들기 
    // 출력: apple apple 

// 2. map(): 매핑처리로 리스트 내 모든 값을 키_값 형태로 처리한다. 
fruits.stream()
        .map(fruit -&gt; fruit.toUpperCase())
        .forEach(System.out::println); 
        // 출력: APPLE BANANA APPLE ORANGE KIWI WATERMELON

//3. sorted() 
fruits.stream()
        .sorted()
        .forEach(System.out::println); 
        // 출력: apple apple banana kiwi orange watermelon

//4. reduce()
String result = fruits.stream()
                        .reduce(&quot;&quot;, (s1, s2)-&gt; s1+s2); 
System.out.println(result); 

//5. distinct() 
fruits.stream()
        .distinct()
        .forEach(System.out::println);
        // 출력: apple banana orange kiwi watermelon
//6. limit()
fruits.stream()
        .limit(3) 
        .forEach(System.out::println);
        // 출력: apple banana apple

//7. skip()
fruits.stream()
              .skip(2)
              .forEach(System.out::println);
        // 출력: apple orange kiwi watermelon

//8. count()
long count = fruits.stream()
                    .count(); 
System.out.println(count);  //출력: 6

</code></pre>
<h4 id="stream-중간-연산에서-자주-쓰이는-가공-메서드">Stream 중간 연산에서 자주 쓰이는 가공 메서드</h4>
<ul>
<li>filter() : 특정 조건에 부합하는 stream 전개 </li>
<li>map(): 매핑처리로 리스트내 모든 값을 키/값 형태로 처리한다. </li>
<li>sorted(): 알파벳 순으로 정렬 </li>
<li>reduce(): 모든 과일을 하나의 문자열로 연결한다. </li>
<li>distinct(): 중복된 값을 제거하고 출력 </li>
<li>limit(long maxSize): 처음부터 maxSize개의 값을 출력한다. </li>
<li>skip(long n): 처음 n개의 값을 제외한 나머지값 출력 </li>
</ul>
<h4 id="stream-최종연산에서-자주-쓰이는-메서드">Stream 최종연산에서 자주 쓰이는 메서드</h4>
<ul>
<li>forEach(Consumer<T> action): 각 요소에 대해 주어진 action을 실행한다</li>
<li>count(): 스트림의 요소 수를 반환</li>
<li>collect(Collector&lt;T, A, R&gt; collector): 스트림의 요소를 수집하여 Collection, List, Set, Map 등의 컬렉션에 저장하는 최종 연산</li>
<li>toArray(): 스트림의 요소를 배열로 반환하는 최종 연산</li>
<li>reduce(T identity, BinaryOperator<T> accumulator): 스트림의 요소를 identity로 초기화한 후, accumulator 연산을 반복하여 값을 줄여나가는 최종 연산 예시코드에서는 더하기연산으로 문자열을 이어쓰는 형태로 활용하였다</li>
<li>min(Comparator<T> comparator): 스트림에서 최소값을 반환</li>
<li>max(Comparator<T> comparator): 스트림에서 최대값을 반환</li>
<li>anyMatch(Predicate<T> predicate): 스트림에서 predicate 조건을 만족하는 요소가 하나라도 있는지 확인</li>
<li>allMatch(Predicate<T> predicate): 스트림의 모든 요소가 predicate 조건을 만족하는지 확인</li>
</ul>
<h2 id="3-백준-2750-수-정렬하기">3. <a href="https://www.acmicpc.net/problem/2750">백준 2750 수 정렬하기</a></h2>
<h2 id="4-백준-1181-단어-정렬">4. <a href="https://www.acmicpc.net/problem/1181">백준 1181 단어 정렬</a></h2>
<blockquote>
<p><strong>아이디어</strong></p>
</blockquote>
<ul>
<li>TreeSet으로 중복 제거 + 자동 정렬 =&gt; sb.append()로 출력 </li>
</ul>
<pre><code class="language-java">TreeSet&lt;String&gt; set = new TreeSet&lt;&gt;((a, b) -&gt; {
    if(a.length() != b.length()){
        return a.length() - b.length();
    }
    return a.compareTo(b); 
})

for (String word: set){
    sb.append(word).append(&quot;\n&quot;); 
}</code></pre>
<pre><code class="language-java">package boj_silver.p1181_단어정렬;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

public class Review2_treeset {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb= new StringBuilder();
        int n = Integer.parseInt(br.readLine());


        //treeset: 중복 제거 + 자동 정렬
        TreeSet&lt;String&gt; set = new TreeSet&lt;&gt;((a,b) -&gt; {
            if(a.length() != b.length()){
                return a.length() - b.length();
            }
            return a.compareTo(b);
        });
//        for (int i = 0; i &lt; strArr.length; i++) {
//            sb.append(strArr[i] + &quot;\n&quot;);
//        }
        for (int i = 0; i&lt;n; i++){
            set.add(br.readLine());
        }
        for (String word: set){
            sb.append(word).append(&quot;\n&quot;);
        }

        System.out.println(sb);
        br.close();
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[정렬 코테 총 정리 ]]></title>
            <link>https://velog.io/@haing3_3/%EC%A0%95%EB%A0%AC-%EC%BD%94%ED%85%8C-%EC%B4%9D-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@haing3_3/%EC%A0%95%EB%A0%AC-%EC%BD%94%ED%85%8C-%EC%B4%9D-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 19 Nov 2025 02:40:24 GMT</pubDate>
            <description><![CDATA[<p>아래 내용은 코테용  정렬 정리본입니다. </p>
<h1 id="정렬-코테-총-정리">정렬 코테 총 정리</h1>
<h2 id="1-배열-array-정렬">1. 배열 Array 정렬</h2>
<h3 id="1-1-기본-타입-배열-오름차순">1-1 기본 타입 배열 오름차순</h3>
<pre><code class="language-java">int[] arr1 = {5,2,8,1,9}; 
//오름차순 
Arrays.sort(arr1); // 1,2,5,8,9
//범위 지정 정렬 (0~2번 인덱스만 정렬 
Arrays.sort(arr1, 0, 3); // 2,5,8,1,9</code></pre>
<h3 id="1-2-wrapper-클래스-배열-내림차순">1-2 Wrapper 클래스 배열 내림차순</h3>
<pre><code class="language-java">Integer[] arr = {5,2,8,1,9}; 
Arrays.sort(arr, Collections.reverseOrder()); </code></pre>
<h3 id="1-3-string-배열-사전순">1-3 String 배열 (사전순)</h3>
<pre><code class="language-java">String[] strArr = {&quot;banana&quot;, &quot;apple&quot;, &quot;cherry&quot;};
Arrays.sort(strArr); //apple, banana, cherry
</code></pre>
<h3 id="1-4-람다식-정렬">1-4 람다식 정렬</h3>
<pre><code class="language-java">Integer[] arr = {5, 2, 8, 1, 9};
Arrays.sort(arr, (a, b)-&gt; a-b); //오름차순 
Arrays.sort(arr, (a,b)-&gt; b-a); //내림차순 </code></pre>
<h3 id="1-5-복잡한-조건-정렬-홀수-우선-같으면-오름차순">1-5 복잡한 조건 정렬 (홀수 우선, 같으면 오름차순)</h3>
<pre><code class="language-java">Integer[] arr = {5, 2, 8, 1, 9};
Arrays.sort(arr, (o1, o2)-&gt; {
    if(o1 %2 !=0 &amp;&amp; o2%2 ==0) return -1; //o1이 홀수 일때 우선 
    if (o1 % 2 == 0 &amp;&amp; o2 % 2 != 0) return 1; 
    return o1-o2; //오름 차순 
}); </code></pre>
<hr>
<h2 id="2-list-정렬">2. List 정렬</h2>
<h3 id="2-1-collectionssort-사용">2-1 Collections.sort() 사용</h3>
<pre><code class="language-java">List&lt;Integer&gt; list = new ArrayList&lt;&gt;(Arrays.asList(5,2,8,1,9)); 
//오름차순 
Collections.sort(list); 
//내림차순 
Collections.sort(list, Collections.reverseOrder()); </code></pre>
<h3 id="2-2-listsort-사용-java-8">2-2 list.sort() 사용 (java 8+)</h3>
<pre><code class="language-java">list.sort(Comparator.naturalOrder()); 

list.sort(Comparator.reverseOrder()); </code></pre>
<h3 id="2-3-람다식">2-3 람다식</h3>
<pre><code class="language-java">//오름차순 
list.sort((a,b)-&gt; a-b);  </code></pre>
<hr>
<h2 id="3-객체-정렬---comparable-인터페이스">3. 객체 정렬 - Comparable 인터페이스</h2>
<h3 id="person-class에서-compareto-메서드-오버라이드">Person Class에서 compareTo 메서드 오버라이드</h3>
<pre><code class="language-java">Class Person implements Comparable&lt;Person&gt;{
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override 
    public int compareTo(Person other){
        return this.age - other.age; //나이 기준 오름 차순 
    }

    @Override 
    publis String toString(){
        return name + &quot;(&quot; + age + &quot;)&quot;; 
    }

}</code></pre>
<h3 id="main-메서드">main 메서드</h3>
<pre><code class="language-java">List&lt;Person&gt; people = new ArrayList&lt;&gt;(); 
people.add(new Person(&quot;김철수&quot;, 25));
people.add(new Person(&quot;이영희&quot;, 20));
people.add(new Person(&quot;박민수&quot;, 30));

Collections.sort(people); //compareTo()기준 정렬 
//역순 정렬 
Collections.sort(people, Collections.reverseOrder()); 

</code></pre>
<hr>
<h2 id="4-객체-정렬---comparator-인터페이스">4. 객체 정렬 - Comparator 인터페이스</h2>
<h3 id="student-class">Student class</h3>
<pre><code class="language-java">class Student {
    String name;
    int score;
    int age;

    public Student(String name, int score, int age) {
        this.name = name;
        this.score = score;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + &quot;(&quot; + score + &quot;점, &quot; + age + &quot;세)&quot;;
    }
}</code></pre>
<h3 id="main-메서드-1">main 메서드</h3>
<pre><code class="language-java">List&lt;Student&gt; students = new ArrayList&lt;&gt;();
        students.add(new Student(&quot;김철수&quot;, 85, 20));
        students.add(new Student(&quot;이영희&quot;, 90, 22));
        students.add(new Student(&quot;박민수&quot;, 85, 21));
//1. 점수 기준 내림차순
students.sort((s1, s2)-&gt; s2.score - s1.score); 

//2. 점수가 같으면 나이 오름차순    
students.sort((s1,s2) -&gt; {
    if(s1.score!=s2.score){
        return s2.score- s1.score; //점수 내림차순
    }
    return s1.age - s2.age; //나이 오름차순 
} 

//3. Comparator 메서드 체이닝 !! 
students.sort(Comparator.comparingInt((Student s) -&gt; s.score).reversed()
                                                    .thenComparingInt(s-&gt; s.age); 

// 4. 이름 기준 사전 순 
students.sort(Comparator.comparing(s-&gt; s.name)); 
</code></pre>
<hr>
<h2 id="5-2차원-배열-정렬">5. 2차원 배열 정렬</h2>
<pre><code class="language-java">int[][] arr = {{3, 5}, {1, 2}, {5, 3}, {1, 7}};

//1. 첫번째 원소 기준 오름차순 
Arrays.sort(arr, (a, b)-&gt; a[0]- b[0]); 

//2. 첫번째 같으면 두번째 기준 
Arrays.sort(arr, (a, b)-&gt; {
    if(a[0] !=b[0]) return a[0] - b[0]; //첫번째 오름차순 
    return a[1]- b[1]; //두번째 오름차순 
}); 

//3. 두번째 원소 기준 내림차순 
Arrays.sort(arr, (a, b)-&gt; b[1]- a[1]); </code></pre>
<hr>
<h2 id="6-특수-자료-구조-정렬">6. 특수 자료 구조 정렬</h2>
<h3 id="priority-queue-정렬">Priority Queue 정렬</h3>
<pre><code class="language-java">// 1. 최소 힙
PrioriyQueue&lt;Integer&gt; minHeap = new PrioriyQueue&lt;&gt;(); 
minHeap.addAll(Arrays.asList(5,2,8,1,9)); 
//출력- 최소 힙 
while(!minHeap.isEmpty()){
    System.out.print(minHeap.poll() + &quot; &quot; ); 
}

// 2. 최대힙 
PrioriyQueue&lt;Integer&gt; maxHeap = new PrioriyQueue&lt;&gt;(Collections.reverseOrder()); 
maxHeap.addAll(Arrays.asList(5,2,8,1,9)); 
while(!minHeap.isEmpty()){
    System.out.print(minHeap.poll() + &quot; &quot; ); 
}</code></pre>
<h3 id="treeset--자동-정렬--중복-제거">TreeSet- 자동 정렬 + 중복 제거</h3>
<pre><code class="language-java">TreeSet&lt;Integer&gt; treeSet = new TreeSet&lt;&gt;(Arrays.asList(5, 2, 8, 1, 9, 2));
System.out.println(&quot;TreeSet (중복 제거): &quot; + treeSet);</code></pre>
<h3 id="treemap--key자동-정렬">TreeMap- key자동 정렬</h3>
<pre><code class="language-java">TreeMap&lt;String, Integer&gt; treeMap = new TreeMap&lt;&gt;(); 
treeMap.put(&quot;banana&quot;, 3);
treeMap.put(&quot;apple&quot;, 1);
treeMap.put(&quot;cherry&quot;, 2);
System.out.println(&quot;TreeMap: &quot; + treeMap);</code></pre>
<hr>
<h2 id="7-문자열-정렬-특수-케이스">7. 문자열 정렬 특수 케이스</h2>
<pre><code class="language-java">String[] words = {&quot;apple&quot;, &quot;pie&quot;, &quot;banana&quot;, &quot;cat&quot;};

//1. 길이 기준 정렬 
Arrays.sort(words, (a,b) -&gt; a.length() - b.length()); 

//2. 길이 같으면 사전순 
Arrays.sort(words, (a, b)-&gt; {
    if(a.length() != b.length()) return a.length()- b.length(); 
    return a.compareTo(b); 
}); 

//3. 대소문자 구분 없이 정렬 
String[] words3 = {&quot;Apple&quot;, &quot;banana&quot;, &quot;Cherry&quot;};
Arrays.sort(words3, String.CASE_INSENSITIVE_ORDER); 
</code></pre>
<hr>
<h2 id="8-코테용-자주-쓰는-정렬-패턴">8. 코테용 자주 쓰는 정렬 패턴</h2>
<p><code>Integer[] arr1 = {-5, 2, -8, 1, 9};</code></p>
<h3 id="절댓값-기준-정렬">절댓값 기준 정렬</h3>
<p><code>Arrays.sort(arr1, (a,b)-&gt; Math.abs(a)- Math.abs(b));</code>  </p>
<h3 id="특정-값과의-거리-기준-정렬">특정 값과의 거리 기준 정렬</h3>
<pre><code class="language-java">int target = 5; 
Integer[] arr2 = {1, 3, 7, 9, 2};
Arrays.sort(arr2, (a, b)-&gt; Math.abs(a-target)- Math.abs(b-target)); </code></pre>
<h3 id="빈도수-기준-정렬">빈도수 기준 정렬</h3>
<pre><code class="language-java">Integer[] arr3 = {1, 1, 2, 2, 2, 3};
Map&lt;Integer, Integer&gt; freqMap =  new HashMap&lt;&gt;(); 
for (int num: arr3){
    freqMap.put(num, freqMap.getOrDefault(num, 0) +1); 
}
//빈도수 내림차순 
Arrays.sort(arr3, (a,b)-&gt; freqMap.get(b) - freqMap.get(a)); 
</code></pre>
<hr>
<h2 id="9-정렬-주의사항-및-시간-복잡도">9. 정렬 주의사항 및 시간 복잡도</h2>
<h3 id="시간-복잡도">시간 복잡도</h3>
<ul>
<li><strong>Arrays.sort()</strong></li>
</ul>
<p><code>- 기본 타입(int[]): O(n log n) - Dual-Pivot Quicksort”</code></p>
<p><code>- 객체 타입(Integer[]): O(n log n) - TimSort”</code></p>
<h3 id="주의사항">주의사항</h3>
<ul>
<li>int[] 배열은 Comparator 사용 불가 → Integer[] 사용</li>
<li>람다식 (a, b)→ a-b 오버플로우 주의<ul>
<li>안전한것은 Integer.compare(a,b)</li>
</ul>
</li>
<li>내림차순 Collections.reverseOrder()또는 (a,b)→ b-a</li>
</ul>
<h3 id="comparable-vs-comparator">Comparable vs Comparator</h3>
<ul>
<li>Comparable: 클래스 내부에  compareTo() 구현 (기본 정렬)</li>
<li>Comparator: 외부에서 compare() 구현 (사용자 정의 정렬)</li>
</ul>
<h3 id="stable-sort">stable sort</h3>
<ul>
<li>Arrays.sort(객체 배열), Collections.sort() : 안정 정렬 o</li>
<li>Arrays.sort(기본 타입) : 안정 정렬 x</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring MVC 1편] Sec2.웹 애플리케이션의 이해 ]]></title>
            <link>https://velog.io/@haing3_3/Spring-MVC-1%ED%8E%B8-Sec2.%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@haing3_3/Spring-MVC-1%ED%8E%B8-Sec2.%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Tue, 18 Nov 2025 09:53:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h1 id="웹서버--was-서블릿-멀티-쓰레드-csrssr-자바-벡엔드-역사-정리">웹서버 &amp; WAS, 서블릿, 멀티 쓰레드, CSR/SSR, 자바 벡엔드 역사 정리</h1>
</blockquote>
<h1 id="1-웹-서버web-server와-웹-애플리케이션-서버was">1. 웹 서버(Web Server)와 웹 애플리케이션 서버(WAS)</h1>
<h2 id="1-1-모든-것이-http-기반">1-1. 모든 것이 HTTP 기반</h2>
<p>브라우저 ↔ 서버 간의 모든 통신은 <strong>HTTP 프로토콜</strong>을 기반으로 한다.
정적/동적 리소스 제공 방식은 서버 종류에 따라 다르다.</p>
<hr>
<h2 id="1-2-웹-서버web-server">1-2. 웹 서버(Web Server)</h2>
<p>정적 리소스를 제공하는 서버.
(HTML, CSS, JS, 이미지, 영상 파일 등)</p>
<ul>
<li>요청이 오면 파일 그대로 전달</li>
<li>실행 로직 없음 → 가볍고 빠르고 잘 안 죽음</li>
<li>예: <strong>NGINX</strong>, <strong>Apache</strong></li>
</ul>
<hr>
<h2 id="1-3-웹-애플리케이션-서버was">1-3. 웹 애플리케이션 서버(WAS)</h2>
<p>정적 리소스 제공 + <strong>애플리케이션 로직 실행</strong>이 가능한 서버.</p>
<ul>
<li>동적으로 HTML 생성 (JSP, Thymeleaf)</li>
<li>REST API(JSON) 응답</li>
<li>서블릿, JSP, 스프링 MVC 처리</li>
<li>예: <strong>Tomcat</strong></li>
</ul>
<hr>
<h2 id="1-4-웹-서버-vs-was-핵심-정리">1-4. 웹 서버 vs WAS (핵심 정리)</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>Web Server</th>
<th>WAS</th>
</tr>
</thead>
<tbody><tr>
<td>역할</td>
<td>정적 리소스 제공</td>
<td>애플리케이션 로직 실행</td>
</tr>
<tr>
<td>부하</td>
<td>가벼움</td>
<td>상대적으로 무거움</td>
</tr>
<tr>
<td>예시</td>
<td>NGINX, Apache</td>
<td>Tomcat</td>
</tr>
</tbody></table>
<p><strong>자바 기반에서 서블릿 컨테이너 기능을 제공하면 WAS로 분류됨.</strong></p>
<hr>
<h2 id="1-5-웹-시스템-구성-방식">1-5. 웹 시스템 구성 방식</h2>
<h3 id="✔-was--db">✔ WAS + DB</h3>
<ul>
<li>단독 구성 가능</li>
<li>하지만 <strong>정적 리소스까지 WAS가 떠맡으면 과부하 발생</strong></li>
<li>WAS 장애 시 에러 페이지도 제공할 수 없음</li>
</ul>
<h3 id="✔-web-server--was--db-권장">✔ Web Server + WAS + DB (권장)</h3>
<ul>
<li><p>정적 리소스: Web Server</p>
</li>
<li><p>동적 로직: WAS</p>
</li>
<li><p>장점</p>
<ul>
<li>효율적인 리소스 분리</li>
<li>Web Server는 안정성이 높음</li>
<li>장애 시 Web Server가 에러 페이지 응답 가능</li>
</ul>
</li>
<li><p>REST API만 사용하는 시스템은 Web Server 생략해도 됨</p>
</li>
</ul>
<hr>
<h1 id="2-서블릿servlet">2. 서블릿(Servlet)</h1>
<h2 id="2-1-html-form-데이터-전송">2-1. HTML Form 데이터 전송</h2>
<ul>
<li>브라우저 → 서버로 데이터 전달 시 <strong>POST 요청</strong> 사용</li>
<li>이를 처리하는 것이 서블릿</li>
</ul>
<p>(예: <code>/hello</code> 주소 호출 → HelloServlet 실행)</p>
<hr>
<h2 id="2-2-서블릿의-역할">2-2. 서블릿의 역할</h2>
<ul>
<li><p><strong>HttpServletRequest</strong>
→ 요청 데이터 조회 (<code>request.getParameter()</code> 등)</p>
</li>
<li><p><strong>HttpServletResponse</strong>
→ 응답 메시지 생성 (HTML, JSON 등)</p>
</li>
</ul>
<p>HTTP 스펙을 개발자가 직접 다룰 수 있게 설계된 API라고 보면 됨.</p>
<hr>
<h2 id="2-3-서블릿-요청응답-흐름">2-3. 서블릿 요청/응답 흐름</h2>
<ol>
<li>클라이언트가 HTTP 요청</li>
<li>WAS가 Request/Response 객체 생성</li>
<li>해당 URL 매핑된 서블릿 호출</li>
<li>개발자가 request/response에 데이터를 읽고 쓰기</li>
<li>WAS가 Response 내용을 기반으로 <strong>최종 HTTP 응답 생성</strong></li>
</ol>
<p>→ 개발자는 HTTP 처리 복잡성을 크게 줄일 수 있음.</p>
<hr>
<h2 id="2-4-서블릿-컨테이너was의-핵심-기능">2-4. 서블릿 컨테이너(=WAS의 핵심 기능)</h2>
<p>WAS 내부에서 서블릿을 관리하는 기능을 말함.</p>
<ul>
<li>서블릿 객체 <strong>생성·초기화·종료</strong> 관리</li>
<li><strong>싱글톤</strong>으로 관리 (한 번만 만들고 재사용)</li>
<li>멀티쓰레드 환경 제공 → 동시 요청 처리</li>
<li>JSP는 서블릿으로 변환되어 실행됨</li>
</ul>
<p><strong>주의:</strong>
싱글톤 객체이므로, 공유 변수 사용 시 동시성 문제에 유의해야 한다.</p>
<hr>
<h1 id="3-멀티쓰레드--쓰레드-풀thread-pool">3. 멀티쓰레드 &amp; 쓰레드 풀(Thread Pool)</h1>
<h2 id="3-1-쓰레드thread">3-1. 쓰레드(Thread)</h2>
<ul>
<li>코드 흐름을 수행하는 실행 단위</li>
<li>동시 처리가 필요하면 여러 쓰레드가 사용됨</li>
</ul>
<hr>
<h2 id="3-2-요청마다-쓰레드-생성-방식의-문제">3-2. 요청마다 쓰레드 생성 방식의 문제</h2>
<ul>
<li>쓰레드 생성 비용이 매우 크다</li>
<li>동시 요청 폭주 → 쓰레드 무제한 생성 → CPU/메모리 초과 → 서버 다운</li>
</ul>
<hr>
<h2 id="3-3-was의-해결책-쓰레드-풀thread-pool">3-3. WAS의 해결책: 쓰레드 풀(Thread Pool)</h2>
<p>WAS는 내부적으로 <strong>쓰레드 풀</strong>을 운영한다.</p>
<h3 id="특징">특징</h3>
<ul>
<li><p>미리 쓰레드를 만들어 두고 재사용</p>
</li>
<li><p>요청 → 쓰레드 대여</p>
</li>
<li><p>처리 완료 → 쓰레드 반납</p>
</li>
<li><p>최대 쓰레드 개수 존재</p>
<ul>
<li>Tomcat 기본 200개</li>
</ul>
</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li>많은 요청도 안정적으로 처리 가능</li>
<li>개발자는 멀티쓰레드 코드를 직접 구현할 필요가 없음
→ 싱글 쓰레드 코딩하듯 개발해도 됨</li>
</ul>
<hr>
<h2 id="3-4-실무-팁">3-4. 실무 팁</h2>
<ul>
<li>쓰레드 수가 너무 적으면 → CPU는 남는데 처리량 부족</li>
<li>너무 많으면 → 서버가 오히려 장애</li>
<li>적정 숫자는 서비스마다 다르므로 <strong>성능 테스트 필수</strong></li>
</ul>
<h3 id="테스트-도구">테스트 도구</h3>
<ul>
<li>Apache ab</li>
<li>JMeter</li>
<li>nGrinder</li>
</ul>
<hr>
<h1 id="4-html-http-api-csr-ssr-정리">4. HTML, HTTP API, CSR, SSR 정리</h1>
<h2 id="4-1-정적-리소스">4-1. 정적 리소스</h2>
<ul>
<li>변경되지 않는 HTML, CSS, JS 파일</li>
</ul>
<hr>
<h2 id="4-2-html-페이지">4-2. HTML 페이지</h2>
<ul>
<li>JSP/Thymeleaf처럼 <strong>서버가 HTML을 만들어 전달</strong>하는 방식</li>
</ul>
<hr>
<h2 id="4-3-http-api">4-3. HTTP API</h2>
<ul>
<li>HTML이 아닌 <strong>데이터(JSON)</strong> 전달</li>
<li>앱, 웹, 서버 간 통신에 널리 사용</li>
</ul>
<hr>
<h2 id="4-4-ssr-server-side-rendering">4-4. SSR (Server-Side Rendering)</h2>
<p><strong>서버가 HTML 완성본을 만들어 클라이언트에 전송</strong></p>
<ul>
<li>정적인 화면에 적합</li>
<li>JSP, 타임리프</li>
<li>백엔드 중심 구조</li>
</ul>
<hr>
<h2 id="4-5-csr-client-side-rendering">4-5. CSR (Client-Side Rendering)</h2>
<p><strong>HTML을 클라이언트(브라우저)에서 JS로 동적으로 생성</strong></p>
<ul>
<li>React, Vue.js</li>
<li>Gmail, Google Maps처럼 인터랙션이 많은 UI에 적합</li>
</ul>
<p>SSR + CSR 혼합 방식도 가능 (Next.js 등)</p>
<hr>
<h1 id="5-자바-백엔드-기술-역사">5. 자바 백엔드 기술 역사</h1>
<h2 id="5-1-과거">5-1. 과거</h2>
<h3 id="servlet">Servlet</h3>
<ul>
<li>동적 화면 생성 어려움 (HTML 출력 코드를 직접 작성해야 함)</li>
</ul>
<h3 id="jsp">JSP</h3>
<ul>
<li>HTML 렌더링은 편하지만</li>
<li>로직 + 렌더링이 뒤섞여 유지보수 어려움</li>
</ul>
<p>→ MVC 패턴 도입
→ 화면과 비즈니스 로직 분리</p>
<hr>
<h2 id="5-2-현재-spring-mvc--spring-boot">5-2. 현재: Spring MVC &amp; Spring Boot</h2>
<h3 id="spring-mvc">Spring MVC</h3>
<ul>
<li>애노테이션 기반 (<code>@Controller</code>, <code>@RequestMapping</code>)</li>
<li>MVC 아키텍처를 표준으로 자리 잡음</li>
</ul>
<h3 id="spring-boot">Spring Boot</h3>
<ul>
<li>내장 WAS 제공 → Jar 파일만으로 실행 가능</li>
<li>복잡한 설정 자동화</li>
<li>배포 간소화</li>
</ul>
<hr>
<h2 id="5-3-최신-기술-spring-webflux">5-3. 최신 기술: Spring WebFlux</h2>
<h3 id="webflux-reactive">WebFlux (Reactive)</h3>
<ul>
<li>비동기 논블로킹 처리</li>
<li>적은 쓰레드로 높은 성능</li>
<li>함수형 프로그래밍 스타일</li>
</ul>
<p>→ 고성능 &amp; 실시간 스트리밍 시스템에서 유용
→ 하지만 <strong>실무 채택률은 아직 낮음</strong></p>
<hr>
<h2 id="5-4-뷰-템플릿의-역사">5-4. 뷰 템플릿의 역사</h2>
<table>
<thead>
<tr>
<th>기술</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>JSP</td>
<td>느리고 기능 제한</td>
</tr>
<tr>
<td>Freemarker / Velocity</td>
<td>빠르고 유연</td>
</tr>
<tr>
<td>Thymeleaf</td>
<td>HTML 구조 그대로 유지(내추럴 템플릿) + 스프링 통합</td>
</tr>
</tbody></table>
<hr>
<h1 id="🔎-전체-흐름-요약">🔎 전체 흐름 요약</h1>
<ul>
<li>Web Server는 정적 파일 제공, WAS는 로직 처리</li>
<li>서블릿은 HTTP 요청을 처리하는 핵심 기반 기술</li>
<li>WAS는 멀티쓰레드 + 쓰레드풀로 동시 요청 처리</li>
<li>Rendering 방식은 SSR, CSR로 나뉨</li>
<li>자바 백엔드는 Servlet → JSP → MVC → Spring MVC → Spring Boot → WebFlux로 발전 중</li>
</ul>
<hr>
<blockquote>
<h2 id="출처">출처</h2>
<p><a href="https://www.inflearn.com/courses/lecture?courseId=326674&amp;type=LECTURE&amp;unitId=71164&amp;tab=curriculum&amp;subtitleLanguage=ko">김영한의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 10일차] 1118]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-10%EC%9D%BC%EC%B0%A8-1118</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-10%EC%9D%BC%EC%B0%A8-1118</guid>
            <pubDate>Tue, 18 Nov 2025 09:30:42 GMT</pubDate>
            <description><![CDATA[<h2 id="1-백준-9012-괄호">1. <a href="https://www.acmicpc.net/problem/9012">백준 9012 괄호</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>입력받는문제: scan.next()로 String 한줄을 입력받고, 문자열 길이만큼 순회하면서 char ch = str.charAt(j)를 입력받는다. </li>
<li>flage로 한번만 출력되게 한다.( &#39;)&#39;가 들어왔는데 비어있으면, no표시만 flag = false로 하고, 마지막 출력때 flag &amp;&amp; stack.isEmpty()조건으로 &quot;YES&quot;를 출력하도록 한다. </li>
</ul>
<pre><code class="language-java">package boj_silver.p9012_괄호;
import java.util.*;

public class Review1 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int T = scan.nextInt();


        for (int i = 0; i &lt; T; i++) {
            Stack&lt;Character&gt; stack = new Stack&lt;&gt;();
            //Character ch = scan.next().charAt(0);

            //입력 처리
            String str = scan.next(); //문자열 전체를 받음
            boolean isValid = true;

            //문자 하나씩 순회하기 !!
            for (int j = 0; j&lt;str.length(); j++){
                char ch = str.charAt(j);  //하나씩 입력받기
                if (ch ==&#39;(&#39;){
                    stack.push(ch);
                }else if(ch ==&#39;)&#39;){
                    if(stack.isEmpty()){
//                        System.out.println(&quot;NO&quot;);
                        //no표시만
                        isValid = false;

//                        return; //main 종료 -&gt; 전체 종료
                        break; //for문 탈출
                        //continue는 다음 반복으로 건너뛰기
                    }else{
                        stack.pop();
                    }
                }
            }

            //stack에 남아있다면
            if (isValid &amp;&amp; stack.isEmpty()) {
                System.out.println(&quot;YES&quot;);
            } else {
                System.out.println(&quot;NO&quot;); //또 출력되는 문제가 있네-&gt; flag 사용
            }

        }//for
    }//main

}//class</code></pre>
<h2 id="2-백준-21736-헌내기는-친구가-필요해">2. <a href="https://www.acmicpc.net/problem/21736">백준 21736 헌내기는 친구가 필요해 </a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>I를 만나는 좌표를 저장함 ! -&gt; bfs를 I부터 시작함 </li>
<li>범위 조건&amp; 탐색 조건을 map[nx][ny] !=&#39;X&#39;로 하고, &#39;P&#39;라면 cnt++하는 방식으로 cnt를 셈. </li>
</ul>
<pre><code class="language-java">package boj_silver.p21736_헌내기는친구가;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;

//미로 탐색이다.
//nxm의 크기으 ㅣ캠퍼스가 있고,
// O : 빈공간 / X: 벽 / I: 도연이 / P: 사람
//범위 조건에 O, X를 쓰고, P를 만날때 ++ 해서 출력

//도연이가 만날수 있는 사람의 수를 출력 -&gt; 아무도 못만난 경우 TT 출력
public class Main {
    static int n,m, cnt ;
    static int[] dx = {-1,1,0,0};
    static int[] dy = {0,0,-1,1};
    static char[][] map;
    static boolean[][] visited;


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

        int sx =0, sy = 0;
        //map 입력 받기
        for (int i = 0; i &lt; n; i++) {
            String line = br.readLine();
            for (int j = 0; j &lt; m; j++) {
                map[i][j] = line.charAt(j);

                //I를 만나면 bfs 시작
                if (map[i][j] == &#39;I&#39;){
                    sx = i;
                    sy = j;
//                    bfs(i, j);//바로 시작하면 전부다 입력이 안됨,.
                }
            }
        }
        bfs(sx, sy);

        //System.out.println(Arrays.deepToString(map));
        if(cnt&gt;=1){
            System.out.println(cnt);
        }else{
            System.out.println(&quot;TT&quot;);
        }
    }
    static void bfs(int x, int y){
        Queue&lt;int[]&gt; q = new ArrayDeque&lt;&gt;();
        q.offer(new int[]{x,y});
        visited[x][y] = true;
        while(!q.isEmpty()){
            int[] cur = q.poll();
            int cx = cur[0];
            int cy = cur[1];
            for (int i = 0; i&lt;4; i++){
                int nx = cx+dx[i];
                int ny = cy+dy[i];

                if(nx&gt;=0 &amp;&amp; ny&gt;=0 &amp;&amp; nx&lt;n &amp;&amp; ny&lt;m){//가장자리 범위
                    if(!visited[nx][ny] &amp;&amp; map[nx][ny]!=&#39;X&#39;){
                        visited[nx][ny] = true;
                        q.offer(new int[]{nx,ny});
                        if (map[nx][ny] == &#39;P&#39;){
                            cnt++;
                        }
                    }
//                    if(!visited[nx][ny] &amp;&amp; map[nx][ny] == &#39;P&#39;){
//                        //P를 만났을때 처리 !!!! -&gt; 큐에 추가해야함
//                        q.offer(new int[]{nx,ny});
//                        visited[nx][ny] = true;
//                        cnt++;
//                    }
//                    if(!visited[nx][ny] &amp;&amp; map[nx][ny] == &#39;O&#39;){
//                        q.offer(new int[]{nx,ny});
//                        visited[nx][ny] = true;
//
//                    }
                }
            }
        }

    }
}
</code></pre>
<h2 id="3-백준-7576-토마토">3. <a href="https://www.acmicpc.net/problem/7576">백준 7576 토마토</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>익은 토마토(1)가 여러개 있을 수 있다 -&gt; list로 좌표 입력 받고 , bfs에 한꺼번에 표시하기 </li>
<li>벽: -1, 안익은 토마토: 0, 익은 토마토: 1 -&gt; visited 배열 필요 없다. </li>
<li>출력은 만약 map에 0이 남아있으면, flag = flase, 아니면, max 변수에, 가장 큰 값을 넣는다. 
!flag이면 -1출력 / max -1 출력 </li>
<li>bfs) queue에 list에 있는 int[] 배열을 동시 추가한다. 
큐가 빌때까지 4방향 탐색을 한다. 범위: 안익은 토마토만 &amp; 벽이 있으면 안됨. <code>map[nx][ny] ==0 &amp;&amp; map[nx][ny]!= -1</code></li>
</ul>
<pre><code class="language-java">package boj_gold.p7576_토마토;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Review1 {
    static int n,m;
    static int[][] map;
//    static boolean [][] visited;
    static int[] dx ={-1,1,0,0};
    static int[] dy ={0,0,-1,1};
    static List&lt;int[]&gt; list;

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

        map = new int[n][m];
//        visited = new boolean[n][m];

        //list에 1인 좌표를 큐에 넣기
        list = new ArrayList&lt;&gt;();

        //map 받기
        for (int i = 0; i &lt; n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j &lt; m; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
                if(map[i][j] == 1){
                    list.add(new int[]{i,j});
                }
            }
        }
        bfs(list);
//        System.out.println(Arrays.deepToString(map));
        int max= 0;
        boolean flag = true;

        //만약 0이 남아있으면 ?
        for (int i =0; i&lt;n; i++) {
            for (int j = 0; j &lt; m; j++) {
                if (map[i][j] == 0) {
                    flag = false;
                }
                max = Math.max(map[i][j], max);
            }
        }
        if(!flag){
            System.out.println(-1);
        }else{
            System.out.println(max-1);
        }


    }
    static void bfs(List&lt;int[]&gt; list){
        Queue&lt;int[]&gt; q= new ArrayDeque&lt;&gt;();
        //동시 추가
        for (int[] pos: list){
            q.offer(pos);
        }

        while(!q.isEmpty()){
            int[] cur = q.poll();
            int cx = cur[0];
            int cy = cur[1];

            //4방향 탐색
            for(int i =0; i&lt; 4; i++){
                int nx = cx+dx[i];
                int ny = cy+dy[i];
                if (nx &gt;=0 &amp;&amp; ny&gt;=0 &amp;&amp; nx&lt;n &amp;&amp; ny&lt;m){ //범위 체크
                    //안익은 토마토만
                    if(map[nx][ny] ==0 &amp;&amp; map[nx][ny]!= -1){
                        map[nx][ny] = map[cx][cy] + 1;
                        q.offer(new int[]{nx,ny});
                    }

                }
            }

        }
    }
}
</code></pre>
<h2 id="4-백준-1874-스택수열">4. <a href="https://www.acmicpc.net/problem/1874">백준 1874 스택수열</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>Stack자료구조 쓰고, flag로 한꺼번에 출력 (StringBuilder) </li>
<li>입력받는 동시에 로직 작성 ! (target은 들어오는 숫자) </li>
<li>cur = 1부터 시작해서, cur&lt;=target까지 push(cur) cur++ </li>
<li>target이 stack.peek()과 같고, stack이 비지 않았다면, pop(); -&gt; else flage = false break; </li>
</ul>
<pre><code class="language-java">package boj_silver.p1847_스택수열;

import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;

//push 하는 순서는 반드시 오름차순 -&gt;
public class Review1 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        StringBuilder sb = new StringBuilder();

        //배열 입력받기
//        int[] numbers = new int[n]; // -&gt; 입력받는 동시에 비교하기
//        for (int i = 0; i&lt;n; i++){
//            numbers[i] = scan.nextInt();
//        }

        Stack&lt;Integer&gt; stack = new Stack&lt;&gt;();
        int cur = 1;
        boolean possible = true;
        //while(cur&lt;=target)

        for (int i = 0; i &lt; n; i++) {
            int target= scan.nextInt();
            while(cur&lt;=target){
                stack.push(cur);
                sb.append(&quot;+\n&quot;);
                cur++;
            }
            if(!stack.isEmpty() &amp;&amp; target ==stack.peek()){
                stack.pop();
                sb.append(&quot;-\n&quot;);
            }else{
                possible = false;
                break; //for문 탈출
            }
        }
        if(possible){
            System.out.println(sb);
        }else{
            System.out.println(&quot;NO&quot;);
        }


    }
}
</code></pre>
<h2 id="5-백준-10773-제로">5. <a href="https://www.acmicpc.net/problem/10773">백준 10773 제로</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>stack에 있는 것 다 더하기 로직 (while(!stack.isEmpty()){int num = stack.pop(); sum+= num; }</li>
</ul>
<pre><code class="language-java">package boj_silver.p10773_제로;

import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        Stack&lt;Integer&gt; stack = new Stack&lt;&gt;();

        for (int i = 0; i &lt; n; i++) {
            int num = scan.nextInt();
            if(num !=0){
                stack.push(num);
            }else if(num ==0){
                stack.pop();
            }
        }
        //stack에 있는 것 다 더하기
        int sum = 0;
        while(!stack.isEmpty()){
            int num = stack.pop();
            sum += num;
        }

        System.out.println(sum);
    }
}

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 9일차] 1117]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-9%EC%9D%BC%EC%B0%A8-1117</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-9%EC%9D%BC%EC%B0%A8-1117</guid>
            <pubDate>Mon, 17 Nov 2025 05:04:54 GMT</pubDate>
            <description><![CDATA[<p>8일차를 보니 벌써 2주나 쉬었다. 그동안 몸살이나, 스터디 활동이 원활하지 않아, 나태해졌던 것 같다! 
다시 한번 시작하자. </p>
<h2 id="1-백준-2164-카드2">1. <a href="https://www.acmicpc.net/problem/2164">백준 2164 카드2</a></h2>
<blockquote>
<p><strong>아이디어</strong>  </p>
</blockquote>
<ul>
<li>처음에는 Stack으로 구현하였으나, 맨 아래로 넣는 작업에서 FIFO인 Queue로 구현하는것이 맞음. </li>
<li>맨 앞에서 빼기: poll() / 맨 뒤에 추가하기 : offer (), add()</li>
<li>구현 클래스는 LinkedList가 구현한다. </li>
</ul>
<pre><code class="language-java">package boj_silver.p2164_카드2;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        //스택
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        Queue&lt;Integer&gt; q = new LinkedList&lt;&gt;();

        //q에 1부터 ,,N까지 넣기 
        for(int i = 1; i&lt;=n; i++){
            q.offer(i);
        }
        //
        while(true){
            //큐에 있는 개수가 1이 될때 poll하기 -&gt; break 
            if (q.size() ==1){
                int num = q.poll();
                System.out.println(num);
                break;
            }//if

            //맨 첫번째 빼기
            q.poll();
            //맨 위에 있는것 맨 뒤로 보내기
            q.offer(q.poll());
        }
        scan.close();
    }
}
</code></pre>
<h2 id="2-백준-2178-미로탐색">2. <a href="https://www.acmicpc.net/problem/2178">백준 2178 미로탐색</a></h2>
<blockquote>
<p>*<em>아이디어 *</em> </p>
</blockquote>
<ul>
<li>map[n][m] 배열에 거리를 담자! (map[nx][ny] = map[cx][cy] + 1) </li>
<li>주의! 범위 체크! map[nx][ny] ==1 인것만 탐색</li>
</ul>
<h3 id="1-bfs로-풀기">1. bfs로 풀기</h3>
<pre><code class="language-java">package boj_silver.p2178_미로탐색;
import java.util.*;
import java.io.*;

public class Review4 {
    static int n,m;
    static int[][] map;
    static boolean[][] visited;

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

    //1,1에서 출발하여, N, M의 위치로 갈때 지나야하는 최소 칸의 개수
    public static void main(String[] args) throws IOException {
        Scanner scan = new Scanner(System.in);


        n = scan.nextInt(); m = scan.nextInt();
        scan.nextLine();
        map= new int[n+1][m+1];
        visited = new boolean[n+1][m+1];

        for (int i= 1; i&lt;=n;i++){
            String line = scan.nextLine();
            for (int j =1; j&lt;=m;j++){
                map[i][j] = line.charAt(j-1)-&#39;0&#39;;
            }
        }//for
//        System.out.println(Arrays.deepToString(map));
        bfs(1,1); 
        System.out.println(map[n][m]);
    }

    static void bfs(int x, int y){

        Queue&lt;int[]&gt; q = new ArrayDeque&lt;&gt;();
        q.offer(new int[]{x,y});
        visited[x][y] = true;

        while (!q.isEmpty()){
            int[] cur = q.poll();
            int cx= cur[0];
            int cy= cur[1];
            //4방향 탐색 
            for (int i = 0; i&lt;4; i++){
                int nx = cx+dx[i];
                int ny = cy+dy[i];
                //범위 조건: 가장 자리 조건 
                if(nx&gt;0 &amp;&amp; ny&gt;0 &amp;&amp; nx&lt;=n &amp;&amp; ny&lt;=m){
                //범위 조건: 탐색하지 않은것, 배열안이 1인것만 탐색 
                    if(!visited[nx][ny] &amp;&amp; map[nx][ny] ==1){
                        visited[nx][ny] = true;
                        q.offer(new int[]{nx,ny});
                        map[nx][ny] = map[cx][cy] +1;
                    }
                }
            }
        }

    }

}
</code></pre>
<h3 id="2-dfs로-풀기">2. dfs로 풀기</h3>
<pre><code class="language-java">
static void main(String[] args){
    visited[1][1]= true; 
    System.out.println(minDistance); 
}//main

static void dfs(int x, int y, int distance){
    //도착 
    if (x==n &amp;&amp; y==m){
        minDistance = Math.min(minDistance, distance); 
        return; 
    }
    //탐색 
    for (int i = 0; i&lt;4; i++){
        int nx = x+dx[i]; 
        int ny = y+ dy[i]; 

        if (nx&gt;0 &amp;&amp; nx&lt;=n &amp;&amp; ny&gt;0 &amp;&amp; ny&lt;=m){
            if (!visited[nx][ny] &amp;&amp; map[nx][ny] ==1){
                visited[nx][ny]= true; 
                dfs(nx, ny, distance+1); 
                visited[nx][ny] = false; //백트래킹 
            }

        }
    }

}
</code></pre>
<h2 id="3-백준-1260-dfs와-bfs">3. <a href="https://www.acmicpc.net/problem/1260">백준 1260 dfs와 bfs</a></h2>
<blockquote>
<p><strong>아이디어</strong></p>
</blockquote>
<ul>
<li><code>LinkedList&lt;Integer&gt;[] list</code> 배열로 받기 </li>
<li>간선 입력 받고, 정렬하기 (Collections.sort(list[i])) </li>
<li>dfs -&gt; bfs로 바꿀때, visited 초기화 </li>
<li>dfs) 현재 정점 방문 처리-&gt; 출력 -&gt; 인접 정점 탐색 (재귀)</li>
<li>bfs) Queue 선언 -&gt; Q offer -&gt; q가 빌때까지 인접 정점 출력</li>
</ul>
<hr>
<pre><code class="language-java">  package boj_silver.p1260_dfs와bfs;

import java.io.*;
import java.util.*;

public class Review1 {
    static int V;
    static boolean[] visited;
    static LinkedList&lt;Integer&gt;[] list;
    //정점 번호가 작은 것 먼저 방문, 더 이상 방문 x-&gt; 종료
    public static void main(String[] args) throws IOException {
        //Linked List&lt;Integer&gt;[] 로 하고, 우선순위 큐
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        V = Integer.parseInt(st.nextToken());

        //n개 생성
        list = new LinkedList[N+1];
        //모든 리스트 초기화
        for (int i = 1; i&lt;=N; i++){
            list[i] = new LinkedList&lt;&gt;();
        }
        //M개 입력 받기
        for (int i = 1; i&lt;= M; i++){
            st = new StringTokenizer(br.readLine());
            //list 초기화 하기
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            //양방향 입력-&gt; 정렬하기 작은 것 부터 방문해야한다.
            list[a].add(b);
            list[b].add(a);
        }
        //정렬하기
        for (int i = 1; i&lt;=N; i++){
            Collections.sort(list[i]); //모두 정렬하기
        }
        //첫번째 dfs
        visited = new boolean[N+1];
        dfs(V);
        System.out.println();
        visited = new boolean[N+1];
        bfs(V);
    }
    static void dfs(int v){
        //현재 정점 방문 처리 -&gt; 현재 정점 출력
        visited[v] = true;
        System.out.print(v + &quot; &quot;);

        //인접 정점 탐색 -&gt; 방문 안한 정점 재귀 호출
        // list[v]의 인점 정점 돌면서
        for (int next: list[v]){
            if(!visited[next]){
                dfs(next); // 재귀
            }
        }//
    }

    static void bfs(int v){
        Queue&lt;Integer&gt; q = new ArrayDeque&lt;&gt;();
        q.offer(v);
        visited[v] = true;
        while(!q.isEmpty()){
            int cur = q.poll();
            System.out.print(cur + &quot; &quot;);
            //인접 정점
            for (int next: list[cur]){
                if(!visited[next]){
                    q.offer(next);
                    visited[next] = true;
                }
            }
        }
    }
}
</code></pre>
<h2 id="4-백준-1012-유기농-배추">4. <a href="https://www.acmicpc.net/problem/1012">백준 1012 유기농 배추</a></h2>
<blockquote>
<p><strong>아이디어</strong></p>
</blockquote>
<h3 id="1-배추-있는-좌표-리스트에-yx순으로-저장함">1. 배추 있는 좌표 리스트에 {y,x}순으로 저장함.</h3>
<pre><code class="language-java">package boj_silver.p1012유기농배추;
//몇개의 bfs가 호출되는지 !
import java.io.*;
import java.util.*;

public class Main {
    static boolean[][] visited;
    static int m,n;
    static int[][] map;
    static int[] dx = { 0, 1, 0, -1 };
    static int[] dy = { 1, 0, -1, 0 };

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st ;

        int T = Integer.parseInt(bf.readLine());
        for (int i = 0; i &lt; T; i++) {
            st = new StringTokenizer(bf.readLine());
            m = Integer.parseInt(st.nextToken());
            n = Integer.parseInt(st.nextToken());
            int k = Integer.parseInt(st.nextToken());//배추의 개수

            ArrayList&lt;int[]&gt; list = new ArrayList&lt;&gt;();
            map = new int[n][m];

            visited = new boolean[n][m]; //초기화
            //k의 줄에 배추의 위치가 저장
            for (int j = 0; j&lt; k; j++){
                st = new StringTokenizer(bf.readLine());
                int x = Integer.parseInt(st.nextToken()); //가로 좌표
                int y = Integer.parseInt(st.nextToken());//세로 좌표
                list.add(new int[]{y,x});
                map[y][x] = 1;
            }// list에 있는 것 돌면서 !

            //boolean[] listVisited = new boolean[list.size()];

            int sum = 0;
            for (int[] cur: list){
                if (!visited[cur[0]][cur[1]]){
                    bfs(cur[0], cur[1]);
                    sum++;
                }

            }
            System.out.println(sum);
        }

        bf.close();
    }//main
    static void bfs(int x, int y){
        Queue&lt;int[]&gt; q = new ArrayDeque&lt;&gt;();
        q.add(new int[]{x,y});
        visited[x][y] = true;
        while(!q.isEmpty()){
            int [] cur = q.poll();
            int cx = cur[0];
            int cy = cur[1];
            for (int i = 0; i &lt; 4; i++) {
                int nx = cx+ dx[i];
                int ny = cy+ dy[i];
                if (nx&gt;=0 &amp;&amp; nx&lt;n &amp;&amp; ny&gt;=0 &amp;&amp; ny&lt;m){
                    if(!visited[nx][ny] &amp;&amp; map[nx][ny]==1 ) {
                        q.offer(new int[]{nx,ny});
                        visited[nx][ny] = true;
                    }

                }

            }//for
        }

    }
}
</code></pre>
<h3 id="2-리스트-없이-2중-for문">2. 리스트 없이 2중 for문</h3>
<blockquote>
<h4 id="-아이디어">** 아이디어**</h4>
<p> ** 1번** 
입력받을때 리스트에 좌표를 저장한다. (가로, 세로)로 주어짐 -&gt; list.add(new int[] {y,x}) 로 저장 
map[y][x] = 1; 
-&gt; 리스트에 있는 배추만 확인 
<strong>2번: 2중 for문</strong> 
입력받을때 map에만 저장한다. map[y][x] = 1; 
전체 map을 순회하면서 배추를 찾는다. 
==&gt; 둘다 괜찮으나, 리스트를 사용하는 경우는, K가 훨씬 작을때 사용하고, 2중 for문은 코드 간결성과 K가 nxm에 가까울때 </p>
</blockquote>
<pre><code class="language-java">//map 전체를 돌면서, 
package boj_silver.p1012유기농배추;
//몇개의 bfs가 호출되는지 !

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main_effi {
    static boolean[][] visited;
    static int m,n;
    static int[][] map;
    static int[] dx = { 0, 1, 0, -1 };
    static int[] dy = { 1, 0, -1, 0 };

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st ;

        int T = Integer.parseInt(bf.readLine());
        for (int i = 0; i &lt; T; i++) {
            st = new StringTokenizer(bf.readLine());
            m = Integer.parseInt(st.nextToken());
            n = Integer.parseInt(st.nextToken());
            int k = Integer.parseInt(st.nextToken());//배추의 개수

            //ArrayList&lt;int[]&gt; list = new ArrayList&lt;&gt;();
            map = new int[n][m];
            visited = new boolean[n][m]; //초기화

            //k의 줄에 배추의 위치가 저장
            for (int j = 0; j&lt; k; j++){
                st = new StringTokenizer(bf.readLine());
                int x = Integer.parseInt(st.nextToken()); //가로 좌표
                int y = Integer.parseInt(st.nextToken());//세로 좌표
                //list.add(new int[]{y,x});
                map[y][x] = 1;
            }// list에 있는 것 돌면서 !

            //boolean[] listVisited = new boolean[list.size()];
            //전체 맵 탐색
            int cnt =0;
            for (int x =0; x&lt;n;x++){
                for (int y =0; y&lt;m;y++){
                    if(map[x][y] ==1 &amp;&amp; !visited[x][y]){
                        bfs(x,y);
                        cnt++;
                    }
                }
            }
            System.out.println(cnt);


//            int sum = 0;
//            for (int[] cur: list){
//                if (!visited[cur[0]][cur[1]]){
//                    bfs(cur[0], cur[1]);
//                    sum++;
//                }
//
//            }
//            System.out.println(sum);
        }

        bf.close();
    }//main
    static void bfs(int x, int y){
        Queue&lt;int[]&gt; q = new ArrayDeque&lt;&gt;();
        q.add(new int[]{x,y});
        visited[x][y] = true;
        while(!q.isEmpty()){
            int [] cur = q.poll();
            int cx = cur[0];
            int cy = cur[1];
            for (int i = 0; i &lt; 4; i++) {
                int nx = cx+ dx[i];
                int ny = cy+ dy[i];
                if (nx&gt;=0 &amp;&amp; nx&lt;n &amp;&amp; ny&gt;=0 &amp;&amp; ny&lt;m){
                    if(!visited[nx][ny] &amp;&amp; map[nx][ny]==1 ) {
                        q.offer(new int[]{nx,ny});
                        visited[nx][ny] = true;
                    }

                }

            }//for
        }

    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 8일차] 1103]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-8%EC%9D%BC%EC%B0%A8-1103</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-8%EC%9D%BC%EC%B0%A8-1103</guid>
            <pubDate>Mon, 03 Nov 2025 10:00:02 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-16234-인구-이동"><a href="https://www.acmicpc.net/problem/16234">백준 16234 인구 이동 </a></h2>
<blockquote>
<p>**아이디어 </p>
</blockquote>
<ul>
<li>처음에 bfs로 했을때 안풀림!!! </li>
<li>인구 이동이 발생하는 동안 while문으로 접근해서 이동이 발생하면, day추가하는 방식으로 함. </li>
</ul>
<pre><code class="language-java"> javapackage boj_gold.p16234_인구이동;

import java.io.*;
import java.util.*;

public class Review1 {
    // 전역 변수 선언
    static int[][] map;           // N x N 크기의 땅 (각 칸의 인구수)
    static boolean[][] visited;   // BFS 방문 체크 배열
    static int[] dx = {-1, 1, 0, 0};  // 상하좌우 x
    static int[] dy = {0, 0, -1, 1};  // 상하좌우 y 
    static int N, L, R;           //  입력 받기 
    static boolean isMoved;       // 인구 이동 발생 여부 플래그

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

        // 맵 초기화 및 입력
        map = new int[N][N];
        for (int i = 0; i &lt; N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j &lt; N; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        int day = 0;  // 인구 이동이 며칠 동안 발생하는지 카운트

        // 인구 이동이 없을 때까지 반복
        while (true) {
            // 매일 visited 배열 초기화
            visited = new boolean[N][N];
            // 이동 발생 여부 초기화 (false부터 시작)
            isMoved = false;

            // 전체 맵을 순회하면서 연합 찾기
            for (int i = 0; i &lt; N; i++) {
                for (int j = 0; j &lt; N; j++) {
                    // 아직 방문하지 않은 칸이면 BFS로 연합 찾기
                    if (!visited[i][j]) {
                        bfs(i, j);
                    }
                }
            }

            // 인구 이동이 발생했으면 day 증가
            if (isMoved) {
                day++;
            } else {
                // 인구 이동이 발생하지 않았으면 종료
                break;
            }
        }

        // 결과 출력 (인구 이동이 며칠 동안 발생했는지)
        System.out.println(day);
    }

    /**
     * BFS를 이용해 (x, y)에서 시작하는 연합을 찾고 인구 이동 처리
     */
    static void bfs(int x, int y) {
        Queue&lt;int[]&gt; q = new ArrayDeque&lt;&gt;();        // BFS 탐색용 큐
        List&lt;int[]&gt; union = new ArrayList&lt;&gt;();      // 연합에 속한 칸들을 저장

        // 시작 칸을 큐와 연합에 추가
        q.offer(new int[]{x, y});
        union.add(new int[]{x, y});
        visited[x][y] = true;

        int sum = map[x][y];  // 연합의 총 인구수 (시작 칸의 인구수로 초기화)

        // BFS 탐색 시작
        while (!q.isEmpty()) {
            int[] cur = q.poll();
            int cx = cur[0];  // 현재 x 좌표
            int cy = cur[1];  // 현재 y 좌표

            // 상하좌우 4방향 탐색
            for (int i = 0; i &lt; 4; i++) {
                int nx = cx + dx[i];  // 다음 x 좌표
                int ny = cy + dy[i];  // 다음 y 좌표

                // 경계 체크 및 방문 체크
                if (0 &lt;= nx &amp;&amp; nx &lt; N &amp;&amp; 0 &lt;= ny &amp;&amp; ny &lt; N &amp;&amp; !visited[nx][ny]) {
                    // 현재 칸과 다음 칸의 인구 차이 계산
                    int diff = Math.abs(map[cx][cy] - map[nx][ny]);

                    // 인구 차이가 L 이상 R 이하이면 연합 형성 가능
                    if (diff &gt;= L &amp;&amp; diff &lt;= R) {
                        q.offer(new int[]{nx, ny});      // 큐에 추가 (BFS 계속)
                        union.add(new int[]{nx, ny});    // 연합에 추가
                        visited[nx][ny] = true;          // 방문 처리
                        sum += map[nx][ny];              // 연합의 총 인구수에 더하기
                    }
                }
            }
        }

        // 연합이 2개 이상의 칸으로 이루어진 경우에만 인구 이동 발생
        if (union.size() &gt;= 2) {
            // 연합의 평균 인구수 계산
            int avg = sum / union.size();

            // 연합에 속한 모든 칸의 인구수를 평균값으로 업데이트
            for (int[] pos : union) {
                map[pos[0]][pos[1]] = avg;
            }

            // 인구 이동이 발생했음을 표시
            isMoved = true;
        }
    }
}
</code></pre>
<pre><code class="language-java">package boj_gold.p16234_인구이동;
//인구 이동이 얼마나 걸리는지 .
//인구이동이 일어나는 조건: 두 나라의 인구 차이가 L명 R명 이하 -&gt;
//visited[] -&gt; bfs 사용
// 방향 둘러가면서, 차이가 L, R 사이면 -&gt; bfs 호출 -&gt; count + 1
// 인구 이동 안하면 바로 0 출력 -&gt; return
//count 출력

import java.io.*;
import java.util.*;

public class Review1 {
    static int[][] map;
    static boolean[][] visited;
    static int[] dx = {-1, 1, 0,0};
    static int[] dy = {0,0,-1,1};
    static int N, L, R;
    static Queue&lt;int[]&gt; q;
    static boolean isMoved;
    static int sum;


    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        L = Integer.parseInt(st.nextToken());
        R = Integer.parseInt(st.nextToken());
        map = new int[N][N];
        //
        for (int i = 0; i&lt; N; i++){
            st = new StringTokenizer(br.readLine());
            for (int j =0; j&lt;N; j++){
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        int day = 0;
        //인구이동이 발생하는 동안
        while(isMoved) {
            //visited 초기화
            visited = new boolean[N][N];
            //이동 발생 여부
            isMoved = false;
            //전체 맵 순회하면서
            for (int i = 0; i &lt; N; i++) {
                for (int j = 0; j &lt; N; j++) {
                    if (!visited[i][j]) {
                        //bfs로 연합 찾기
                        bfs(i, j);

                        isMoved = true;
                    }
                }
            }//for

            //만약 이동이 발생하면
            if(isMoved){
                day++;
            }else break;
        }//while
        System.out.println(day);

//        System.out.println(Arrays.deepToString(map));

        //일단 (0,0부터 시작하기)
        //만약 호출을 안하면 넣어줘야 함...........
//        int count =0;
//        q = new ArrayDeque&lt;&gt;();
//        for(int i = 0; i&lt; N; i++){
//            for (int j = 0; j&lt; N; j++){
//                if(!visited[i][j]){
//                    q.offer(new int[] {i,j});
//                    int sum = bfs(i, j, 0);
//                    count++;
//                }
//            }
//        }
//        System.out.println(count);


    }//main
    static void bfs(int x, int y){
        //돌면서 찾기
        Queue&lt;int[]&gt; q = new ArrayDeque&lt;&gt;();
        //연합에 속한 칸 저장
        List&lt;int[]&gt; union = new ArrayList&lt;&gt;();

        q.offer(new int[]{x,y});
        union.add(new int[]{x,y});
        visited[x][y] = true;
        while(!q.isEmpty()){
            int[] cur = q.poll();
            int cx = cur[0];
            int cy = cur[1];

            for(int i =0; i&lt;4; i++){
                //이동하면서 차이가 L, R사이이면,
                int nx = cx+ dx[i];
                int ny = cy + dy[i];

                if (0&lt;=nx &amp;&amp; nx &lt;N &amp;&amp; 0&lt;=ny &amp;&amp; ny&lt;N &amp;&amp; !visited[nx][ny]){
                    int diff = Math.abs(map[cx][cy] - map[nx][ny]);
                    if (diff&gt;=L &amp;&amp; diff&lt;=R){
                        //이동
                        q.offer(new int[]{nx,ny});
                        union.add(new int[]{nx,ny});
                        visited[nx][ny] = true;
                        sum += map[nx][ny];
                        //bfs(nx, ny, sum+map[cx][cy]);
                    }
                }
            }
        }//while
        //현재
        //union이 2개이상이라면 ?

        if(union.size()&gt;1){
            //평균 계산
            int avg  = sum/union.size();
            for (int[] pos: union){
                map[pos[0]][pos[1]] = avg;//map 업데이트
            }
            isMoved = true;
        }


    }


//    static int bfs(int x, int y, int sum){
//        q.offer(new int[] {x,y});
//        visited[x][y] = true;
//        //현재
//        int[] cur = q.poll();
//        int cx = cur[0];
//        int cy = cur[1];
//
//        cnt =0;
//        for (int i = 0; i&lt; 4; i++){
//            //이동하면서 차이가 L이상 R이하라면, 일단 더함
//            int nx = x+ dx[i];
//            int ny = y+ dy[i];
//            if (0&lt;=nx &amp;&amp; nx &lt;N &amp;&amp; 0&lt;=ny &amp;&amp; ny&lt;N &amp;&amp; !visited[nx][ny]){//경계선
//                int diff = Math.abs(map[cx][cy] - map[nx][ny]);
//                if (diff&gt;=L &amp;&amp; diff&lt;=R){
//                    //이동
//                    bfs(nx, ny, sum + map[cx][cy]);
//                    cnt++;
//                }
//
//            }
//        }//for
//        return sum;
//    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 7일차] 1031]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-7%EC%9D%BC%EC%B0%A8-1031</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-7%EC%9D%BC%EC%B0%A8-1031</guid>
            <pubDate>Mon, 03 Nov 2025 00:51:37 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-16234-인구이동"><a href="https://www.acmicpc.net/problem/16234">백준 16234 인구이동</a></h2>
<pre><code class="language-java">package boj_bronze.p3040_백설공주와일곱난쟁이;
import java.util.*;

public class Review1 {
    // 아이디어: 9개의 요소를 다 더한 후 100을 빼면, 제거해야할 2명의 난쟁이가 남는다. 
    static int[] nums; //9개 숫자 넣을 배열 

    public static void main(String[] args) {
        //입력 받기
        Scanner scan = new Scanner(System.in);
        nums = new int[9];

        int sum  =0;
        for (int i = 0; i &lt; 9; i++){
            nums[i] = scan.nextInt();
            sum+= nums[i];
        }
        //100에서 sum을 뺀 값이 난쟁이가 아닌 두 수를 더한 후보이다.
        int target_num = sum - 100;
        int n1  = -1, n2 = -1;
        // 두 숫자 찾기
        //두숫자를 더해 target_num이면 제거를 하는것
        for (int i = 0; i&lt; 9; i++){
            //nums배열에서 두 값을 더해서 target_num인 두 값을 찾기
            for (int j = i+1; j &lt; 9; j++){
                if (nums[i] + nums[j] == target_num){
                    n1 = i;//인덱스 저장
                    n2 = j; //인덱스 저장
                    break;
                }
            }
        }//for
        //출력
        for (int i = 0; i&lt; 9; i++){
            if (i!=n1 &amp;&amp; i !=n2){
                System.out.println(nums[i]);
            }
        }
        scan.close();
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 매일 풀기 6일차] 1030 ]]></title>
            <link>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-6%EC%9D%BC%EC%B0%A8-1030</link>
            <guid>https://velog.io/@haing3_3/%EC%BD%94%ED%85%8C-%EB%A7%A4%EC%9D%BC-%ED%92%80%EA%B8%B0-6%EC%9D%BC%EC%B0%A8-1030</guid>
            <pubDate>Thu, 30 Oct 2025 09:37:25 GMT</pubDate>
            <description><![CDATA[<h2 id="백준-11720-숫자의-합"><a href="https://www.acmicpc.net/problem/11720">백준 11720 숫자의 합</a></h2>
<blockquote>
<p><strong>아이디어</strong> </p>
</blockquote>
<ul>
<li>입력을 받는게 은근 쉽지 않네 </li>
<li>공백없이 숫자 받기 -&gt; ? </li>
<li>그냥 String으로 받아서 charAt()-&#39;0&#39;으로 받기 </li>
</ul>
<h3 id="나의-문제-풀이-과정">나의 문제 풀이 과정</h3>
<ul>
<li>scanner로 입력을 받을때, scan.nextInt()로 받으면 &#39;\n&#39;의 개행문자가 남아 입력부분이 잘 처리가 안되었음. </li>
<li><blockquote>
<p>scan.nextLine()으로 받기 </p>
</blockquote>
</li>
</ul>
<pre><code class="language-java">public class Review1 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int N = Integer.parseInt(scan.nextLine());

        //배열 생성
        int[] array = new int[N];

        String line = scan.nextLine();

        //N개만큼 받기
        for (int i = 0; i&lt; N ; i++) {
            array[i] = line.charAt(i) - &#39;0&#39;;
        }

        for (int i = 0; i&lt; N ; i++) {
            System.out.println(array[i]);
        }
    }
}
</code></pre>
<h2 id="코테에서-입력-꿀팁">코테에서 입력 꿀팁</h2>
<h3 id="1-n개의-정수-한줄에">1. N개의 정수 한줄에</h3>
<pre><code class="language-java">//입력: 5 5 4 3 2 1 
int n = scan.nextInt(); 
int[] arr = new int[n]; 
for (int i=0; i&lt;n; i++){
    arr[i] = scan.nextInt(); 
}</code></pre>
<h3 id="2-공백으로-구분된-숫자---bufferedreader--stringtokenizer">2. 공백으로 구분된 숫자 -&gt; BufferedReader + StringTokenizer</h3>
<pre><code class="language-java">//입력: 1 2 3 4 5
String[] input = bf.readLine().split(&quot; &quot;); 
int[] arr = new int[input.length]; 
for (int i = 0; i&lt; input.length; i++){
    arr[i] = Integer.parseInt(input[i]); 

//또는 String Tokenizer
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); 
 StringTokenizer st = new StringTokenizer(bf.readLine()); 
 int N = Integer.parseInt(st.nextToken()); 
}</code></pre>
<h3 id="3-붙어-있는-숫자들">3. 붙어 있는 숫자들</h3>
<pre><code class="language-java">//입력: 12345
String line = bf.readine(); 
int[] arr = new int[line.length()]; 
for (int i = 0; i&lt; line.length(); i++){
    arr[i] = line.charAt(i)- &#39;0&#39;; 
}</code></pre>
<h3 id="4-2차원-배열-받기">4. 2차원 배열 받기</h3>
<pre><code class="language-java">// 입력: 
// 3 4
// 1 2 3 4
// 5 6 7 8
// 9 10 11 12

int n = scan.nextInt(); 
int m - scan.nextInt(); 
int[][] arr = new int[n][m]; 
for (int i = 0; i&lt; n; i++){
    for(int j = 0; j&lt; m; j){
            arr[i][j] = scan.nextInt(); 
    }
}</code></pre>
<h3 id="5-끝까지-읽기-eof까지-읽기">5. 끝까지 읽기 (EOF까지 읽기)</h3>
<pre><code class="language-java">//scanner 
while(scan.hasNext()){
    int n = scan.nextInt(); 
    //처리 
}</code></pre>
<h3 id="6-빠른-출력">6. 빠른 출력</h3>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(); 
for (int i =0; i&lt; n; i++_){
    sb.append(i).append(&quot;\n&quot;); 
}
System.out.print(sb); </code></pre>
]]></description>
        </item>
    </channel>
</rss>