<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>co_ol.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 23 Nov 2024 17:05:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>co_ol.log</title>
            <url>https://velog.velcdn.com/images/co_ol/profile/0d3616a3-4460-48ca-9429-5c6beb6ad60c/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. co_ol.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/co_ol" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[프로그래머스 - 아이템 줍기(java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%95%84%EC%9D%B4%ED%85%9C-%EC%A4%8D%EA%B8%B0java</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%95%84%EC%9D%B4%ED%85%9C-%EC%A4%8D%EA%B8%B0java</guid>
            <pubDate>Sat, 23 Nov 2024 17:05:31 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/87694">📃프로그래머스 - 아이템 줍기</a></p>
<p><code>DFS/BFS</code> , <code>LEVEL3</code></p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">    int sx, sy, ex, ey;
    int[][] map = new int[102][102];
    boolean[][] chkMap = new boolean[102][102];
    public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) {
        int answer = 0;
        sx = characterX * 2;
        sy = characterY * 2;
        ex = itemX * 2;
        ey = itemY * 2;


        /* 1. map에 주어진 사각형 영역을 -1 로 채운다. */
        for(int[] r : rectangle){
            for(int x=r[0]*2; x&lt;=r[2]*2; x++){
                for(int y=r[1]*2; y&lt;= r[3]*2; y++){
                    map[x][y] = -1;
                }
            }
        }

        /* 2. 지뢰찾기 하듯이.. chkMap 에 테두리만 부분만 true 로 남긴다. */
        for(int i=1 ; i&lt; 101 ; i++){
            for(int j=1; j &lt; 101 ; j++){
                if(map[i][j] != -1)continue;
                if(map[i-1][j-1] + map[i-1][j] + map[i-1][j+1] + map[i][j-1] + map[i][j+1] + map[i+1][j-1] + map[i+1][j] + map[i+1][j+1] &gt; -8){
                    chkMap[i][j] = true;
                }
            }
        }

        bfs(sx, sy, 0);

        return map[ex][ey] / 2;
    }


    public void bfs(int x, int y, int cnt){

        if(map[x][y] == -1){
            // map 에 현재 카운트수 기록
            map[x][y] = cnt;

        } else{
            // 이미 방문한 적이 있는 경우(목적지) 더 적은 cnt 채택
            map[x][y] = Math.min(map[x][y], cnt);
        }
        if(x==ex &amp;&amp; y==ey ) {
            // 탈출 조건
            return;
        }

        /* 3. 테두리를 따라 갈 수 있는 방향으로 계속 간다. */
        // 목적지를 제외하고 한번 간 곳은 가지 않는다.
        if((x-1 == ex &amp;&amp; y == ey) || (chkMap[x-1][y] &amp;&amp; map[x-1][y] == -1)) bfs(x-1, y, cnt + 1);
        if((x+1 == ex &amp;&amp; y == ey) || (chkMap[x+1][y] &amp;&amp; map[x+1][y] == -1)) bfs(x+1, y, cnt + 1);
        if((x == ex &amp;&amp; y-1 == ey) || (chkMap[x][y-1] &amp;&amp; map[x][y-1] == -1)) bfs(x, y-1, cnt + 1);
        if((x == ex &amp;&amp; y+1 == ey) || (chkMap[x][y+1] &amp;&amp; map[x][y+1] == -1)) bfs(x, y+1, cnt + 1);

    }</code></pre>
<h2 id="풀이">풀이</h2>
<blockquote>
<ol>
<li>map에 주어진 사각형 영역을 -1 로 채운다.</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/co_ol/post/2de262b6-511e-42e5-b2ce-33914f039a25/image.png" alt=""></p>
<blockquote>
<ol start="2">
<li>지뢰찾기 하듯이.. chkMap 에 테두리만 부분만 true 로 남긴다.</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/co_ol/post/ee8e86be-3c8c-427b-9567-e43d762a2526/image.png" alt=""></p>
<blockquote>
<ol start="3">
<li>테두리를 따라 갈 수 있는 방향으로 간다.</li>
</ol>
</blockquote>
<p>x, y 현재 위치 기준으로 T 인곳으로 가면서 cnt를 map 에 기록한다.</p>
<p><img src="https://velog.velcdn.com/images/co_ol/post/5bf78c22-608c-4573-87e4-e67878e53dd1/image.png" alt=""></p>
<blockquote>
<ol start="4">
<li>목적지에 있는 cnt 수를 가져온다. </li>
</ol>
</blockquote>
<p>2를 곱하여 계산했으므로 나누기 2 하면 답!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 과제 진행하기(java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B3%BC%EC%A0%9C-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0java</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B3%BC%EC%A0%9C-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0java</guid>
            <pubDate>Thu, 20 Apr 2023 01:31:27 GMT</pubDate>
            <description><![CDATA[<h4 id="📓문제">📓문제</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/176962">프로그래머스 - 과제 진행하기</a></p>
<h4 id="📓풀이">📓풀이</h4>
<p>과제가 끝날 시간과 다음과제가 시작될 시간의 차인 <code>remainTime</code> 이 핵심값</p>
<blockquote>
<p><code>remainTime</code>  == 0 
 과제가 끝남과 동시에 다음 과제 시작</p>
</blockquote>
<blockquote>
<p><code>remainTime</code>  &lt; 0 
  과제를 다 못했는데 다음 과제가 시작됨
 과제를 미뤄야함</p>
</blockquote>
<blockquote>
<p><code>remainTime</code>  &gt; 0 
  과제를 다 했는데 다음 과제까지 시간이 남음
  미뤄둔 과제가 있다면 할 수 있음</p>
</blockquote>
<ul>
<li><p>과제를 둘로 나누어 생각한다.
<code>계획된 과제</code>와 <code>미뤄둔 과제</code> </p>
</li>
<li><p>계획된 시간에 맞춰 과제를 진행한다.
위 처럼 remainTime을 계산하여 시간이 맞지 않으면 과제를 미루거나 밀린 과제를 한다. </p>
</li>
<li><p>마지막 시간에 시작하는 과제는 중간에 그만둬야하는 경우가 없다. 
→ 다음 과제 시작시간을 예상종료시간(start + play)과 똑같이 정하면 된다.</p>
</li>
<li><p>마지막 과제가 끝나면 미뤄둔 과제들은 play 시간과 상관 없이 차례로 끝내면된다.</p>
</li>
</ul>
<p><br><br></p>
<h4 id="📓코드">📓코드</h4>
<pre><code class="language-java"> public List&lt;String&gt; solution(String[][] plans) {
    List&lt;String&gt; answer = new ArrayList&lt;&gt;();

    PriorityQueue&lt;Integer&gt; startQ = new PriorityQueue&lt;&gt;();
    Map&lt;Integer, String&gt; startNameMap = new HashMap&lt;&gt;();
    Map&lt;String, Integer&gt; namePlayMap = new HashMap&lt;&gt;();

    for(String[] plan : plans){
        String name = plan[0];
        int start = Integer.parseInt(plan[1].substring(3,5)) + (Integer.parseInt(plan[1].substring(0,2)) * 60);
        int playTime = Integer.parseInt(plan[2]);
        startQ.add(start);
        startNameMap.put(start, name);
        namePlayMap.put(name, playTime);
    }        

    Stack&lt;String&gt; postponedTask = new Stack&lt;&gt;();
    //1. 주어진 시간대로 과제하기
    while(!startQ.isEmpty()){
        int now = startQ.poll();
        String name = startNameMap.get(now);        //해야할 과제명
        int endTime = now + namePlayMap.get(name);  //예상 종료시간
        int nextStartTime = (!startQ.isEmpty()) ? startQ.peek() : endTime;// 다음 과제 시작 시간
        //1-1. 시간 계산
        int remainTime = nextStartTime - endTime;

        //1-2. A. 과제를 다했다
        if(remainTime &gt;= 0){
            answer.add(name);//A-1. 완료처리
            while (remainTime &gt; 0){//A-2. 남은 시간 활용하기
                if(!postponedTask.isEmpty()){//A-3. 미뤄둔 과제가 있다.
                    String postponed = postponedTask.peek();
                    int postponedTime = namePlayMap.get(postponed);
                    if (postponedTime &lt;= remainTime){//A-3. 남은 시간동안 완료함(완료처리)
                        answer.add(postponedTask.pop());
                    }else{//A-3. 남은 시간동안 다 못함
                        namePlayMap.put(postponed, postponedTime - remainTime);
                    }
                    remainTime -= postponedTime;
                }else break;
            }
        }
        //1-2. B. 과제를 다 못함..
        else{
            namePlayMap.put(name, Math.abs(remainTime));
            postponedTask.push(name);//B-1. 과제 미루기
        }
    }
    //2. 미뤄둔 과제 차례로 완료하기
    while(!postponedTask.isEmpty()){
        answer.add(postponedTask.pop());
    }
    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 가장 먼 노드(java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9E%A5-%EB%A8%BC-%EB%85%B8%EB%93%9Cjava</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9E%A5-%EB%A8%BC-%EB%85%B8%EB%93%9Cjava</guid>
            <pubDate>Mon, 08 Aug 2022 13:58:50 GMT</pubDate>
            <description><![CDATA[<h3 id="🐴-문제">🐴 문제</h3>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/49189">📃프로그래머스 - 가장 먼 노드</a></p>
<p>그래프 카테고리의 level3문제다.</p>
<p>처음 풀어보는 그래프 문제라 처음에 헤맸다. 그래도 이 문제를 풀면서 언제 bfs를 써야하는지 감이 좀 잡혔다.</p>
<p>bfs를 공부할겸 인접리스트로 푸는 방법, 인접행렬로 푸는 방법 두 가지로 풀어봤다.</p>
<h3 id="🐴-bfs">🐴 bfs</h3>
<p>bfs 문제를 푸는 방법은 인접리스트를 이용하는 방법, 인접행렬을 이용하는 방법 두가지가 있다.</p>
<p>푸는 방법은</p>
<ul>
<li>인접리스트 : 존재하는 간선에 대해서만 탐색을 한다.</li>
<li>인접행렬 : 모든 정점에 대해 탐색</li>
</ul>
<p>시간복잡도로 보면<br><code>G: 그래프, V: 정점, E: 간선</code></p>
<ul>
<li>인접리스트    : <code>O(V+E)</code></li>
<li>인접행렬 : <code>O(V^2)</code></li>
</ul>
<h3 id="🐴-로직---인접리스트">🐴 로직 - 인접리스트</h3>
<p>** <em>테스트케이스 *</em></p>
<pre><code>기본 테스트케이스를 조금 변형한 아래의 테스트케이스로 로직을 설명한다.
6, [[3, 6], [1, 3], [1, 2], [2, 4], [5, 2]]</code></pre><h4 id="1-인접-리스트-만들기">1. 인접 리스트 만들기</h4>
<p>간선의 방향이 양방향 이므로 인접 리스트 양쪽 노드에 모두 추가
<img src="https://images.velog.io/images/co_ol/post/6d52988a-3dd8-4752-b7d5-3358574943d4/image.png" alt=""></p>
<h4 id="2-bfs로-탐색">2. bfs로 탐색</h4>
<p>시작 노드가 1(0)로 정해져있다. 
bfs메서드에 탐색해야할 노드를 큐로 넘겨준다.</p>
<p><img src="https://images.velog.io/images/co_ol/post/31e2ab3b-ea92-440e-8b04-4b373f5feacd/image.png" alt=""></p>
<h3 id="🐴-코드---인접리스트">🐴 코드 - 인접리스트</h3>
<pre><code class="language-java">public int solution(int n, int[][] edge) {
    /* 인접 리스트에 데이터 추가*/
    //인접리스트 생성
    List&lt;List&lt;Integer&gt;&gt; adList = new ArrayList&lt;&gt;();
    //노드수만큼 초기화
    for (int i = 0; i &lt; n; i++) {
        adList.add(new ArrayList&lt;Integer&gt;());
    }
    //데이터 추가
    for (int[] e : edge) {
        adList.get(e[0] - 1).add(e[1] - 1);
        adList.get(e[1] - 1).add(e[0] - 1);
    }

    Queue&lt;Integer&gt; q = new LinkedList&lt;&gt;();
    q.offer(0);

    boolean[] check = new boolean[n];
    check[0] = true;

    return bfs(adList, q, check);
}


public int bfs(List&lt;List&lt;Integer&gt;&gt; adList, Queue&lt;Integer&gt; q, boolean[] check) {
    int answer = q.size();        
    Queue&lt;Integer&gt; q2 = new LinkedList&lt;&gt;();

    /* 1. 다음 depth에 해당하는 노드를 확인하고 큐에 담는다.*/
    while(!q.isEmpty()) {
        for (int i : adList.get(q.poll())) {
            if (!check[i]) {
                check[i] = true;
                q2.offer(i);
            }
        }
    }
    /* 2. 다음 depth가 없다면 return */
    if(q2.size()==0) return answer;
    /* 2. 있다면 bfs */
    answer = bfs(adList, q2, check);

    return answer;
}</code></pre>
<h3 id="🐴-로직---인접행렬">🐴 로직 - 인접행렬</h3>
<h4 id="1-인접행렬-만들기">1. 인접행렬 만들기</h4>
<p>boolean타입의 2차원 배열로 행렬을 사용했다.
<img src="https://images.velog.io/images/co_ol/post/f261fd1e-c18b-457d-8bd2-cf4aea25077d/image.png" alt=""></p>
<h3 id="🐴-코드---인접행렬">🐴 코드 - 인접행렬</h3>
<pre><code class="language-java">public int solution(int n, int[][] edge) {
    /*1. 인접행렬에 담기  */
    boolean[][] arr = new boolean[n+1][n+1];

    for(int[] e : edge) {
        arr[e[0]][e[1]] = true;
        arr[e[1]][e[0]] = true;
    }

    Queue&lt;Integer&gt; q = new LinkedList&lt;Integer&gt;();
    q.offer(1);
    boolean[] check = new boolean[n+1];
    check[1] = true;
    /* 2. bfs*/
    return bfs(arr, q, check);
}


public int bfs(boolean[][] arr, Queue&lt;Integer&gt; q, boolean[] check) {
    int size = q.size();    //현제 Depth의 노드 수 

    /* 다음 탐색해야할 노드들 큐에 담기  */
    Queue&lt;Integer&gt; q2 = new LinkedList&lt;Integer&gt;();
    while(!q.isEmpty()) {
        for(int i = 1; i &lt; check.length ; i++) {
            if(arr[q.peek()][i] &amp;&amp; !check[i]) {
                check[i] = true;
                q2.offer(i);
            }
        }
        q.poll();
    }
    /* 다음 탐색해야할 노드가 없다면(지금이 마지막 depth라면) size 리턴*/
    if(q2.isEmpty()) {
        return size;
    }

    return bfs(arr, q2, check);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[maven이란?]]></title>
            <link>https://velog.io/@co_ol/maven%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@co_ol/maven%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Mon, 08 Aug 2022 13:56:48 GMT</pubDate>
            <description><![CDATA[<h3 id="maven-이란">maven 이란?</h3>
<p>프로젝트를 <strong>빌드</strong>하고 <strong>라이브러리를 관리</strong>해주는 도구</p>
<p>  프로젝트를 진행하게 되면 단순히 자신이 작성한 코드만으로 개발하는 것이 아니라 많은 라이브러리들을 활용해서 개발을 하게 된다.
  Maven은 내가 사용할 라이브러리 뿐만 아니라 해당 라이브러리가 작동하는데 필요한 다른 라이브러리들까지 관리하여 네트워크를 통해 자동으로 다운 받아준다.</p>
<p>  Maven은 프로젝트의 전체적인 라이프사이클을 관리하는 도구이며, 많은 편리함과 이점이 있어 널리 사용되고 있다. 기존에는 Ant가 많이 사용되었지만 Maven이 Ant를 넘어서 더 많은 개발자들이 사용하게 되었고 비교적 최근에는 Gradle이 새롭게 나와 사용되고 있다.</p>
<h3 id="maven의-lifecycle">maven의 LifeCycle</h3>
<p><a href="https://myjamong.tistory.com/153">https://myjamong.tistory.com/153</a></p>
<p>maven 에서는 미리 정의하고 있는 빌드 순서가 있으며 이 순서를 라이프사이클이라고 한다. 라이프 사이클의 가 빌드 단계를 <strong>Phase</strong>라고 하는데 이런 Phase들은 의존관계를 가지고 있다.</p>
<p>각 phase에는 plugin이 존재하고 해당 plugin에서 수행 가능한 명령을 <strong>goal</strong> 이라고 합니다.</p>
<p><img src="https://velog.velcdn.com/images/co_ol/post/763724b5-7120-47bd-b7f2-ca45541e2ec7/image.png" alt=""></p>
<p>Goals의 &quot;:&quot; 기준으로 앞은 plugin을 의미하고 뒷 부분은 해당 plugin의 goal을 뜻합니다.</p>
<p><img src="https://velog.velcdn.com/images/co_ol/post/4695a184-ac47-4d49-92fd-dc4730b16616/image.png" alt="기본 라이프 사이클"></p>
<p><strong>&lt; 기본(Default) 라이프사이클&gt;</strong></p>
<ul>
<li>Validate : 프로젝트가 올바른지 확인학고 필요한 모든 정보를 사용할 수 있는 지 확인하는 단계</li>
<li>Compile : 프로젝트의 소스코드를 컴파일하는 단계<pre><code>   성공적으로 컴파일되면 target/classes 폴더가 만들어지고 컴파일된 class파일이 생성된다.</code></pre></li>
<li>Test : 유닛(단위) 테스트를 수행하는 단계(테스트 실패시 빌드 실패로 처리, 스킵 가능)</li>
<li>Package : 실제 컴파일된 소스 코드와 리소스들을 jar등의 배포를 위한 패키지로 만드는 단계</li>
<li>Verify : 통합테스트 결과에 대한 검사를 실행하여 품질 기준을 충족하는지 확인하는 단계</li>
<li>Install : 패키지를 로컬 저장소에 설치하는 단계
  (local repository 즉, maven이 설치되어 있는 PC에 배포)</li>
<li>Deploy : 만들어진 Package를 원격 저장소에 release하는 단계</li>
</ul>
<p><strong>&lt; clean 라이프사이클&gt;</strong></p>
<ul>
<li>Clean : 이전 빌드에서 생성된 파일들을 삭제하는 단계</li>
</ul>
<p><strong>&lt; site 라이프사이클&gt;</strong></p>
<ul>
<li>Site : 프로젝트 문서를 생성하는 단계</li>
</ul>
<h3 id="pom---project-object-model">POM - Project Object Model</h3>
<p>pom은 Project Object Model 의 약자로 이름 그대로 Project Object Model의 정보를 담고있는 파일이다. 이 파일에서 주요하게 다루는 기능들은 다음과 같다.</p>
<ul>
<li>프로젝트 정보 : 프로젝트의 이름, 개발자 목록, 라이센스 등</li>
<li>빌드 설정 : 소스, 리소스, 라이프 사이클별 실행한 플러그인(goal)등 빌드와 관련된 설정</li>
<li>빌드 환경 : 사용자 환경 별로 달라질 수 있는 프로파일 정보</li>
<li>POM연관 정보 : 의존 프로젝트(모듈), 상위 프로젝트, 포함하고 있는 하위 모듈 등</li>
</ul>
<p>POM은 pom.xml파일을 말하며 Maven의 기능을 이용하기 위해 POM이 사용된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스-등굣길(java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%93%B1%EA%B5%A3%EA%B8%B8java</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%93%B1%EA%B5%A3%EA%B8%B8java</guid>
            <pubDate>Mon, 08 Aug 2022 13:54:53 GMT</pubDate>
            <description><![CDATA[<h2 id="🏫문제">🏫문제</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42898">프로그래머스-등굣길</a></p>
<p>** 다이나믹 프로그래밍이란? **
특정 범위까지의 값을 구하기 위해서 그것과 다른 범위까지의 값을 이용하여 효율적으로 값을 구하는 알고리즘 설계 기법이다. </p>
<p>최단경로 문제도 기존 경로 값을 이용하여 쉽게 구할 수 있다.</p>
<h2 id="🏫풀이">🏫풀이</h2>
<p>예제의 기본 테스트케이스를 준비했다.
아래의 지도에 경로의 수를 기록하면 된다.
<img src="https://velog.velcdn.com/images/co_ol/post/a49801ff-94e0-4858-b2c8-2eacd884c9cc/image.png" alt=""></p>
<p><strong>1. 초기화</strong></p>
<ul>
<li>시작점은 (1,1)로 정해져 있으므로 첫칸(1,1)은 &quot;1&quot;로 설정한다.</li>
<li>웅덩이를 식별하기 위해 음수 &quot;-1&quot; 로 설정한다.</li>
<li>편의를 위해 0번째 행과 열은 비워둔다. (깍두기)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/co_ol/post/3dddd679-f571-47b0-b4a4-d54bb461f711/image.png" alt=""></p>
<p>** 2. 경로 계산 **</p>
<ul>
<li><p>등굣길은 오른쪽과 아래 방향으로만 갈 수 있으므로</p>
</li>
<li><p>** 이 길을 지나갈 수 있는 경우의 수 = 위쪽 길의 경우의 수 + 왼쪽 길의 경우의 수 **</p>
</li>
<li><p>첫칸(1,1)은 생략하고 왼쪽부터 아래로 차례대로 왼쪽과 위쪽의 값을 더해준다.</p>
</li>
<li><p>웅덩이가 나오면 0으로 설정해주고 더한다.
_ 첫번째 열과 첫번재 행의 계산을 편하게 하기 위해 &#39;2.초기화&#39; 과정에서 깍두기 줄을 추가 해줬다. _</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/co_ol/post/88e7b18b-a122-4e51-8d53-77b9cd05f54b/image.png" alt=""></p>
<p>** 3. 정답은 4!! **</p>
<h2 id="코드">코드</h2>
<pre><code class="language-java">
public int solution(int m, int n, int[][] puddles) {
    //배열 생성 및 초기화
    int[][] route = new int[m+1][n+1];

    route[1][1] = 1;

    /* 2. 웅덩이 -1 으로 표시 */
    for(int[] p : puddles) {
        int i = p[0];
        int j = p[1];
        route[i][j] = -1;
    }

    /* 3. 경우의 수 계산 */
    for(int i=1 ; i &lt;= m ; i++) {
        for(int j=1 ; j &lt;= n ; j++) {
            if(i == 1 &amp;&amp; j == 1) continue; //첫칸은 생략
            if(route[i][j] &lt; 0) {//웅덩이
                route[i][j] = 0;
                continue; 
            }
            route[i][j] = (route[i][j-1]  % 1000000007) + (route[i-1][j] % 1000000007);
        }
    }

    return route[m][n] % 1000000007;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 주차 요금 문제 (java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A3%BC%EC%B0%A8-%EC%9A%94%EA%B8%88-%EB%AC%B8%EC%A0%9C-java</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A3%BC%EC%B0%A8-%EC%9A%94%EA%B8%88-%EB%AC%B8%EC%A0%9C-java</guid>
            <pubDate>Fri, 15 Jul 2022 06:06:45 GMT</pubDate>
            <description><![CDATA[<h3 id="🚗문제">🚗문제</h3>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/92341">코딩테스트 연습 - 주차 요금 계산</a></p>
<h3 id="🚗풀이">🚗풀이</h3>
<ol>
<li><p>시간 기록하기</p>
<ul>
<li>Map&lt;차량번호, 주차시간&gt; 을 사용하여 In 일때는 &quot;- 시간&quot;, out 일때는 &quot;+ 시간&quot; 을 한다.</li>
</ul>
</li>
<li><p>정산하기</p>
<ul>
<li><p>map을 돌며 주차요금을 계산한다.</p>
<p>2-1. 미출차 차량 시간 계산</p>
</li>
<li><p>미출차 차량(시간이 0 or 음수인 차량)인 경우 12:59 기준으로 시간 계산</p>
<p>2-2. 정산하기</p>
</li>
<li><p>주어진 요금표 정보로 계산</p>
</li>
</ul>
</li>
</ol>
<h3 id="🚗코드">🚗코드</h3>
<pre><code class="language-java">import java.util.*;
class Solution {
    public List&lt;Integer&gt; solution(int[] fees, String[] records) {

        Comparator&lt;String&gt; comparator = (s1, s2)-&gt;s1.compareTo(s2);        
        Map&lt;String, Integer&gt; timeMap = new TreeMap&lt;&gt;(comparator);

        final int basetime  = fees[0]; //기본 시간
        final int baseFee   = fees[1]; //기본 요금
        final int plustime  = fees[2]; //추가 시간
        final int plusFee   = fees[3]; //추가 요금

        /* 기록하기
         * Map&lt;차번호, 시간&gt;*/
        for(String record : records) {
            String[] r = record.split(&quot; &quot;);
            int time = Integer.parseInt(r[0].split(&quot;:&quot;)[0]) * 60 + Integer.parseInt(r[0].split(&quot;:&quot;)[1]);
            String carNum = r[1];
            //IN 이면 &quot;-시간&quot; OUT이면 &quot;시간&quot;
            time = (r[2].equals(&quot;IN&quot;)) ? time*-1 : time;
            timeMap.put(carNum, timeMap.getOrDefault(carNum, 0) + time);

        }

        /* 정산하기 */
        timeMap.forEach((key, value) -&gt; {
            //1. 출차 내역 없는 차량(시간이 음수값 or 0 인 차량) 시간 계산
            int howlong = (value &lt;= 0) ? value + 1439 : value;
            //2. 정산
            int howmuch = (howlong &lt; basetime) ? baseFee : baseFee + (int) Math.ceil(((float)(howlong - basetime) / plustime)) * plusFee; 
            timeMap.put(key, howmuch);
        });

        return new ArrayList&lt;&gt;(timeMap.values());
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 정수 삼각형(java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%95%EC%88%98-%EC%82%BC%EA%B0%81%ED%98%95java</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%95%EC%88%98-%EC%82%BC%EA%B0%81%ED%98%95java</guid>
            <pubDate>Thu, 21 Oct 2021 04:44:37 GMT</pubDate>
            <description><![CDATA[<h3 id="🔺문제">🔺문제</h3>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/43105">📃프로그래머스 - 정수 삼각형</a></p>
<p>동적계획법(Dynamic Programming) 카테고리의 level3 문제다. </p>
<h3 id="🔺동적프로그래밍">🔺동적프로그래밍</h3>
<p>처음엔 동적프로그래밍이 뭔지 공부도 안하고 모든 경우의 수를 재귀로 풀려고 했다.
역시나 효율성 제로ㅎ</p>
<p>동적프로그래밍이 무엇인지 찾아보니..</p>
<p><strong>&lt; 동적프로그래밍 &gt;</strong></p>
<ul>
<li>큰 문제를 작은 문제로 분할하여 해결하는 알고리즘이다.</li>
<li>작은 문제는 반복되지 않고 풀때마다 항상 값이 같다.</li>
<li>작은 문제의 답을 어딘가에 메모 해놓는다. → Memoization</li>
</ul>
<p>설명만 읽고는 잘 와닿지 않았다. 문제를 풀며 조금씩 감이 잡혔다.</p>
<p>이 문제는 위에서 아래로 대각선 방향으로 내려오며 더했을 때 가장 큰 경우를 찾는 문제이다.</p>
<h3 id="🔺로직">🔺로직</h3>
<p>이 문제의 로직은 간단하다.
대각선 방향으로 한줄씩 내려오며 숫자를 더하는걸 작은 문제로 나눠서 풀면 된다.
작은 문제의 답은 풀때마다 항상 같다.</p>
<p>아래가 이 문제의 작은문제다.
노랑(자신 + 왼쪽 대각선) vs 초록(자신 + 오른쪽 대각선)
이 두개를 비교하여 더 큰수가 해당 자리의 답이 된다. 
<img src="https://images.velog.io/images/co_ol/post/aa4b766c-b312-4ab1-aaed-d8bd3ce7fc38/image.png" alt=""></p>
<p>두번째 줄 부터</p>
<ol>
<li><p>줄의 왼쪽 끝 숫자는 자신과 윗줄의 왼쪽 숫자와 더한다.
<img src="https://images.velog.io/images/co_ol/post/a263c9ed-ed1b-44a7-8d3f-5dde5e4150d0/image.png" alt=""></p>
</li>
<li><p>왼쪽과 더한 수 , 오른쪽과 더한 수 두 개를 비교하여 더 큰수가 해당 자리의 답이 된다. 
<img src="https://images.velog.io/images/co_ol/post/aa4b766c-b312-4ab1-aaed-d8bd3ce7fc38/image.png" alt=""></p>
</li>
<li><p>오른쪽 끝 숫자는 자신과 윗줄의 오른쪽 숫자와 더한다. 
<img src="https://images.velog.io/images/co_ol/post/a648a377-70d8-4e1d-9e10-3e9fb49b3604/image.png" alt=""></p>
</li>
</ol>
<p>위 과정을 반복하여 memoization을 거치면 오른쪽과 같이 된다.
이 중 가장 큰 수 가 문제의 답이된다. 
<img src="https://images.velog.io/images/co_ol/post/5dfca397-f293-4807-970b-5af6dc79d9d7/image.png" alt=""></p>
<h3 id="🔺코드">🔺코드</h3>
<pre><code class="language-java">for(int i = 1; i &lt; n ; i++) {
    for(int j = 0; j &lt; triangle[i].length ; j++) {

        if(j == 0) {//왼쪽 끝
            triangle[i][j] += triangle[i-1][j];
        }
        else if(j == i) {//오른쪽 끝
            triangle[i][j] += triangle[i-1][j-1];
        }
        else {
            triangle[i][j] += Math.max(triangle[i-1][j], triangle[i-1][j-1]);
        }

        answer = Math.max(answer, triangle[i][j]);
    }
}
return answer;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 베스트앨범(java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%B2%A0%EC%8A%A4%ED%8A%B8%EC%95%A8%EB%B2%94java</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%B2%A0%EC%8A%A4%ED%8A%B8%EC%95%A8%EB%B2%94java</guid>
            <pubDate>Wed, 08 Sep 2021 16:45:13 GMT</pubDate>
            <description><![CDATA[<h3 id="💿📀-문제">💿📀 문제</h3>
<p>[📃프로그래머스 - 베스트앨범] (<a href="https://programmers.co.kr/learn/courses/30/lessons/42579">https://programmers.co.kr/learn/courses/30/lessons/42579</a>)
<br/></p>
<h3 id="💿📀-풀이">💿📀 풀이</h3>
<p>문제의 조건에 따라 고려 대상의 우선순위는 아래와 같다.</p>
<p>** 장르별 총 재생수 → 앨범별 재생 수 → 앨범의 고유번호 **</p>
<p> 장르별 정렬이 우선이기 때문에 장르명이 Key값인 Map을 이용해 풀어야 할 것 같은데 value를 어떻게 잡을지 고민이 됐다. </p>
<p>장르명에 따라 총 재생수와 앨범의 정보(재생수 와 고유번호)가 필요했다. 
앨범의 고유번호는 plays 배열의 인덱스다. 고유번호만 있으면 앨범의 재생수는 plays[고유번호]로 알 수 있다.</p>
<p>따라서, value로 필요한 정보를 총재생수와 고유번호 리스트로 정했다. 
둘의 타입이 달라 Genre라는 클래스를만들었다. </p>
<p>Genre클래스는
장르별 총재생수를 누적할 수 있는 total 변수와
앨범의 고유번호를 담는 albumList 리스트로 구성했다.</p>
<p>아래와 같은 Map 구조로 문제를 풀었다.
<img src="https://images.velog.io/images/co_ol/post/2ead7132-e398-4b72-a477-b4a5cdaf3235/image.png" alt=""></p>
<br/>

<h3 id="💿📀-로직">💿📀 로직</h3>
<h4 id="입력데이터">입력데이터</h4>
<p>문제에 나와있는 기본 테스트케이스이다. </p>
<pre><code>genres : [&quot;classic&quot;, &quot;pop&quot;, &quot;classic&quot;, &quot;classic&quot;, &quot;pop&quot;]
plays  : [500, 600, 150, 800, 2500]</code></pre><br/>

<h4 id="1-입력-데이터를-map에-넣는다">1. 입력 데이터를 Map에 넣는다.</h4>
<p>→ 데이터가 장르별로 구분된다.
<img src="https://images.velog.io/images/co_ol/post/d75d88cd-b47a-428d-9eba-db5285fb8029/image.png" alt=""></p>
<h4 id="2-총재생수로-정렬">2. 총재생수로 정렬</h4>
<p>이제 장르명은 필요없다!
Map의 value값을 List<Genre>로 변환 후 
장르별 총재생수로 List를 정렬한다.
<del>사실 List로 변환하지 않고 Map 그대로 정렬하려고 했는데,  Map 정렬하는 코드가 좀 더러워서 간단하게 List로 변환하여 정렬하였다.</del>
<img src="https://images.velog.io/images/co_ol/post/b9ee1dde-8977-419a-aa9e-5a935414578e/image.png" alt=""></p>
<h4 id="3-마지막-장르별로-베스트-앨범-두개를-선정">3. 마지막, 장르별로 베스트 앨범 두개를 선정</h4>
<p>앨범별 재생수를 비교하기 위해 우선순위큐(PriorityQueue)에
고유번호와 재생수를 put해준 후 
베스트앨범 두개or한개를 poll해주면 답이 나온다.
<img src="https://images.velog.io/images/co_ol/post/07fcb58f-7ffa-4369-9ab6-c3d8446bddbf/image.png" alt="">답!!
<img src="https://images.velog.io/images/co_ol/post/38c4cf42-b691-45fb-b5db-72a11711de60/image.png" alt="">
  <br/><br/></p>
<h3 id="💿📀-코드">💿📀 코드</h3>
<pre><code class="language-java">public List&lt;Integer&gt; solution(String[] genres, int[] plays) {
    List&lt;Integer&gt; answer = new ArrayList&lt;Integer&gt;();

    Map&lt;String, Genre&gt; gMap = new HashMap&lt;&gt;();

    /* 1. map에 장르별로 데이터 추가 */
    for(int i=0; i&lt; genres.length ; i++) {        
        if(gMap.containsKey(genres[i])) {                
            Genre oriGen = gMap.get(genres[i]);
            oriGen.addGenre(plays[i], i);
            gMap.put(genres[i], oriGen);
        }
        else {
            gMap.put(genres[i], new Genre(plays[i], i));
        }
    }

    /* 2. 장르별 정렬 */
    List&lt;Genre&gt; gList = new ArrayList&lt;&gt;(gMap.values());
    //총재생수를 이용하여 비교
    gList.sort((o1, o2)-&gt; o2.getTotal() - o1.getTotal());

    /* 3. 장르별 베스트앨범 2개 선정 */
    for (Genre list : gList) {
        /* PriorityQueue 
         * 재생수 큰 순서대로 정렬 
         * 같을 경우 앨범고유번호 순으로  */
        PriorityQueue&lt;int[]&gt; q = new PriorityQueue&lt;&gt;((o1,o2) -&gt; {
            if(o2[1] - o1[1] == 0)
                return o1[0] - o2[0];
            else
                return o2[1] - o1[1];
        });
        // 큐에 모든 앨범 추가
        for(int i : list.getAlbumList()) {    
            int[] play = {i,plays[i]};
            q.offer(play);
        }

        // 상위 두개만 꺼낸다.
        answer.add(q.poll()[0]);
        if(!q.isEmpty())
            answer.add(q.poll()[0]);
    }

    return answer;
}

class Genre{
    int total = 0;    //총 재생 수
    List&lt;Integer&gt; albumList = new ArrayList&lt;&gt;();    //앨범 고유번호 리스트

    /**
     * 앨범 추가
     * - 재생수 누적, 앨범리스트 추가
     */
    public void addGenre(int total, int album) {
        this.total += total;
        this.albumList.add(album);
    }

    public Genre(int total, int album) {
        this.total += total;
        this.albumList.add(album);
    }

    // Getter, Setter 생략 //
}</code></pre>
<p>   <br/><br/></p>
<h3 id="💿📀-마무리">💿📀 마무리</h3>
<p>처음에 Map으로 풀어야되는건 알겠는데 구조 잡는데 헤맸다.</p>
<p>Map도 쓰고 List도 쓰고 Queue도 쓰고 너무 많이 쓴건가 싶기도하다.</p>
<p>더 간단하게 만들 수 있을것 같기도 하다. 담에 다시 풀어봐야지~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 - 단어변환(java)]]></title>
            <link>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8B%A8%EC%96%B4%EB%B3%80%ED%99%98java</link>
            <guid>https://velog.io/@co_ol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8B%A8%EC%96%B4%EB%B3%80%ED%99%98java</guid>
            <pubDate>Mon, 06 Sep 2021 08:42:23 GMT</pubDate>
            <description><![CDATA[<h3 id="📌문제">📌문제</h3>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/43163">📄 프로그래머스 - 단어변환문제</a></p>
<p>프로그래머스 DFS/BFS 카테고리에 있는 &quot;단어변환&quot;문제다.
DFS를 이용하여 풀었다.</p>
<br/>

<h3 id="📌로직">📌로직</h3>
<p>문제에 있는 테스트케이스로 그림을 한번 그려봤다.</p>
<p>주어진 words 리스트에 target문자열이 있는지 먼저 체크 한 후
target문자열이 있다면 아래 그림처럼 모든 경우의 수를 탐색한다. </p>
<p>begin 부터 시작해 변환 가능한 단어로 가지치기 하듯이 모든 경우를 모두 찾아 카운트를 한다.
가지치기(?) 한곳에서 카운트가 작은 쪽이 리턴된다. 
이 과정을 반복하여 최종적으로 모든 경우의 수 중 가장 작은 값이 리턴된다.</p>
<p><img src="https://images.velog.io/images/co_ol/post/d544fb52-5635-49aa-9ec2-eef71abd3b08/image.png" alt="hit에서 cog까지의 경우의 수"></p>
<p>정리하면</p>
<pre><code>1. words 에 target 있는지 확인
2. 단어변환 경로 탐색
2-1. target이 되었을때 RETURN (탈출조건)
2-2. 가능한 단어 체크 후 재귀(2번으로)
</code></pre><br/>

<h3 id="📌테스트케이스">📌테스트케이스</h3>
<h5 id="--begin-target-words--결과">- &quot;begin&quot;, &quot;target&quot;, words  //결과</h5>
<pre><code>- &quot;hit&quot;, &quot;cog&quot;, {&quot;hot&quot;, &quot;dot&quot;, &quot;dog&quot;, &quot;lot&quot;, &quot;log&quot;, &quot;cog&quot;}    //4
- &quot;hit&quot;, &quot;log&quot;, {&quot;hot&quot;, &quot;dot&quot;, &quot;dog&quot;, &quot;lot&quot;, &quot;log&quot;, &quot;cog&quot;}    //3
- &quot;hit&quot;, &quot;cog&quot;, {&quot;cog&quot;, &quot;log&quot;, &quot;lot&quot;, &quot;dog&quot;, &quot;dot&quot;, &quot;hot&quot;}    //4
- &quot;hit&quot;, &quot;cog&quot;, {&quot;hot&quot;, &quot;dot&quot;, &quot;dog&quot;, &quot;lot&quot;, &quot;log&quot;}        //0
- &quot;1234567000&quot;, &quot;1234567899&quot;, {&quot;1234567800&quot;, &quot;1234567890&quot;, &quot;1234567899&quot;}//3</code></pre><br/>

<h3 id="📌코드">📌코드</h3>
<pre><code class="language-java">public int solution(String begin, String target, String[] words) {
    int n = words.length;

    /* 1. words 에 target 있는지 확인*/
    int index = -1;
    for(int i = 0 ; i &lt; n ; i++) {
        if(words[i].equals(target)) index = i;
    }
    if(index&lt; 0) {
        return 0;
    }
    /* 2. 단어변환 경로 탐색 */
    boolean[] chk = new boolean[n];
    return dfs(begin, target, -1, words, chk, 0);
}

/**
 * 단어변환의 모든 경로 탐색 최저 카운트 수 반환
 */
public int dfs(String begin, String target, int idx, String[] words, boolean[] chk , int cnt) {        
    /* target이 되었을때 RETURN (탈출조건) */
    if(target.equals(begin)) {
        return cnt;
    }

    /* 방문체크, 카운트 */
    if(idx &gt;= 0) chk[idx] = true;
    cnt++;

    /* 가능한 단어 체크 후 재귀 */
    int answer = chk.length;
    for(int i=0 ; i&lt;chk.length ; i++) {            
        if(!chk[i]) {
            if(wordCheck(begin.toCharArray(), words[i].toCharArray())) {
                answer = Math.min(answer, dfs(words[i], target, i, words, chk, cnt));
                chk[i] = false;
            }
        }
    }
    return answer;
}

/**
 * 가능한 단어인지 체크 
 */
public boolean wordCheck(char[] begin, char[] target) {
    /* 한글자만 다른지 체크 */
    int cnt = 0;
    for(int j=0 ; j&lt;begin.length ; j++) {
        if(begin[j] != target[j])
            cnt ++;
    }
    return (cnt ==1) ? true : false;
}</code></pre>
<br/>

<h3 id="📌마무리">📌마무리</h3>
<p>재귀 로직을 생각하느라 좀 헤맸다. 아직 재귀 문제를 풀면 뫼비우스 띠에 빠지는 느낌이다..</p>
<p>dfs 메서드에 파라미터가 너무 주렁주렁 달려있어서 줄이고 싶은데 일단 저게 최선이다😥</p>
<p>아직 BFS 알고리즘은 뭔지, DFS/BFS 중 뭘 이용해야 효율적인지 모르겠다. 다음엔 BFS 공부해서 DFS/BFS 알고리즘을 한번 정리 해봐야겠다!</p>
]]></description>
        </item>
    </channel>
</rss>