<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>seungg-0.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 19 Jun 2023 14:56:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>seungg-0.log</title>
            <url>https://velog.velcdn.com/images/seungg-0/profile/e5c14444-4f02-4f51-aaff-1b043d53117a/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. seungg-0.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/seungg-0" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[알고리즘] 그리디_체육복 ]]></title>
            <link>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B7%B8%EB%A6%AC%EB%94%94%EC%B2%B4%EC%9C%A1%EB%B3%B5</link>
            <guid>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B7%B8%EB%A6%AC%EB%94%94%EC%B2%B4%EC%9C%A1%EB%B3%B5</guid>
            <pubDate>Mon, 19 Jun 2023 14:56:27 GMT</pubDate>
            <description><![CDATA[<h3 id="💡-강의-참고-전-코드-성공">💡 강의 참고 전 코드 (성공)</h3>
<pre><code class="language-python">def solution(n, lost, reserve):
    answer = 0
    lost.sort()
    reserve.sort()

    # 1. 여벌 가져온 학생 중 도난당한 학생 체크
    reserve_list = []
    for i in reserve: # for문 안에 remove 함수 있으면 시간복잡도 N^2....
        if i in lost:
            lost.remove(i)
            continue
        else:
            reserve_list.append(i)

    # 2. 체육복 유무 알 수 있는 having 
    having = [True for _ in range(n+1)]

    for i in lost:
        having[i] = False

    for i in reserve_list:
        if i == 1:
            if having[i+1] == False:
                having[i+1] = True
        elif i == n:
            if having[i-1] == False:
                having[i-1] = True
        else:
            if having[i-1] == False:
                having[i-1] = True
            elif having[i+1] == False:
                having[i+1] = True

    having[0] = False
    answer = having.count(True)

    return answer</code></pre>
<blockquote>
<p>통과는 했지만 코드가 매우 길고, for문 안에 remove 함수가 있어 시간복잡도가 O(N^2)이 나온다.</p>
</blockquote>
<h3 id="💡-강사님-풀이">💡 강사님 풀이</h3>
<p>우선 이 문제는 그리디 알고리즘을 이용해서 푸는 문제이다.
<code>그리디</code> : 현재의 선택이 마지막 해답의 최적성을 해치지 않을 때 사용</p>
<pre><code class="language-python">def solution(n, lost, reserve):
    u = [1] * (n + 2) # 체육복 정보 (편의성을 위해 앞, 뒤 체육복을 가진 학생 추가)
    for i in reserve:
        u[i] += 1 # 여벌 가져온 학생 체육복 하나씩 더 추가
    for i in lost:
        u[i] -= 1
    for i in range(1, n+1):
        if u[i-1] == 0 and u[i] == 2: # 앞의 사람 빌려야 하는 입장이고 내가 빌려줄 수 있으면
            u[i-1:i+1] = [1, 1] # 체육복을 빌려준다.
        elif u[i] == 2 and u[i+1] == 0: # 아니면 뒷사람 체크
            u[i:i+2] = [1, 1] # 뒷사람에게 체육복을 빌려준다.
    return len([x for x in u[1:-1] if x &gt; 0])</code></pre>
<blockquote>
<p>초기 값을 모두 1로 둔 후에, 여벌체육복이 있으면 +1, 잃어버렸으면 -1을 해준다. 그리고 앞, 뒤 순서로 체크하면서 현재 위치의 학생이 여벌이 있고, 앞, 뒤의 학생이 체육복이 없는 경우 체육복을 빌려주는 방식으로 for문을 돌린다. (각 상황에서의 선택이 마지막 해답의 최적성을 해치지 않음)
이렇게 하면 시간복잡도는 O(N)이 된다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 해시_방울 python]]></title>
            <link>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%95%B4%EC%8B%9C%EB%B0%A9%EC%9A%B8-python</link>
            <guid>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%95%B4%EC%8B%9C%EB%B0%A9%EC%9A%B8-python</guid>
            <pubDate>Mon, 19 Jun 2023 10:21:45 GMT</pubDate>
            <description><![CDATA[<h3 id="💡-풀이-참고-전-코드-실패">💡 풀이 참고 전 코드 (실패)</h3>
<pre><code class="language-python">def solution(bell):
    answer = 0
    accumulate_bell = [0]
    for i in range(len(bell)):
        if bell[i] == 1:
            accumulate_bell.append(accumulate_bell[i+1-1]+1)
        else:
            accumulate_bell.append(accumulate_bell[i+1-1]-1)
    s, e = 0, 2
    while s &lt; len(accumulate_bell) and e &lt; len(accumulate_bell):
        if accumulate_bell[s] == accumulate_bell[e]:
            answer = max(answer, e-s)
            e += 1
        else:
            e += 1
        if e &gt;= len(accumulate_bell) and s &lt; e-2:
                s += 1
                e = (s + 2)
    return answer</code></pre>
<blockquote>
<p>사실 처음엔 아이디어도 떠올리기 어려웠다. 강의에서 제시한 아이디어 (초록방울일 경우 1, 빨간방울일 경우 -1을 해서 누적값이 같아질 떄의 최대 길이 구하기) 를 참고하고 짜봤지만, bell의 최대 길이가 1,000,000이라 테스트케이스 말곤 모두 시간초과가 났다.
while문 안에서 e, s의 값을 변경해서 시간초과가 난 것 같다.</p>
</blockquote>
<h3 id="💡-강사님-풀이">💡 강사님 풀이</h3>
<pre><code class="language-python">from itertools import accumulate

def solution(bell):
    coors_start = {}
    coors_end = {}
    for i, x in enumerate(accumulate([0] + [-1 if b == 1 else 1 for b in bell])):
        if x not in coors_start:
            coors_start[x] = i
        coors_end[x] = i
    return max(coors_end[x] - coors_start[x] for x in coors_end)</code></pre>
<ul>
<li>먼저 itertools의 accumulate 사용법을 알아야 할 것 같다.<pre><code class="language-python">from itertools import accumulate
</code></pre>
</li>
</ul>
<p>a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = list(accumulate(a))
print(a)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(b)  # [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]</p>
<p>```</p>
<ul>
<li>accumulate는 <code>누적합</code>을 뽑아준다.</li>
</ul>
<blockquote>
<p>같은 수의 길이를 구해주는 부분에서 시간초과를 해결하지 못했는데 강사님 풀이에선 이를 딕셔너리를 활용해서 풀었다.
start와 end 딕셔너리를 각각 만들어주고, start 딕셔너리는 초기 key값 한 번만, end 딕셔너리는 같은 key값이 나오면 업데이트 해준다.
key는 실제 누적 값이고, value는 인덱스 이다.
(최대 길이를 구하는 것이기 때문에 start는 가장 앞의 수, end는 가장 뒤의 수를 찾아야 하기 때문)</p>
</blockquote>
<ul>
<li>처음엔 for문 안에서 <code>if x not in coors_start:</code> 부분이 for문 안에 있어 O(N)보다 큰 시간복잡도를 가질 것이라 생각했지만, 아니었다. 딕셔너리의 key값을 찾는 연산(in)은 평균적으로 상수 시간에 수행된다.</li>
</ul>
<h3 id="✔️-배운점">✔️ 배운점</h3>
<p>1️⃣ itertools의 accumulate로 누적합을 구할 수 있다.</p>
<p>2️⃣ 딕셔너리 내부에서 키의 존재 여부를 확인하는 연산(in 연산자)은 <code>해시 테이블</code>을 이용하여 평균적으로 <code>상수 시간</code>에 수행된다. (앞으로 리스트에서 같은 숫자의 인덱스를 찾을 땐 해시 테이블, 즉 딕셔너리 자료구조를 사용해보자!⭐️)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 해시_완주하지 못한 선수 Python]]></title>
            <link>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%95%B4%EC%8B%9C%EC%99%84%EC%A3%BC%ED%95%98%EC%A7%80-%EB%AA%BB%ED%95%9C-%EC%84%A0%EC%88%98-Python</link>
            <guid>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%95%B4%EC%8B%9C%EC%99%84%EC%A3%BC%ED%95%98%EC%A7%80-%EB%AA%BB%ED%95%9C-%EC%84%A0%EC%88%98-Python</guid>
            <pubDate>Mon, 19 Jun 2023 09:22:12 GMT</pubDate>
            <description><![CDATA[<h3 id="💡-강의-참고-전-코드-성공">💡 강의 참고 전 코드 (성공)</h3>
<pre><code class="language-python">def solution(participant, completion):
    answer = &#39;&#39;

    participant.sort()
    completion.sort()

    for i in range(len(completion)):
        if participant[i] != completion[i]:
            answer = participant[i]
            break
    if answer == &#39;&#39;:
        answer = participant[-1]

    return answer</code></pre>
<blockquote>
<p>통과는 했지만, 문제의 의도인 해쉬를 사용하지 않았다.
sort() 함수를 사용했기 때문에 시간복잡도는 O(NlogN)</p>
</blockquote>
<h3 id="💡-강의-참고-후-코드">💡 강의 참고 후 코드</h3>
<pre><code class="language-python">def solution(participant, completion):
    answer = &#39;&#39;

    participant_dict = {}
    completion_dict = {}
    for x in participant:
        participant_dict[x] = participant_dict.get(x, 0) + 1
    for x in completion:
        completion_dict[x] = completion_dict.get(x, 0) + 1

    for key, value in completion_dict.items():
        participant_dict[key] -= value

    answer = [key for key, value in participant_dict.items() if value &gt; 0]

    return &#39;&#39;.join(answer)</code></pre>
<blockquote>
<p>시간 복잡도 O(N)이 된다.</p>
</blockquote>
<h3 id="✔️-새로-알게된-함수">✔️ 새로 알게된 함수</h3>
<p>1️⃣ <code>get(x, 0)</code> -&gt; x라는 key가 없을 때 0 반환, 있으면 해당 value 반환
2️⃣ <code>answer = [key for key, value in participant_dict.items() if value &gt; 0]</code> 형태로 작성 가능</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 투 포인터_티셔츠 Python]]></title>
            <link>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%88%AC%ED%8F%AC%EC%9D%B8%ED%84%B0%ED%8B%B0%EC%85%94%EC%B8%A0-Python</link>
            <guid>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%88%AC%ED%8F%AC%EC%9D%B8%ED%84%B0%ED%8B%B0%EC%85%94%EC%B8%A0-Python</guid>
            <pubDate>Sun, 18 Jun 2023 07:54:52 GMT</pubDate>
            <description><![CDATA[<h3 id="💡-강의-참고-전-코드-성공">💡 강의 참고 전 코드 (성공)</h3>
<pre><code class="language-python"># 자신의 상의 크기와 같거나 큰 티셔츠를 받는다.

# people 하나씩 탐색하면서 같거나 큰 티셔츠 찾음
# 이중 for문 N^2 -&gt; 5,000*5,000 = 25,000,000 
from collections import deque

def solution(people, tshirts):
    answer = 0
    # people과 tshirts 모두 오름차순 정렬
    people_dq = deque(sorted(people))
    tshirts_dq = deque(sorted(tshirts))

    while (people_dq):
        person = people_dq.popleft()
        while (tshirts_dq):
            tshirt = tshirts_dq.popleft()
            if person &lt;= tshirt: # 같거나 큰 티셔츠 찾을 때까지 반복
                answer += 1
                break

    return answer</code></pre>
<h3 id="💡-문제-설명-및-강사님-풀이">💡 문제 설명 및 강사님 풀이</h3>
<pre><code class="language-python">def solution(people, tshirts):
    people.sort()
    tshirts.sort()
    p, t, ans = 0, 0, 0
    while p &lt; len(people) and t &lt; len(tshirts):
        if tshirts[t] &gt;= people[p]:
            ans += 1
            p += 1
        t += 1
    return ans</code></pre>
<blockquote>
<h4 id="후기">후기</h4>
<p>나는 deque 자료형을 이용해서 풀었는데, 이렇게 투포인터를 사용하면 코드가 훨씬 간결해진다.
두 리스트를 탐색하며 비교할 땐 투 포인터 알고리즘을 사용해보자.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 투 포인터_상담예약제 Python]]></title>
            <link>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BD%94%EC%8A%A419%ED%9A%8C%EC%B0%A8-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%8B%A4%EB%A0%A5-UP-%EC%83%81%EB%8B%B4%EC%98%88%EC%95%BD%EC%A0%9C</link>
            <guid>https://velog.io/@seungg-0/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BD%94%EC%8A%A419%ED%9A%8C%EC%B0%A8-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%8B%A4%EB%A0%A5-UP-%EC%83%81%EB%8B%B4%EC%98%88%EC%95%BD%EC%A0%9C</guid>
            <pubDate>Sun, 18 Jun 2023 07:44:52 GMT</pubDate>
            <description><![CDATA[<h3 id="💡-강의-참고-전-코드-실패">💡 강의 참고 전 코드 (실패)</h3>
<pre><code class="language-python"># 업무 처리시간 10분

# (1) 현재 시각보다 앞선 시각의 고객 중 업무 시작하는데, 예약고객 우선 시작
# (2) 10분 더했을 때 (1)번 반복

# 시간 : 기준으로 자르기, 분 기준으로 변환, 시간 기준으로 sort
# booked 먼저 탐색, unbooked 그 다음에 탐색
from collections import deque
def solution(booked, unbooked):
    answer = []
    for idx, value in enumerate(booked):
        time, name = value
        h, m = time.split(&quot;:&quot;)
        mins = 60*int(h) + int(m)
        booked[idx] = [mins, name]
    for idx, value in enumerate(unbooked):
        time, name = value
        h, m = time.split(&quot;:&quot;)
        mins = 60*int(h) + int(m)
        unbooked[idx] = [mins, name]

    booked_dq = deque(sorted(booked, key = lambda x:x[0]))
    unbooked_dq = deque(sorted(unbooked, key = lambda x:x[0]))

    now = 1440
    while (True):
        if len(booked_dq) &gt; 0:
            booked = booked_dq.popleft()
        else:
            booked = False
        while (unbooked_dq):
            unbooked = unbooked_dq.popleft()
            if (now == 1440 and unbooked[0] &lt; booked[0]) or (now != 1440 and unbooked[0] &lt;= now and unbooked[0] &gt;= now) or not booked:
                # unbooked 먼저
                answer.append(unbooked[1])
                if now == 1440:
                    now = (unbooked[0]+10)
                else:
                    now += 10
                booked_dq.appendleft(booked)
            else:
                # booked 먼저
                answer.append(booked[1])
                if now == 1440:
                    now = (booked[0]+10)
                else:
                    now += 10
                unbooked_dq.appendleft(unbooked)
            break
        if len(booked_dq) == 0 and len(unbooked_dq) == 0:
            break


    return answer

</code></pre>
<h3 id="💡-강사님-풀이">💡 강사님 풀이</h3>
<pre><code class="language-python">def parse_time(t):
    h, m = map(int, t.split(&#39;:&#39;))
    return 60*h + m

def solution(booked, unbooked):

    booked = [(parse_time(t), name) for t, name in booked] + [(1000000, None)]
    unbooked = [(parse_time(t), name) for t, name in unbooked] + [(1000000, None)]
    booked.sort()
    unbooked.sort()
    b, u, t, answer = 0, 0, 0, []

    while b &lt; len(booked) and u &lt; len(unbooked):

        t1, t2 = booked[b][0], unbooked[u][0]
        if t1 &lt;= t:
            answer.append(booked[b][1])
            b += 1
            t += 10
        elif t2 &lt;= t:
            answer.append(unbooked[u][1])
            u += 1
            t += 10
        else:
            t = min(t1, t2)

    answer.pop()
    return answer</code></pre>
<blockquote>
<h3 id="후기">후기</h3>
<p>풀이가 굉장히 단순하다.
시간을 적절한 숫자로 바꿔주는 부분은 동일하다.
다만 초기 규칙을 단순하게 생각하지 못했다.</p>
</blockquote>
<h3 id="✔️-실수한-점">✔️ 실수한 점</h3>
<p>1️⃣ 반복문에 사용할 자료형</p>
<ul>
<li>나는 deque를 사용했는데 deque를 사용하게 되면 booked unbooked 두가지 중 answer에 추가하지 않은 것을 다시 appendleft 해줘야 하는 문제가 생긴다.</li>
<li>여기선 자료형의 길이로 반복문을 돌리는 방식으로 사용했다.</li>
</ul>
<p>2️⃣ 초기 시간 설정</p>
<ul>
<li>나는 초기 시간을 1440으로 설정했는데, 그럴 필요가 없었다.</li>
</ul>
<h3 id="✔️-배운-점">✔️ 배운 점</h3>
<ul>
<li>특정 자료형을 사용할 때는 그 자료형을 쓰는게 좋을지 다른 자료형을 쓰는게 좋을지 먼저 고민해야 한다.</li>
<li>코드를 짜기 전에 풀이 로직을 정리하는데 더 시간을 쓰자.</li>
<li>코드가 길어지고 복잡해질 것 같으면 함수로 뺴자</li>
<li>강사님 코드의 while문 구조 기억하고 나중에 써먹자 !</li>
<li>예외처리 해주기 전에 더미데이터를 추가해서 해결할 수 있는지 확인</li>
<li><code>문법</code> booked = [[parse_time(time), value] for time, value in booked] + [[10000, &#39;dummy&#39;]] 리스트끼리 더할 떄는 각각 동등한 자료형끼리 더해야 한다 (ex. 이중 리스트 + 이중 리스트)</li>
</ul>
<h3 id="💡-강의-참고-후-코드">💡 강의 참고 후 코드</h3>
<pre><code class="language-python">
def parse_time(time):
    h, m = time.split(&quot;:&quot;)
    return (60*int(h) + int(m))

def solution(booked, unbooked):
    b, u, t, answer = 0, 0, 0, []
    booked = [[parse_time(time), value] for time, value in booked] + [[10000, &#39;dummy&#39;]]
    unbooked = [[parse_time(time), value] for time, value in unbooked] + [[10000, &#39;dummy&#39;]]
    booked.sort()
    unbooked.sort()

    while b&lt;len(booked) and u&lt;len(unbooked):
        bt, ut = booked[b][0], unbooked[u][0]
        if bt &lt;= t: # 대기중인 손님 중 예약한 손님 우선으로 처리
            answer.append(booked[b][1])
            b += 1
            t += 10
        elif ut &lt;= t:
            answer.append(unbooked[u][1])
            u += 1
            t += 10
        else: # 현재 시점에서 대기중인 손님이 없는 경우
            t = min(bt, ut) # 현재 시간 이후로 올 손님 중 가장 빨리 올 손님 시간으로 설정

    answer.pop()
    return answer</code></pre>
<blockquote>
<p>더미데이터를 추가해주는 부분은 나중에도 스스로 떠올릴 수 있을지 모르겠다.
잘 쓴 코드들 많이 참고하면서 공부하기 ✔️</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] JPA란 ?]]></title>
            <link>https://velog.io/@seungg-0/JPA-JPA%EB%9E%80</link>
            <guid>https://velog.io/@seungg-0/JPA-JPA%EB%9E%80</guid>
            <pubDate>Sat, 17 Jun 2023 15:28:56 GMT</pubDate>
            <description><![CDATA[<h2 id="jpa-java-persistence-api">JPA (Java Persistence API)</h2>
<ul>
<li>자바 진영의 <strong>ORM</strong> 기술 표준으로, <strong>인터페이스의 모음</strong></li>
<li>JPA 인터페이스를 구현한 대표적인 오픈소스가 Hibernate
<img src="https://velog.velcdn.com/images/seungg-0/post/08b8a0cc-271b-4417-a53d-2af6d3679260/image.png" alt=""></li>
</ul>
<h3 id="💡-orm-object-relational-mapping">💡 ORM (Object-relational mapping)</h3>
<blockquote>
<p>객체 관계 매핑
-&gt;객체는 객체대로 설계하고, 관계형 데이터베이스는 관계형 데이터베이스대로 설계한다
ORM프레임워크가 중간에서 매핑해준다.</p>
</blockquote>
<h3 id="📍-jpa의-동작-과정">📍 JPA의 동작 과정</h3>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/8c369766-d146-43e3-bca3-994f71a53d5b/image.png" alt=""></p>
<ul>
<li>JPA는 애플리케이션과 JDBC 사이에서 동작한다.<ul>
<li>개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용해 SQL을 호출하여 DB와 통신한다.</li>
<li>개발자가 직업 JDBC API를 쓰는 것이 아니다.</li>
</ul>
</li>
</ul>
<h4 id="저장-과정">저장 과정</h4>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/34e1b0f4-28d7-4650-b0f2-deef2d4e7929/image.png" alt=""></p>
<p>EX) MemerDAO에서 객체를 저장하고 싶을 때</p>
<ul>
<li>개발자는 JPA에 Member 객체를 넘긴다.</li>
<li>JPA는<ul>
<li>1) Member엔티티를 분석</li>
<li>2) INSERT SQL 생성</li>
<li>3) JDBC API를 사용해 SQL을 DB에 날린다.</li>
</ul>
</li>
</ul>
<h4 id="조회-과정">조회 과정</h4>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/36636777-b32a-4468-a95b-23e408229379/image.png" alt=""></p>
<ul>
<li><p>EX) MemerDAO 객체를 조회하고 싶을 때</p>
<ul>
<li>개발자는 member의 pk값을 JPA에 넘긴다.</li>
<li>JPA는</li>
<li>1) 엔티티의 매핑 정보를 바탕으로 적절한 SELECT SQL을 생성</li>
<li>2) JDBC API를 사용해 SQL을 DB에 날린다.</li>
<li>3) DB로부터 결과를 받아온다.</li>
<li>4) 결과(ResultSet)를 객체에 모두 매핑한다.</li>
</ul>
</li>
<li><p>쿼리를 JPA가 만들어 주기 때문에 Object와 RDB간의 <strong>패러다임 불일치</strong>를 해결할 수 있다.</p>
</li>
</ul>
<blockquote>
<p>*<em>패러다임 불일치란 ? *</em>💡<br>
<u>db는 철저히 데이터 중심으로 설계</u>되어 있으며 객체와 db는 목적이 다르다. 
패러다임의 불일치는 이렇게 <u>객체(OOP)와 관계형 DB의 데이터 표현방식과 다루는 방법이 달라 일어나는 현상</u>이다.
객체와 db 양쪽의 불일치를 해결해줘야 한다. 그렇지 않다면, db에 의존적이게 코딩을 하게 될 수 밖에 없다.</p>
</blockquote>
<h3 id="🤔-jpa를-왜-사용해야-할까">🤔 JPA를 왜 사용해야 할까?</h3>
<h4 id="1-sql-중심적인-개발에서-객체-중심으로-개발">1. SQL 중심적인 개발에서 객체 중심으로 개발</h4>
<ul>
<li><a href="https://gmlwjd9405.github.io/2019/08/03/reason-why-use-jpa.html">SQL중심적인 개발의 문제점</a></li>
</ul>
<h4 id="2-생산성">2. 생산성</h4>
<ul>
<li>간단한 CRUD<ul>
<li><code>저장</code> : jpa.persist(member)</li>
<li><code>조회</code> : Member member = jpa.find(memberId)</li>
<li><code>수정</code> : member.setName(&quot;변경할 이름&quot;)</li>
<li><code>삭제</code> : jpa.ermove(member) <br>    </li>
</ul>
</li>
<li>수정시엔 객체를 변경하면 자동으로 DB에 UPDATE Query가 나간다.</li>
</ul>
<h4 id="3-유지보수">3. 유지보수</h4>
<ul>
<li>기존 : 필드 변경 시 모든 SQL 수정 필요</li>
<li>JPA : 필드만 추가하면 JPA가 SQL을 처리해줌</li>
</ul>
<br/>

<p><strong>참고 자료</strong></p>
<p><a href="https://gmlwjd9405.github.io/2019/08/04/what-is-jpa.html">https://gmlwjd9405.github.io/2019/08/04/what-is-jpa.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java 미니 기술세미나  Exception]]></title>
            <link>https://velog.io/@seungg-0/Java-%EB%AF%B8%EB%8B%88-%EA%B8%B0%EC%88%A0%EC%84%B8%EB%AF%B8%EB%82%98-Exception</link>
            <guid>https://velog.io/@seungg-0/Java-%EB%AF%B8%EB%8B%88-%EA%B8%B0%EC%88%A0%EC%84%B8%EB%AF%B8%EB%82%98-Exception</guid>
            <pubDate>Wed, 14 Jun 2023 08:45:44 GMT</pubDate>
            <description><![CDATA[<h2 id="error-exception-차이-💡">Error, Exception 차이 💡</h2>
<h3 id="error-오류">Error (오류)</h3>
<ul>
<li>프로그램에서 복구할 수 없는 시스템 수준의 심각한 문제를 의미 (주로 자바 가상머신에서 발생시키는 것)</li>
<li>개발자가 미리 예측하여 방지할 수 없음 (로직 수정으로 처리할 수 없음)</li>
</ul>
<pre><code>ex) OutOfMemoryError, ThreadDeath, StackOverflowError 등</code></pre><h3 id="exception-예외">Exception (예외)</h3>
<ul>
<li>개발자가 구현한 로직에서 실수가 발생하거나, 사용자 영향에 의해 발생</li>
<li>개발자가 미리 예측하여 방지할 수 있음 (상황에 맞는 예외처리 필요)</li>
</ul>
<br>

<h2 id="java-예외의-종류">Java 예외의 종류</h2>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/4a960612-261d-44a9-9664-a161cdb32a5b/image.png" alt=""></p>
<blockquote>
<p>상속 관계가 이렇게 되어 있는 이유는 <strong>Exception이나 Error의 성격은 다르지만, 모두 동일한 이름의 메소드를 사용하여 처리할 수 있도록 하기 위함</strong>
<br></p>
</blockquote>
<h3 id="1-checked-exception-일반-예외">1. checked exception (일반 예외)</h3>
<blockquote>
<p>컴파일러가 해당 예외를 확인하고 처리 여부를 강제하는 예외</p>
</blockquote>
<ul>
<li>처리를 해주지 않으면 런타임 전에 에러가 발생한다. (실행 불가) ⬇️
<img src="https://velog.velcdn.com/images/seungg-0/post/33dd3a4f-a814-4e8e-9527-a7dff16a3909/image.png" alt=""></li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>Checked Exception 종류</th>
</tr>
</thead>
<tbody><tr>
<td>IOException</td>
<td>입출력 작업 중에 발생하는 예외 (파일을 읽거나 쓸 때 발생)</td>
</tr>
<tr>
<td>SQLException</td>
<td>데이터베이스 작업 중에 발생하는 예외 (데이터베이스 연결, 쿼리 실행, 트랜잭션 등)</td>
</tr>
</tbody></table>
<br>

<h3 id="2-unchecked-exception-실행-예외">2. unchecked exception (실행 예외)</h3>
<blockquote>
<p>컴파일러가 해당 예외를 확인하지 않고 예외 처리를 강제하지 않는 예외
RuntimeException을 상속한 클래스</p>
</blockquote>
<ul>
<li>처리 안해줘도 실행 되지만, 런타임에서 에러 발생</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>Unchecked Exception 종류</th>
</tr>
</thead>
<tbody><tr>
<td>NullPointerException</td>
<td>null 값을 갖는 참조 변수로 객체 접근 연산자인 도트(.)를 사용했을 때 발생</td>
</tr>
<tr>
<td>ArrayIndexOutOfBoundsException</td>
<td>배열에서 인덱스 범위를 초과하여 사용할 때 발생</td>
</tr>
<tr>
<td>NumberFormatException</td>
<td>숫자로 변환할 수 없는 문자열을 숫자로 변경할 때 발생</td>
</tr>
<tr>
<td>ClassCastException</td>
<td>허용되지 않는데 억지로 타입 변환을 시도할 경우 발생 (ex. 부모 클래스를 자식 클래스로 타입 변환 시도)</td>
</tr>
<tr>
<td>IllegalArgumentException</td>
<td>적합하지 않거나(illegal) 적절하지 못한(inappropriate) 인자를 메소드에 넘겨주었을 때 발생</td>
</tr>
<tr>
<td>ArithmeticException</td>
<td>예외적인 산술 조건이 발생했을 때 (ex. 0으로 나누기)</td>
</tr>
</tbody></table>
<br>

<h3 id="throwable-클래스에-선언-exception-클래스에서-오버로딩한-메소드">Throwable 클래스에 선언, Exception 클래스에서 오버로딩한 메소드</h3>
<h4 id="1-getmessage">1. getMessage()</h4>
<p><strong>예외 메시지를 String 형태로 제공</strong>받는다. 예외가 출력되었을 때 <strong>어떤 예외가 발생되었는지를 확인할 때 매우 유용</strong>하다. 즉, 그 메시지를 활용하여 별도의 예외 메시지를 사용자에게 보여주려고 할 때 좋다.</p>
<h4 id="2-tostring">2. toString()</h4>
<p><strong>예외 메시지를 String 형태로 제공</strong>받는다. 그런데, getMessage() 메소드보다는 <strong>약간 더 자세하게, 예외 클래스 이름도 같이 제공</strong>한다.</p>
<h4 id="3-printstacktrace">3. printStackTrace()</h4>
<p>가장 첫 줄에는 <strong>예외 메시지</strong>를 출력하고, 두 번째 줄부터는 <strong>예외가 발생하게 된 메소드들의 호출 관계(스택 트레이스)를 출력</strong>해준다.</p>
<br>

<h2 id="exception-처리-방법">Exception 처리 방법</h2>
<p><strong>try :</strong> 예외 발생 가능성이 있는 로직이 포함된 블럭
<strong>catch :</strong> 예외가 발생했을 때 처리되는 로직이 포함된 블럭
<strong>finally :</strong> 예외가 발생하던 안하던 최종적으로 처리되는 로직이 포함된 블럭</p>
<p>[예외에 대한 책임 전가]</p>
<p>📍 *<em>throw *</em> </p>
<ul>
<li>예외를 강제로 발생시킨 후, 상위 블럭이나 catch문으로 예외를 던진다.</li>
<li>즉, 예외를 발생시키는데 사용<pre><code class="language-java"></code></pre>
</li>
</ul>
<p>public void divide(int num1, int num2) {
    if (num2 == 0) {
        throw new ArithmeticException(&quot;Divide by zero error&quot;);
    }
    int result = num1 / num2;
    System.out.println(&quot;Result: &quot; + result);
}</p>
<pre><code>
📍 **throws **
- 예외가 발생할 수 있는 메서드에서 해당 예외를 호출자에게 전달하는 데 사용
- 예외를 직접 처리하지 않고, 호출자에게 예외 처리 책임을 넘기는 방식
- Throws를 던지면 해당 코드를 사용하는 쪽에서 try catch 요구를 받게 된다.

```java

import java.io.IOException;

public class FileReader {

    public void readFile() throws IOException {
        // 파일을 읽는 작업
        // IOException이 발생할 수 있음
    }

    public static void main(String[] args) {
        FileReader reader = new FileReader();
        try {
            reader.readFile();
        } catch (IOException e) {
            System.out.println(&quot;파일 읽기 오류: &quot; + e.getMessage());
        }
    }
}
</code></pre><br>

<h3 id="1-예외-복구">1. 예외 복구</h3>
<ul>
<li>예외 상황을 파악하고 문제를 해결해 정상 상태로 돌려놓는 방법</li>
<li>예외를 잡아서 일정 시간, 조건만큼 대기하고 다시 재시도를 반복</li>
<li>최대 재시도 횟수를 넘기게 되는 경우 예외 발생시킴</li>
</ul>
<pre><code class="language-java">
final int MAX_RETRY = 100;
public Object someMethod() {
    int maxRetry = MAX_RETRY;
    while(maxRetry &gt; 0) {
        try {
            ...
        } catch(SomeException e) {
            // 로그 출력. 정해진 시간만큼 대기한다.
        } finally {
            // 리소스 반납 및 정리 작업
        }
    }
    // 최대 재시도 횟수를 넘기면 직접 예외를 발생시킨다.
    throw new RetryFailedException();
}

</code></pre>
<br>

<h3 id="2-예외처리-회피">2. 예외처리 회피</h3>
<ul>
<li>예외 처리를 직접 담당하지 않고 호출한 쪽으로 던져 회피하는 방법</li>
<li>긴밀하게 역할을 분담하고 있는 관계가 아니라면 예외를 그냥 던지는 것은 무책임하다.</li>
</ul>
<pre><code class="language-java">
public void method1(){
 try {
   method2(); // throws가 붙은 method2는 반드시 이렇게 try문 안에서 호출되어야 함. 
   // method2가 떠넘긴 예외를 아래 catch문을 통해 처리
}
 catch (ClassNotFoundException e1) {
  System.out.println(&quot;클래스가 존재하지 않습니다.&quot;);
}

public void method2() throws ClassNotFoundException {
 Class class = Class.forName(&quot;java.lang.String22&quot;);
}</code></pre>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/4790e749-0f72-4ca6-9274-ae8685f161b8/image.png" alt=""></p>
<br>

<h3 id="3-예외-전환">3. 예외 전환</h3>
<ul>
<li>회피와 비슷하게 메서드 밖으로 예외 던지지만, 그냥 던지지 않고 적절한 예외로 전환해서 넘기는 방법</li>
<li>더 명확한 의미로 전달하기 위해 적합한 의미를 가진 예외로 변경</li>
<li>예외 처리를 단순하게 만들기 위해 포장(wrap)할 수도 있음</li>
</ul>
<pre><code class="language-java">
// 조금 더 명확한 예외로 던진다.
public void add(User user) throws DuplicateUserIdException, SQLException {
    try {
        // ...생략
    } catch(SQLException e) {
        if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
            throw DuplicateUserIdException();
        }
        else throw e;
    }
}

// 예외를 단순하게 포장한다.
public void someMethod() {
    try {
        // ...생략
    }
    catch(NamingException ne) {
        throw new EJBException(ne);
        }
    catch(SQLException se) {
        throw new EJBException(se);
        }
    catch(RemoteException re) {
        throw new EJBException(re);
        }
}
</code></pre>
<br>

<blockquote>
<p>서버쪽 시스템 <strong>오류를 메세지로 사용자에게</strong> 보여주게 되면, 심각한 <strong>보안적인 사고</strong>를 초래할 수 있다. 따라서 에러메세지를 사용자에게 보내주면 안될 때 오류를 파일 형식으로 저장할 수 있는 <strong>로깅 시스템</strong>을 사용한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ-BFS] 18405 경쟁적 전염 Python]]></title>
            <link>https://velog.io/@seungg-0/BOJ-BFS-18405-%EA%B2%BD%EC%9F%81%EC%A0%81-%EC%A0%84%EC%97%BC-Python</link>
            <guid>https://velog.io/@seungg-0/BOJ-BFS-18405-%EA%B2%BD%EC%9F%81%EC%A0%81-%EC%A0%84%EC%97%BC-Python</guid>
            <pubDate>Thu, 25 May 2023 10:24:37 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/18405">https://www.acmicpc.net/problem/18405</a></p>
<h3 id="문제">문제</h3>
<p>NxN 크기의 시험관이 있다. 시험관은 1x1 크기의 칸으로 나누어지며, 특정한 위치에는 바이러스가 존재할 수 있다. 모든 바이러스는 1번부터 K번까지의 바이러스 종류 중 하나에 속한다.</p>
<p>시험관에 존재하는 모든 바이러스는 1초마다 상, 하, 좌, 우의 방향으로 증식해 나간다. 단, 매 초마다 번호가 낮은 종류의 바이러스부터 먼저 증식한다. 또한 증식 과정에서 특정한 칸에 이미 어떠한 바이러스가 존재한다면, 그 곳에는 다른 바이러스가 들어갈 수 없다.</p>
<p>시험관의 크기와 바이러스의 위치 정보가 주어졌을 때, S초가 지난 후에 (X,Y)에 존재하는 바이러스의 종류를 출력하는 프로그램을 작성하시오. 만약 S초가 지난 후에 해당 위치에 바이러스가 존재하지 않는다면, 0을 출력한다. 이 때 X와 Y는 각각 행과 열의 위치를 의미하며, 시험관의 가장 왼쪽 위에 해당하는 곳은 (1,1)에 해당한다.</p>
<p>예를 들어 다음과 같이 3x3 크기의 시험관이 있다고 하자. 서로 다른 1번, 2번, 3번 바이러스가 각각 (1,1), (1,3), (3,1)에 위치해 있다. 이 때 2초가 지난 뒤에 (3,2)에 존재하는 바이러스의 종류를 계산해보자.</p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/8bb2f96e-c42b-45c9-b226-070a48890b5f/image.png" alt=""></p>
<p>1초가 지난 후에 시험관의 상태는 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/6d98352e-fd47-4beb-b95b-4c52fc360c88/image.png" alt=""></p>
<p>2초가 지난 후에 시험관의 상태는 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/f34447ab-f983-4cf6-b323-2b2a49acb6b6/image.png" alt=""></p>
<p>결과적으로 2초가 지난 뒤에 (3,2)에 존재하는 바이러스의 종류는 3번 바이러스다. 따라서 3을 출력하면 정답이다.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000) 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다. 각 행은 N개의 원소로 구성되며, 해당 위치에 존재하는 바이러스의 번호가 공백을 기준으로 구분되어 주어진다. 단, 해당 위치에 바이러스가 존재하지 않는 경우 0이 주어진다. 또한 모든 바이러스의 번호는 K이하의 자연수로만 주어진다. N+2번째 줄에는 S, X, Y가 공백을 기준으로 구분되어 주어진다. (0 ≤ S ≤ 10,000, 1 ≤ X, Y ≤ N)</p>
<h3 id="출력">출력</h3>
<p>S초 뒤에 (X,Y)에 존재하는 바이러스의 종류를 출력한다. 만약 S초 뒤에 해당 위치에 바이러스가 존재하지 않는다면, 0을 출력한다.</p>
<h3 id="풀이">풀이</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline

n, k = map(int, input().split())
graph = []

for i in range(n):
    tmp = list(map(int, input().split()))
    graph.append(tmp)

s, x, y = map(int, input().split())

dx = [-1 ,1 , 0, 0]
dy = [0, 0, -1, 1]
def bfs(i, j):
    x, y = i, j
    for i in range(4):
        nx, ny = x+dx[i], y+dy[i]
        if 0&lt;= nx &lt; n and 0&lt;= ny &lt; len(graph[0]):
            # 한 번 전파될 때 숫자가 더 낮은 바이러스를 우선적으로 전파시켜주기 위한 조건문
            # 이미 한 번 전파되었고 현재 전파되는 바이러스가 더 작을 경우 현재 바이러스 숫자로 변경
            if graph[nx][ny] != 0 and visited[nx][ny] and (graph[nx][ny] &gt; graph[x][y]):
                graph[nx][ny] = graph[x][y]
                visited[nx][ny] = True
            elif graph[nx][ny] == 0:
                graph[nx][ny] = graph[x][y]
                visited[nx][ny] = True

for _ in range(s):
    visited = [[False] * (len(graph[0])) for _ in range(n)]
    for i in range(n):
        for j in range(len(graph[0])):
            if graph[i][j] != 0 and not visited[i][j]:
                bfs(i, j)
    cnt = 0
    for row in graph:
        cnt += row.count(0)
    if cnt == 0:
        break
print(graph[x-1][y-1])</code></pre>
<h3 id="후기🤔">후기🤔</h3>
<p>처음 시간초과 오류가 났다.
조건 중 &#39;바이러스가 모두 전파된 경우 전파를 멈춘다&#39;라는 조건을 처리해주지 않아서였다.
그래프에 0이 하나도 없을 경우 for문을 빠져나오는 부분을 추가해준 후 해결 !
조건을 주는건 이유가 있기 때문에 모든 조건을 빠짐없이 처리해주자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ-BFS] 1240 노드사이의 거리 Python ]]></title>
            <link>https://velog.io/@seungg-0/BOJ-BFS-1240-%EB%85%B8%EB%93%9C%EC%82%AC%EC%9D%B4%EC%9D%98-%EA%B1%B0%EB%A6%AC-Python</link>
            <guid>https://velog.io/@seungg-0/BOJ-BFS-1240-%EB%85%B8%EB%93%9C%EC%82%AC%EC%9D%B4%EC%9D%98-%EA%B1%B0%EB%A6%AC-Python</guid>
            <pubDate>Sun, 21 May 2023 09:49:11 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/1240">https://www.acmicpc.net/problem/1240</a></p>
<h3 id="문제">문제</h3>
<p>N(2≤N≤1,000)개의 노드로 이루어진 트리가 주어지고 M(M≤1,000)개의 두 노드 쌍을 입력받을 때 두 노드 사이의 거리를 출력하라.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 노드의 개수 N이 입력되고 다음 N-1개의 줄에 트리 상에 연결된 두 점과 거리(10,000 이하의 정수)를 입력받는다. 그 다음 줄에는 거리를 알고 싶은 M개의 노드 쌍이 한 줄에 한 쌍씩 입력된다.</p>
<h3 id="출력">출력</h3>
<p>M개의 줄에 차례대로 입력받은 두 노드 사이의 거리를 출력한다.</p>
<h4 id="예제-입력-1">예제 입력 1</h4>
<p>4 2
2 1 2
4 3 2
1 4 3
1 2
3 2</p>
<h4 id="예제-출력-1">예제 출력 1</h4>
<p>2
7</p>
<h3 id="풀이">풀이</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline
from collections import deque

nodes, n = map(int, input().split())
# graph에 저장되는 값 (연결된 노드, 거리)
graph = [[] for _ in range(nodes+1)]

# graph에 노드간 연결, 거리 정보 저장
for _ in range(nodes-1):
    a, b, dist = map(int, input().split())
    graph[a].append((b, dist))
    graph[b].append((a, dist))

for _ in range(n):
    # visited로 거리 계산
    visited = [-1 for _ in range(nodes+1)]
    a, b = map(int, input().split())
    queue = deque()
    queue.append(a)
    visited[a] = 0
    while queue:
        now = queue.popleft()
        if now == b:
            print(visited[b])
            break

        for node, dist in graph[now]:
            if visited[node] == -1:
                # 거리 누적 (이전노드까지 걸린 거리 + 이전 노드에서 현재 노드까지 걸린 거리)
                visited[node] += (visited[now]+(dist+1))
                queue.append(node)</code></pre>
<h3 id="후기-🤔">후기 🤔</h3>
<p>처음 dfs로 시도했다가 계속 실패해서 bfs로 풀었다.
거리를 누적해주는 부분에서 조금 고민했는데, &#39;최단거리&#39;를 구하는 문제와 유사하다.
이렇게 &#39;거리&#39;를 구할 때는 visited 자료형을 활용하면 된다는걸 기억하자 !</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ-BFS] 2583 영역 구하기 Python]]></title>
            <link>https://velog.io/@seungg-0/BOJ-BFS-2583-%EC%98%81%EC%97%AD-%EA%B5%AC%ED%95%98%EA%B8%B0-Python</link>
            <guid>https://velog.io/@seungg-0/BOJ-BFS-2583-%EC%98%81%EC%97%AD-%EA%B5%AC%ED%95%98%EA%B8%B0-Python</guid>
            <pubDate>Fri, 19 May 2023 17:20:11 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/2583">https://www.acmicpc.net/problem/2583</a></p>
<h3 id="문제">문제</h3>
<p>눈금의 간격이 1인 M×N(M,N≤100)크기의 모눈종이가 있다. 이 모눈종이 위에 눈금에 맞추어 K개의 직사각형을 그릴 때, 이들 K개의 직사각형의 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어진다.</p>
<p>예를 들어 M=5, N=7 인 모눈종이 위에 &lt;그림 1&gt;과 같이 직사각형 3개를 그렸다면, 그 나머지 영역은 &lt;그림 2&gt;와 같이 3개의 분리된 영역으로 나누어지게 된다.</p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/72266ed0-794f-4ae4-9d7c-48c35996bfec/image.png" alt=""></p>
<p>&lt;그림 2&gt;와 같이 분리된 세 영역의 넓이는 각각 1, 7, 13이 된다.</p>
<p>M, N과 K 그리고 K개의 직사각형의 좌표가 주어질 때, K개의 직사각형 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어지는지, 그리고 분리된 각 영역의 넓이가 얼마인지를 구하여 이를 출력하는 프로그램을 작성하시오.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오른쪽 위 꼭짓점의 x, y좌표값이 빈칸을 사이에 두고 차례로 주어진다. 모눈종이의 왼쪽 아래 꼭짓점의 좌표는 (0,0)이고, 오른쪽 위 꼭짓점의 좌표는(N,M)이다. 입력되는 K개의 직사각형들이 모눈종이 전체를 채우는 경우는 없다.</p>
<h3 id="출력">출력</h3>
<p>첫째 줄에 분리되어 나누어지는 영역의 개수를 출력한다. 둘째 줄에는 각 영역의 넓이를 오름차순으로 정렬하여 빈칸을 사이에 두고 출력한다.</p>
<h3 id="풀이-bfs">풀이 (BFS)</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline
from collections import deque

row, col, n = map(int, input().split(&#39; &#39;))
graph = [[0]*(col) for _ in range(row)]

for _ in range(n):
    x1, y1, x2, y2 = map(int, input().split(&#39; &#39;))
    for i in range(row-y2, row-y1):
        for j in range(x1, x2):
            graph[i][j] = 1

dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]

queue = deque()
def bfs(i, j, cnt):
    queue.append((i, j))
    count = cnt
    while queue:
        x, y = queue.popleft()
        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            if 0 &lt;= nx &lt; row and 0 &lt;= ny &lt; col:
                if graph[nx][ny] == 0:
                    graph[nx][ny] = 1
                    queue.append((nx, ny))
                    count += 1
    return count
answer = []
for i in range(row):
    for j in range(col):
        if graph[i][j] == 0:
            graph[i][j] = 1
            cnt = 1
            tmp = bfs(i, j, cnt)
            answer.append(tmp)

answer.sort()
print(len(answer))
print(*answer)</code></pre>
<h3 id="후기-🤔">후기 🤔</h3>
<p>사각형이 있는 부분은 1, 그렇지 않은 부분은 0으로 채워두고 BFS로 하나씩 탐색하면 된다.
초반 그래프를 그릴 때 (1을 칠할 때) for문의 범위를 잡아주는 부분에서 헷갈려서 조금 오래걸렸다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ-BFS] 11725 트리의 부모 찾기 Python]]></title>
            <link>https://velog.io/@seungg-0/BOJ-BFS-11725-%ED%8A%B8%EB%A6%AC%EC%9D%98-%EB%B6%80%EB%AA%A8-%EC%B0%BE%EA%B8%B0-Python</link>
            <guid>https://velog.io/@seungg-0/BOJ-BFS-11725-%ED%8A%B8%EB%A6%AC%EC%9D%98-%EB%B6%80%EB%AA%A8-%EC%B0%BE%EA%B8%B0-Python</guid>
            <pubDate>Thu, 18 May 2023 11:35:49 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/11725">https://www.acmicpc.net/problem/11725</a></p>
<h2 id="문제">문제</h2>
<p>루트 없는 트리가 주어진다. 이때, 트리의 루트를 1이라고 정했을 때, 각 노드의 부모를 구하는 프로그램을 작성하시오.</p>
<h2 id="입력">입력</h2>
<p>첫째 줄에 노드의 개수 N (2 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N-1개의 줄에 트리 상에서 연결된 두 정점이 주어진다.</p>
<h2 id="출력">출력</h2>
<p>첫째 줄부터 N-1개의 줄에 각 노드의 부모 노드 번호를 2번 노드부터 순서대로 출력한다.</p>
<h3 id="예제-입력-1">예제 입력 1</h3>
<pre><code>7
1 6
6 3
3 5
4 1
2 4
4 7</code></pre><h3 id="예제-출력-1">예제 출력 1</h3>
<pre><code>4
6
1
3
1
4</code></pre><h3 id="풀이-bfs">풀이 (BFS)</h3>
<pre><code class="language-python">import sys
input = sys.stdin.readline
from collections import deque

n = int(input())
visited = [False for _ in range(n+1)]

# 노드 연결 정보
linked = [[] for _ in range(n+1)]
for i in range(n-1):
    a, b = map(int, input().split())
    linked[a].append(b)
    linked[b].append(a)

queue = deque()
queue.append(1)
answer = [[] for _ in range(n+1)]
while queue:
    parent = queue.popleft()
    for i in linked[parent]:
        if not visited[i]:
            visited[i] = True
            queue.append(i)
            answer[i] = parent

for i in range(2, n+1):
    print(answer[i])

</code></pre>
<p>graph에 노드들의 연결 정보를 저장한다.
최상단 노드인 1부터 큐에 넣는다. (큐에 들어간 노드는 이제 더이상 누군가의 자식 노드가 될 수 없다.)
이제 큐에서 하나씩 pop 하며 연결된 노드를 자식 노드로 저장하면 된다.</p>
<p>처음에 BFS방식이 아닌 for문을 사용해서 풀었다가 다시 풀었다.</p>
<p><strong>자료구조, 알고리즘을 먼저 생각하고 문제에 적용하자</strong> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 사용법]]></title>
            <link>https://velog.io/@seungg-0/Git%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@seungg-0/Git%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Sun, 30 Apr 2023 02:50:14 GMT</pubDate>
            <description><![CDATA[<h3 id="commit-메시지-작성-방법">Commit 메시지 작성 방법</h3>
<pre><code>1번째 줄 : 커밋 내의 변경 내용을 요약
2번째 줄 : 빈 칸
3번째 줄 : 변경한 이유</code></pre><h3 id="작업트리와-인덱스">작업트리와 인덱스</h3>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/a75fc223-ef2f-42dc-9489-e8d092bb0fef/image.png" alt=""></p>
<p>Git의 <strong>&#39;커밋&#39;</strong> 작업은 <strong>&#39;작업 트리&#39;</strong>에 있는 변경 내용을 저장소에 바로 기록하는 것이 아니라 <strong>&#39;인덱스&#39;</strong>에 파일 상태를 <strong>기록(stage - 스테이징)</strong> 해야 한다.</p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/1d4ccb25-1835-4118-a6f0-b0983221c664/image.png" alt=""></p>
<h3 id="원격-저장소-복제-clone">원격 저장소 복제 (Clone)</h3>
<ul>
<li>누군가의 변경 이력이 적용된 원격 저장소가 있으면, 그걸 통째로 복제해와 내 PC에서 작업할 수 있다. 이때 사용하는 것이 Clone !</li>
</ul>
<ul>
<li><strong>변경 이력도 함께 로컬 저장소에 복제</strong>되어 오기 때문에, 원격 저장소와 똑같이 이력을 참조, 커밋 진행이 가능하다.</li>
</ul>
<h3 id="원격-저장소에서-pull-해오기">원격 저장소에서 Pull 해오기</h3>
<ul>
<li>원격 저장소를 공유해 여러 사람이 함께 작업하면, 모두가 같은 원격 저장소에 push를 하게 됨.</li>
<li>그렇다면, 다른 사람이 원격 저장소에 push한 내용을 내 로컬 저장소에도 pull 할 필요가 있다. (원격 저장소 변경 내역 로컬 저장소에 업데이트)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/3cb69cf2-635b-4dd6-9c95-6b920502227e/image.png" alt=""></p>
<h3 id="변경-이력-병합merge">변경 이력 병합(Merge)</h3>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/da3588fd-7d89-4044-81a9-e339f13f7610/image.png" alt=""></p>
<p>내가 <strong>pull을 한 후 다른 사람이 push를 해 원격 저장소를 업데이트</strong> 한 경우 내 <strong>push 요청이 거부</strong>된다.
<img src="https://velog.velcdn.com/images/seungg-0/post/4f088f14-d27b-44c0-b9c9-32e1bf108ba1/image.png" alt=""></p>
<p>이 경우 <strong>병합(merge)</strong> 작업을 통해 다른 사람의 업데이트 이력을 내 저장소에도 갱신해야 한다.</p>
<p><strong>1. 수동으로 해결하는 방법</strong></p>
<ul>
<li>원격 저장소와 로컬 저장소 양쪽에서 파일의 동일한 부분을 변경한 경우
<em>두 변경 내용 중 어느 쪽을 저장할 것인지 판단 할 수 없기 때문에 충돌 발생</em></li>
</ul>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/a6018bea-16eb-48f3-b579-555e996f6ed6/image.png" alt=""></p>
<p>Git은 충돌이 발생한 파일 내용을 위 그림처럼 표시해준다. (이 부분을 직접 수정해 주어야 함)
즉, 파일을 일일이 비교하며 바뀐 점을 찾아서 적용한 후 병합</p>
<p>당연히 &quot;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD , &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;footer&quot; 같은 충돌기호는 다 지워야 한다.</p>
<p><strong>2. 깃으로 자동 병합</strong></p>
<ul>
<li><p>파일의 다른 위치를 수정했다면 깃에서 서로 다른 위치의 소스를 자동으로 병합하기 때문에 문제가 없다.</p>
</li>
<li><p>하지만 실제 개발 환경에서는 여러 사람이 같은 위치의 코드를 수정하기 때문에 자동병합으론 해결 못하는 충돌이 자주 일어남.</p>
</li>
</ul>
<p>이 경우,</p>
<blockquote>
<p>git checkout master : 기준이 되는 브랜치로 먼저 이동
git merge feature : 병합당하는_브랜치</p>
</blockquote>
<p>명령어를 입력하면 브랜치의 코드가 아래처럼 수정된다.</p>
<p><strong>동일한 곳을 수정했을 경우</strong></p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/094c01f7-3107-4057-bcb4-c88858c22d6a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/ca94845f-97bc-4be9-a7a7-d8bb883ecf1a/image.png" alt=""></p>
<p><strong>아래처럼 수정됨</strong></p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/69c32dcd-9eea-4536-826e-ab20e6c4e470/image.png" alt=""></p>
<p>HEAD가 현재 브랜치이고, 둘 다 수락하거나 둘 중 하나를 수학하면 자동으로 충돌이 해결된다.
선택하고 add, commit 하면 병합이 완료된다.</p>
<h3 id="충돌-예방-방법">충돌 예방 방법</h3>
<ul>
<li>내부적으로 팀원 간 규칙을 정하고 상의하면서 개발을 진행하면 항후 발생할 충돌을 줄인다.</li>
<li>자주 커밋하고 자주 병합할 수록 충돌이 발생할 기회는 적다.</li>
<li>자신의 브랜치 상태가 최신일수록 병합할 때 발생하는 충돌을 최소화 할수 있다.</li>
<li>기준이 되는 브랜치(예를 들어 master)를 자주 모니터링하고, 변화된 부분을 즉시 자신의 브랜치에 반영하면서 작업하면 충돌을 줄일 수 있다.</li>
</ul>
<h3 id="브랜치-병합-여부-확인">브랜치 병합 여부 확인</h3>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/29c65d3b-92b1-41eb-8aaf-31c51870f6c4/image.png" alt=""></p>
<pre><code>병합한 브랜치는 (*)로 표시된다!
git branch --no-merged :병합하지 않은 브랜치 조회</code></pre><h4 id="참고">참고</h4>
<blockquote>
<ol>
<li><a href="https://backlog.com/git-tutorial/kr/intro/intro1_1.html">https://backlog.com/git-tutorial/kr/intro/intro1_1.html</a></li>
<li><a href="https://konkukcodekat.tistory.com/entry/%EA%B9%83git-%EB%B3%91%ED%95%A9-merge-Fast-Forward-3-way">https://konkukcodekat.tistory.com/entry/%EA%B9%83git-%EB%B3%91%ED%95%A9-merge-Fast-Forward-3-way</a></li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA) 반복문과 배열]]></title>
            <link>https://velog.io/@seungg-0/%EB%B0%98%EB%B3%B5%EB%AC%B8%EA%B3%BC-%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@seungg-0/%EB%B0%98%EB%B3%B5%EB%AC%B8%EA%B3%BC-%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Sat, 29 Apr 2023 12:52:25 GMT</pubDate>
            <description><![CDATA[<h3 id="반복문">반복문</h3>
<ul>
<li>for문과 while문
  <strong>while문</strong>은 <strong>반복 횟수가 상황에 따라 다른 경우</strong>에 사용하는 반면, <strong>for문</strong>은 <strong>반복횟수가 명확할 때</strong> 좋다.</li>
</ul>
<ul>
<li>while문 예시</li>
</ul>
<pre><code>int n = 1;
while (n &lt;= 10) {
  System.out.println(n);
  n++;
}</code></pre><ul>
<li>for문 예시<pre><code>for (int i = 1; i &lt;= 9; i++) {
System.out.printf(&quot;3 x %d = %d\n&quot;, i, 3 * i);
}</code></pre></li>
</ul>
<p>Python과 같이 break, continue 사용이 가능하다.</p>
<h3 id="배열">배열</h3>
<p>자바의 배열은 Python의 List와 다르게 같은 형의 데이터만 저장할 수 있다.
<img src="https://velog.velcdn.com/images/seungg-0/post/10f33591-ef48-46ce-91b2-ddfc6143f2b4/image.png" alt=""></p>
<h4 id="배열이란">배열이란?</h4>
<p>여러 값을 하나의 변수로 묶은 것.</p>
<pre><code>int[] scores = { 65, 74, 23, 75, 68, 96, 88, 98, 54 };


// 1) 배열 값 읽기(read)
int[] scores = {99, 88, 77};
System.out.println(scores[0]); // 99
System.out.println(scores[1]); // 88
System.out.println(scores[2]); // 77
// 2) 배열 값 변경(write)
System.out.println(scores[0]); // 99
scores[0] = 0; // 0번 인덱스 값 변경
System.out.println(scores[0]); // 0
</code></pre><p>length 키워드로 배열의 길이 알 수 있음</p>
<pre><code>String[] names = {&quot;Kim&quot;, &quot;Lee&quot;, &quot;Park&quot;, &quot;Choi&quot;, &quot;Oh&quot;, &quot;Jo&quot;};
int[] mathScores = {82, 76, 100, 92, 68, 96};
for (int i = 0; i &lt; names.length; i++) {
  System.out.printf(&quot;%s : %d\n&quot;, names[i], mathScores[i]);
}</code></pre><p>출처: <a href="https://cloudstudying.kr/courses/10">https://cloudstudying.kr/courses/10</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA) 메소드와 조건문]]></title>
            <link>https://velog.io/@seungg-0/%EB%A9%94%EC%86%8C%EB%93%9C%EC%99%80-%EC%A1%B0%EA%B1%B4%EB%AC%B8</link>
            <guid>https://velog.io/@seungg-0/%EB%A9%94%EC%86%8C%EB%93%9C%EC%99%80-%EC%A1%B0%EA%B1%B4%EB%AC%B8</guid>
            <pubDate>Sat, 29 Apr 2023 12:44:21 GMT</pubDate>
            <description><![CDATA[<h3 id="타입과-형-변환">타입과 형 변환</h3>
<ul>
<li><p><strong>나눗셈 연산 주의</strong>
숫자간 연산은 더 큰 타입을 따른다.</p>
<pre><code>1. double a = 5.0 / 2.0; // 2.5
2. int b = 4 / 2;        // 2
3. int c = 5 / 2;        // 2.5 (X) =&gt; 2 (O)
</code></pre></li>
<li><p><strong>타입 불일치 주의</strong>
변수에 값 대입 시, 그 <strong>값이 변수의 타입과 일치</strong>해야 한다.</p>
<pre><code>1. // 타입 불일치 에러
2. int score = &quot;100&quot;;
3. 
4. // 해결 방법
5. int score = 100;      // int로 일치
6. String score = &quot;100&quot;; // String으로 일치
7. int score = Integer.parseInt(&quot;100&quot;); // &quot;100&quot; =&gt; 100</code></pre></li>
<li><p><strong>타입 변환 주의</strong>
  타입 불일치의 문제는 <strong>타입 변환</strong>을 통해 해결 가능하다.</p>
<ul>
<li><strong>자동변환</strong> (더 큰 타입으로 대입시 발생)
```</li>
</ul>
<ol>
<li><p>// 자동 변환 (더 큰 타입으로 대입될 때)</p>
</li>
<li><p>double p = 2;  // 2 =&gt; 2.0</p>
</li>
<li><p>int n = 5 / 2; // 2</p>
</li>
<li><p>double q = n;  // 2 =&gt; 2.0</p>
<pre><code></code></pre></li>
</ol>
<ul>
<li><strong>직접변환</strong> (타입 casting)
```</li>
</ul>
<ol>
<li>// 에러 발생</li>
<li>int r = 10.4; // ERROR</li>
<li></li>
<li>// 실수를 정수로 강제 캐스팅</li>
<li>int r = (int) 10.4; // 10.4 =&gt; 10<pre><code></code></pre></li>
</ol>
</li>
</ul>
<h3 id="메소드-호출과-정의">메소드 호출과 정의</h3>
<h4 id="메소드란">메소드란?</h4>
<p>일련의 동작을 하나로 묶는 것
입력값에 따른 반환값이 있다.</p>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/3e9d889b-311e-4f98-99d4-370fd4aa5e79/image.png" alt=""></p>
<h3 id="메소드-정의">메소드 정의</h3>
<p>메소드를 사용하려면, 먼저 정의돼 있어야한다.
<img src="https://velog.velcdn.com/images/seungg-0/post/a6999ceb-bba4-4d2f-8220-b97a9a673bb2/image.png" alt=""></p>
<h3 id="메소드-예시">메소드 예시</h3>
<pre><code>public static int square(int n) {
  int result;
  result = n * n;
  return result;
}</code></pre><p>다음과 같이 호출 가능</p>
<pre><code>int z = square(4); // 입력: 4 =&gt; 반환: 16
System.out.println(z); // 16</code></pre><h3 id="조건문">조건문</h3>
<h4 id="조건문이란">조건문이란?</h4>
<p>상황에 따라 실행 흐름을 달리하는 문법</p>
<ul>
<li>if문, else if문, else문<pre><code>if (90점이상?) {
A 학점
} else if (80점 이상?){
B 학점
} else {
C 학점
}</code></pre><h4 id="비교-연산자">비교 연산자</h4>
<pre><code>System.out.println(7 &gt; 4); // 7은 4보다 큰가? =&gt; true
System.out.println(10 % 3 == 0); // 10을 3으로 나눈 나머지가 0인가? =&gt; false
</code></pre></li>
</ul>
<p>```</p>
<h4 id="논리-연산자">논리 연산자</h4>
<ol>
<li>and -&gt; &amp;&amp;</li>
<li>or -&gt; ||</li>
<li>not -&gt; !</li>
</ol>
<p>출처: <a href="https://cloudstudying.kr/courses/10">https://cloudstudying.kr/courses/10</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA) 자바 시작하기]]></title>
            <link>https://velog.io/@seungg-0/%EC%9E%90%EB%B0%94-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@seungg-0/%EC%9E%90%EB%B0%94-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 29 Apr 2023 12:31:19 GMT</pubDate>
            <description><![CDATA[<h3 id="자바-프로그래밍이란">자바 프로그래밍이란?</h3>
<ul>
<li>자바 언어로 컴퓨터에게 일을 시키는 것.</li>
<li>개발자가 컴퓨터에게 시킬 일을 자바 언어(소스코드)로 작성하면, 소스코드는 컴파일러라는 번역기를 통해 기계어로 바뀐다.</li>
<li>컴파일링(compiling) : 자바 코드가 기계어로 번역되는 과정</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seungg-0/post/ba4ecc7b-a2c6-4c18-a37f-93b48747499f/image.png" alt=""></p>
<h3 id="자바의-특징과-객체지향">자바의 특징과 객체지향</h3>
<ul>
<li>자바는 <strong>멀티플랫폼</strong> 언어이다.<ul>
<li>멀티플랫폼 언어 : 다양한 운영체제(UNIX, Window, MacOS, Android, etc..)에서 변경없이 동작. (이식성이 좋음)</li>
</ul>
</li>
<li>자바는 <strong>객체지향</strong> 언어이다.<ul>
<li>객체 지향 언어 : 객체를 조립해 전체 프로그램을 만든느 언어</li>
</ul>
</li>
</ul>
<h3 id="변수와-타입-그리고-연산자">변수와 타입 그리고 연산자</h3>
<ul>
<li>변수 : 변하는 수로서, 이름 붙여진 메모리 공간</li>
<li>변수 생성의 예<pre><code>int mathScore = 88;            // 수학 점수를 저장할 공간
String bookTitle = &quot;오만과 편견&quot;; // 책 이름을 저장할 공간
double weight = 72.4;          // 무게를 저장할 공간
boolean finished = true;       // 종료 여부를 저장할 공간</code></pre></li>
</ul>
<p>출처: <a href="https://cloudstudying.kr/courses/10">https://cloudstudying.kr/courses/10</a></p>
]]></description>
        </item>
    </channel>
</rss>