<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>choi_sujin.log</title>
        <link>https://velog.io/</link>
        <description> 매일매일 머리 터지는 중 ᕙ(•̀‸•́‶)ᕗ</description>
        <lastBuildDate>Fri, 01 Nov 2024 08:36:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>choi_sujin.log</title>
            <url>https://velog.velcdn.com/images/choi_sujin/profile/5f82849d-1878-48b6-b12d-176c048231d9/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. choi_sujin.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/choi_sujin" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[2775) 부녀회장이 될테야]]></title>
            <link>https://velog.io/@choi_sujin/2775-%EB%B6%80%EB%85%80%ED%9A%8C%EC%9E%A5%EC%9D%B4-%EB%90%A0%ED%85%8C%EC%95%BC</link>
            <guid>https://velog.io/@choi_sujin/2775-%EB%B6%80%EB%85%80%ED%9A%8C%EC%9E%A5%EC%9D%B4-%EB%90%A0%ED%85%8C%EC%95%BC</guid>
            <pubDate>Fri, 01 Nov 2024 08:36:50 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<ul>
<li>k층 n호에 살고 있는 사람의 수 구하기</li>
<li>a층 b호에 사는 사람은, a-1층의 1호부터 b호까지의 사람들의 수의 합</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>K층의 N번째 사람 수를 구할 때 까지 총 O(K) * O(N)번의 연산이 필요.
K와 N 모두 최대 14이고, 최대 연산수는 196
시간제한 : 0.5</p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>DP : 앞에 계산해 놓은 값을 재활용해 뒤의 문제의 답을 구하는 방식</p>
<h2 id="📌-풀이하기">📌 풀이하기</h2>
<ol>
<li>a층 b호 사람은 (a층 b-1호의 사람) + (a-1층 b호의 사람)</li>
<li>관계식 구하기
dp[b] += dp[b-1]</li>
</ol>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input을 받는다.</li>
<li>가장 작은 문제의 답, 0번째 층의 사람 수를 기록한다.</li>
<li>설계한 관계식에 맞게 DP 탐색을 진행한다.</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">
import sys

T = int(sys.stdin.readline())

for _ in range(T):
    K = int(sys.stdin.readline()) # 층
    N = int(sys.stdin.readline()) # 호

    # 0번째 층의 사람수
    DP = [i for i in range(1, N+1)]

    for a in range(K):
        for b in range(1, N):
            DP[b] += DP[b-1]

    print(DP[N - 1])


</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[2748) 피보나치 수 2]]></title>
            <link>https://velog.io/@choi_sujin/2748-%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%EC%88%98-2</link>
            <guid>https://velog.io/@choi_sujin/2748-%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%EC%88%98-2</guid>
            <pubDate>Tue, 29 Oct 2024 06:12:07 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<ul>
<li>피보나치 수는 0과 1로 시작</li>
<li>Fn = Fn-1 + Fn-2</li>
<li>즉, n = 10이면 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55</li>
<li>N번째 피보나치 수를 구하기</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>N번째 피보나치 수를 구할 때 까지 N번의 연산이 필요.
따라서 O(N)이 되고, N은 최대 90개 이기 때문에 1초의 시간안에 연산 가능.</p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>DP : 앞에 계산해 놓은 값을 재활용해 뒤의 문제의 답을 구하는 방식</p>
<h2 id="📌-풀이하기">📌 풀이하기</h2>
<ul>
<li>DP 관계식 구하기
dp[N] = dp[n-1] + dp[n-2]</li>
</ul>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input을 받는다.</li>
<li>가장 작은 문제의 답(피보나치 0,1번째 수)를 먼저 구한다.</li>
<li>DP 관계식을 구현하고, N번 째 수까지의 답을 순차적으로 탐색한다.</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">
# 백준 2578
import sys

n = int(sys.stdin.readline())

dp = []
dp.append(0)
dp.append(1)

for i in range(2, n+1):
    dp.append(dp[i-2] + dp[i-1])

print(dp[n])


</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[2578) 빙고]]></title>
            <link>https://velog.io/@choi_sujin/2578-%EB%B9%99%EA%B3%A0-2923k1qp</link>
            <guid>https://velog.io/@choi_sujin/2578-%EB%B9%99%EA%B3%A0-2923k1qp</guid>
            <pubDate>Fri, 25 Oct 2024 10:28:12 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<ul>
<li>5 * 5 크기의 빙고판 입력</li>
<li>그 후 사회자가 불러주는 숫자가 5 * 5 배열로 입력</li>
<li>사회자가 숫자를 부른 후, 빙고판에서 빙고가 몇개 완성되었는지 확인</li>
<li>완성된 빙고가 3개 이상이라면 부른 숫자가 몇번째 숫자인지 출력</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>시간 제한 : 1초
사회자는 총 25개의 숫자를 부르고, 빙고판에서 어느 위치에 숫자가 존재하는지 확인하는데도 총 25개의 비교연산이 필요하므로, 25 * 25 = 약 625개의 연산 필요</p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>시뮬레이션, 구현</p>
<h2 id="📌-풀이하기">📌 풀이하기</h2>
<ol>
<li><p>사회자가 부른 숫자를 빙고판에 체크하기</p>
<ul>
<li><p>5 * 5 2차원 빙고판을 만들어두고, False 또는 0으로 마킹</p>
</li>
<li><p>빙고판을 모두 탐색하며 사회자가 부른 숫자와 일치하면 True 또는 1로 마킹</p>
<blockquote>
<p>사회자는 총 25개의 숫자를 부르고, 빙고판에서 어느 위치에 숫자가 존재하는지 확인하는데도 총 25개의 비교연산이 필요하므로, 25 * 25 = 약 625개의 연산 필요 =&gt; 1초 안에 가능</p>
</blockquote>
</li>
</ul>
</li>
<li><p>현재까지 완성된 빙고의 개수 확인하기
빙고는 총 가로 5개, 세로 5개, 대각선 2개 존재</p>
<ol>
<li>가로 빙고</li>
</ol>
<ul>
<li>가로 빙고는 i번째 행에 대해 [i][0], [i][1], ..., [i][4]가 모두 마킹된(True)인지 확인</li>
<li>5개 행에 대해 모두 확인 필요</li>
</ul>
<ol start="2">
<li>세로 빙고</li>
</ol>
<ul>
<li>세로 빙고는 i번째 행에 대해 [0][i], [1][i], ...,[4][i]가 모두 True인지 확인</li>
<li>5개 열에 대해 모두 확인 필요</li>
</ul>
<ol start="3">
<li>대각선 빙고</li>
</ol>
<ul>
<li>대각선의 경우 /모양과 \모양이 있다. \모양은 [i][i], /모양은 [i][4-i]<blockquote>
<p> 사회자가 숫자를 부른 후, 현재까지 완성된 빙고의 개수를 확인하는데 걸리는 연산 개수
빙고는 총 가로 5개, 세로 5개, 대각선 2개가 존재하고 빙고 1줄당 총 5개의 비교연산이 필요하므로, 총 12 * 5 = 60번의 비교연산이 필요
사회자가 최대 25개의 숫자를 부를 수 있으므로, 최악의 경우 25 * 60 == 1500개의 연산 필요 =&gt; 1초 안에 가능</p>
</blockquote>
</li>
</ul>
</li>
</ol>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input을 받는다.</li>
<li>빙고판을 초기화한다.</li>
<li>빙고의 개수를 구할 수 있는 함수를 구현한다. (행, 열, 대각선)</li>
<li>사회자가 부르는 각 수에 대해 빙고판을 True로 체크하고 만족하는 빙고의 수를 확인한다.</li>
<li>완성된 빙고의 수가 3개 이상인지 확인하고, 정답을 출력한다.</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">import sys

# 백준 2578

# 1. 빙고판 입력 받기
arr = []
for _ in range(5):
    arr.append(sys.stdin.readline().split())


# 2. 사회자가 부르는 수 list 담기
num = []
for _ in range(5):
    list = sys.stdin.readline().split()

    for i in list:
        num.append(i)

# 3. 빙고판 초기화
check_board = [[False for _ in range(5)] for _ in range(5)]

# 4. 빙고 수를 체크할 수 있는 함수
def check_row_bingo():
    count = 0
    for i in range(5):
        is_bingo = True
        for j in range(5):
            if not check_board[i][j]:
                is_bingo = False
                break
        if is_bingo:
            count += 1
    return count

# 5. 빙고 column 수를 확인하기 위한 함수 구현
def check_column_bingo():
    count = 0
    for j in range(5):
        is_bingo = True
        for i in range(5):
            if not check_board[i][j]:
                is_bingo = False
                break
        if is_bingo:
            count += 1
    return count

# 6. 대각선 빙고 수 확인하기 위한 함수 구현
def check_diagonal_bingo():
    count = 0
    # \ 모양 대각선
    is_bingo = True
    for i in range(5):
        if not check_board[i][i]:
            is_bingo = False
            break
    if is_bingo:
        count += 1

    # / 모양 대각선
    is_bingo = True
    for i in range(5):
        if not check_board[i][4 - i]:
            is_bingo = False
            break
    if is_bingo:
        count += 1

    return count


# 7. 사회자가 부르는 각 수에 대해 빙고판을 True로 체크하고,
#    만족하는 빙고의 수를 확인
for i in range(25):
    now_num = num[i]
    # 사회자가 부른 숫자의 빙고판 위치 확인하고 True로 표기
    for x in range(5):
        for y in range(5):
            if arr[x][y] == now_num:
                check_board[x][y] = True
    # 빙고판 True로 체크한 이후 빙고 몇개 완성됐는지 확인
    count = check_row_bingo() + check_column_bingo() + check_diagonal_bingo()
    # 완성된 빙고의 개수가 3개 이상이라면 해당 순서 출력
    if count &gt;= 3:
        print(i + 1)
        break
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[7568) 덩치]]></title>
            <link>https://velog.io/@choi_sujin/7568-%EB%8D%A9%EC%B9%98</link>
            <guid>https://velog.io/@choi_sujin/7568-%EB%8D%A9%EC%B9%98</guid>
            <pubDate>Thu, 12 Sep 2024 06:29:26 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/910525d9-1075-4109-a964-fbdf657a8ebf/image.png" alt=""></p>
<ul>
<li>몸무게 x, 키 y -&gt; (x, y)</li>
<li>덩치는 x와 y 모두 커야 덩치 큰 것</li>
<li>x만 크거나 y만 큰 건 공동 순위</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>시간 제한 : 1초
2 ≤ N ≤ 50</p>
<ul>
<li>N이 크지 않기 때문에 이중for문을 사용하여 O(N^2)</li>
</ul>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>브루트포스</p>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input 받기</li>
<li>list[0]과 list[1] 모두 큰 1등 덩치와 꼴등 덩치 먼저 구하기</li>
<li>나머지는 공동 순위</li>
<li>순위 출력</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">N = int(input())
people = [tuple(map(int, input().split())) for _ in range(N)]
# 덩치 등수
ranks = [1] * N

for i in range(N):
    for j in range(N):
        if i != j:
            if people[i][0] &lt; people[j][0] and people[i][1] &lt; people[j][1]:
                ranks[i] += 1

print(*ranks, sep=&quot; &quot;)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[2947) 나무조각]]></title>
            <link>https://velog.io/@choi_sujin/2947-%EB%82%98%EB%AC%B4%EC%A1%B0%EA%B0%81</link>
            <guid>https://velog.io/@choi_sujin/2947-%EB%82%98%EB%AC%B4%EC%A1%B0%EA%B0%81</guid>
            <pubDate>Thu, 12 Sep 2024 06:27:46 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/4b768aa3-3b02-4d25-ae6c-e6e5da6c1f66/image.png" alt=""></p>
<ul>
<li>1~5 숫자 나무조각을 오름차순으로 정렬</li>
<li>입력 받은 순서에서 오름차순으로 정렬되는 과정 출력<ul>
<li>첫번째 조각 &gt; 두번째 조각 -&gt; swap</li>
<li>두번째 조각 &gt; 세번째 조각 -&gt; swap</li>
<li>세번째 조각 &gt; 네번째 조각 -&gt; swap</li>
<li>네번째 조각 &gt; 다섯번째 조각 -&gt; swap</li>
<li>1,2,3,4,5가 아니라면 다시 반복<ul>
<li>단, swap 될 때만 출력</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>시간 제한 : 1초</p>
<p>이중 for문의 시간복잡도는 O(N^2)
-&gt; N이 매우 클 경우 효율적인 알고리즘은 아니지만, N은 5로 작으므로 괜찮다.</p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>버블 정렬 </p>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input 받기</li>
<li>이중 for 문으로 인접한 두 수를 비교해서 앞에 수가 뒤에 수보다 크면 교환 후 리스트 출력 -&gt; 정렬이 완료될 때까지 반복(N:5번)</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">import sys

# arr = list(map(int, sys.stdin.readline().strip().split()))
arr = [int(x) for x in sys.stdin.readline().strip().split()]

for i in range(5):
    for j in range(5-i-1):
        if(arr[j+1] &lt; arr[j]):
            arr[j+1], arr[j] = arr[j], arr[j+1]
            print(*arr, sep=&quot; &quot;)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[25305) 커트라인]]></title>
            <link>https://velog.io/@choi_sujin/25305-%EC%BB%A4%ED%8A%B8%EB%9D%BC%EC%9D%B8-%EB%AF%B8%EC%A0%9C%EC%B6%9C</link>
            <guid>https://velog.io/@choi_sujin/25305-%EC%BB%A4%ED%8A%B8%EB%9D%BC%EC%9D%B8-%EB%AF%B8%EC%A0%9C%EC%B6%9C</guid>
            <pubDate>Thu, 12 Sep 2024 05:49:11 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/846322d1-1c35-43cf-9073-0c3450610fcd/image.png" alt=""></p>
<ul>
<li>응시생 N명 / 수상 인원 K명</li>
<li>점수가 가장 높은 K명 중 점수가 가장 낮은 사람의 점수 </li>
<li>즉, 상을 받는 커트라인 출력</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>시간 제한 : 1초
1 ≤ N ≤ 1000</p>
<p>sort() 메소드의 시간복잡도는 O(NlogN) </p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>정렬 </p>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input 받기</li>
<li>조건에 맞게 정렬<ul>
<li>점수를 내림차순으로 정렬</li>
</ul>
</li>
<li>출력 <ul>
<li>K-1번째 리스트 요소 출력</li>
</ul>
</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h3 id="1회차">1회차</h3>
<ul>
<li>import sys 를 빼먹어서 런타임 에러가 났다</li>
</ul>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">import sys

N, K = map(int, sys.stdin.readline().strip().split())
arr = list(map(int,sys.stdin.readline().strip().split()))

arr.sort(reverse=True)
print(arr[K-1])
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[5635) 생일]]></title>
            <link>https://velog.io/@choi_sujin/5635-%EC%83%9D%EC%9D%BC</link>
            <guid>https://velog.io/@choi_sujin/5635-%EC%83%9D%EC%9D%BC</guid>
            <pubDate>Thu, 12 Sep 2024 04:15:16 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/3c34d963-bd56-4f20-b5ae-db026813516f/image.png" alt=""></p>
<ul>
<li>주어진 생년월일로 </li>
<li>가장 나이가 적은 사람과 가장 많은 사람 구하기</li>
<li>연도가 같으면 생일로 구분!</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>시간 제한 : 1초
1 ≤ N ≤ 100</p>
<p>sort() 메소드의 시간복잡도는 O(NlogN) </p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>정렬 </p>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input 받기</li>
<li>조건에 맞게 정렬<ul>
<li>yyyy(연도) 오름차순</li>
<li>mm(월) 오름차순</li>
<li>dd(일) 오름차순</li>
</ul>
</li>
<li>출력 <ul>
<li>가장 나이가 적은 사람의 이름</li>
<li>가장 나이가 많은 사람의 이름</li>
</ul>
</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">import sys

N = int(sys.stdin.readline())
arr = []

for i in range(N):
    name, dd, mm, yyyy = sys.stdin.readline().strip().split()
    arr.append([name, int(dd), int(mm), int(yyyy)])

# 정렬
arr.sort(key=lambda x: (x[3], x[2], x[1]))

print(arr[N-1][0])
print(arr[0][0])
</code></pre>
<ul>
<li>람다식 이용</li>
</ul>
<pre><code class="language-python">import sys

N = int(sys.stdin.readline())
arr = []

for i in range(N):
    name, dd, mm, yyyy = sys.stdin.readline().strip().split()
    arr.append([int(yyyy), int(mm), int(dd), name])

# 정렬
arr.sort()

print(arr[N-1][0])
print(arr[0][0])
</code></pre>
<ul>
<li>리스트 저장 순서를 바꿔서 sort() 자체로 정렬</li>
<li>이름이 같거나, 생일이 같은 사람은 없다는 조건 !</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[1181) 단어정렬]]></title>
            <link>https://velog.io/@choi_sujin/%EB%8B%A8%EC%96%B4%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@choi_sujin/%EB%8B%A8%EC%96%B4%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Wed, 11 Sep 2024 09:18:03 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/cf139bc2-4ce8-40b6-a470-acbf19191140/image.png" alt=""></p>
<ul>
<li>정렬 조건<ol>
<li>길이 오름차순  2. 사전 오름차순</li>
</ol>
</li>
<li>중복된 단어는 제거!</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>시간 제한 : 2초
1 ≤ N ≤ 20,000</p>
<p>입력 처리: O(N)
중복 제거: O(N) (set을 사용한 중복 제거)
정렬: O(N log N) (Timsort 정렬)
출력: O(N)
=&gt; O(N log N) = 약 80,000만 =&gt; 적합</p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>파이썬의 내장 정렬 함수인 sort()는 <strong>Timsort 알고리즘</strong>을 사용한다. 
Timsort는 합병 정렬과 삽입 정렬의 장점을 결합한 알고리즘으로, 최악의 경우 시간 복잡도는 <em>*O(N log N)</em></p>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input 받기</li>
<li>중복 제거 <ul>
<li>set 활용</li>
</ul>
</li>
<li>조건에 맞게 정렬 (1. 길이 오름차순 2. 사전 오름차순)<ul>
<li>람다식 활용</li>
</ul>
</li>
<li>출력</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h3 id="1회차">1회차</h3>
<pre><code class="language-python">import sys

# 1. input 받기
N = int(sys.stdin.readline())
arr = []
for _ in range(N):
    arr.append(sys.stdin.readline())

# 2. 중복 제거
unique = list(set(arr)) 

# 3. 정렬
unique.sort(key=lambda x: (len(x), x))

# 4. 출력
for u in unique:
    print(u)

# print(*unique, sep=&quot;\n&quot;)
</code></pre>
<ul>
<li>sys.stdin.readline() 를 사용했더니 출력에 개행이 한 줄씩 더 들어가 있어서 출력 형식이 다르다고 떴다.</li>
<li>sys.stdin.readline()는 입출력은 빠르지만, 줄바꿈 문자를 포함하여 출력이 다르게 나올 수 있다. -&gt; strip()을 사용하여 공백, 개행문자 제거하거나 input() 사용하기!</li>
</ul>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python"># 1. input 받기
N = int(input())
arr = []
for _ in range(N):
    arr.append(input())

# 2. 중복 제거
unique = list(set(arr)) 

# 3. 정렬
unique.sort(key=lambda x: (len(x), x))

# 4. 출력
print(*unique, sep=&quot;\n&quot;)

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[10814) 나이순 정렬 ]]></title>
            <link>https://velog.io/@choi_sujin/%EB%82%98%EC%9D%B4%EC%88%9C-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@choi_sujin/%EB%82%98%EC%9D%B4%EC%88%9C-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Tue, 10 Sep 2024 12:01:19 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/5438b604-1a71-4448-ba32-3efba0bc67be/image.png" alt=""></p>
<ul>
<li>회원의 나이와 이름을 정렬하여 출력<ul>
<li>나이가 증가하는 순</li>
<li>나이가 같으면 먼저 가입한 순</li>
</ul>
</li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>정렬의 시간 복잡도는 O(NlogN)
N은 회원의 수로, 최대 100,000</p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>정렬</p>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input 받기</li>
<li>배열을 1열을 기준으로 1열의 값이 같을 경우 입력 순서 유지되도록 정렬<blockquote>
<p>arr.sort(key=lambda x: (x[0]))</p>
</blockquote>
</li>
<li>정렬한 배열을 출력</li>
</ol>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h3 id="1회차">1회차</h3>
<ul>
<li>python 문법이 많이 부족하다..</li>
<li>2차원 배열과 같은 자료형</li>
</ul>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">import sys

# 1. 문제의 입출력을 받습니다.
N = int(sys.stdin.readline())
arr = []
for _ in range(N):
    age, name = sys.stdin.readline().split()
    arr.append([int(age), name])

# 2. 2차원 배열을 정렬합니다. 이 때 1열의 값이 같을 경우, 2열의 정렬 순서는 배열의 원래 순서 유지
arr.sort(key=lambda x: (x[0]))
for i in arr:
    print(i[0], i[1])

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[시간복잡도]]></title>
            <link>https://velog.io/@choi_sujin/%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84</link>
            <guid>https://velog.io/@choi_sujin/%EC%8B%9C%EA%B0%84%EB%B3%B5%EC%9E%A1%EB%8F%84</guid>
            <pubDate>Mon, 09 Sep 2024 10:41:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>빅-오메가 : 최선일 때</li>
</ul>
</blockquote>
<ul>
<li>빅-세타 : 보통일 때</li>
<li>📍 빅-오 O(n) : 최악일 때</li>
</ul>
<pre><code class="language-python">import random
findNumber = random.randrange(1,101) # 1~100 사이 랜덤값 생성

for i in range(1, 101):
    if i == findNumber:
        print(i)
        break
# 빅-오메가 : 시간복잡도 1번
# 빅-세타 : 시간복잡도 N/2번 = 50번
# 빅-오 : 시간복잡도 N번 = 100번</code></pre>
<p>코딩테스트에서는 <strong>빅-오 표기법(O(n))</strong> 기준으로 수행 시간 계산하는 것이 좋다.</p>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/13a467e3-b65f-4fa1-b509-8388e0970885/image.png" alt=""></p>
<h2 id="빅-오-표기법-on">빅-오 표기법 O(n)</h2>
<h3 id="수-정렬하기-예제">수 정렬하기 예제</h3>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/91e296e0-9301-4238-b45c-b29b8187a87a/image.png" alt=""></p>
<ul>
<li><strong>데이터의 크기</strong>와 <strong>시간 제한</strong> 항상 고려!</li>
<li>1 &lt;= N &lt;=** 1,000,000**</li>
<li>최악의 케이스를 고려해야 하기 때문에 <ul>
<li>데이터 크기(N)는 1,000,000값</li>
<li>시간 제한은 1초에 2,000만번이므로, 2초에 40,000,000 번 이하의 연산 횟수로 문제 해야해야 함</li>
</ul>
</li>
<li>즉, 연산 횟수 = 알고리즘 시간 복잡도 n값에 데이터의 최대 크기를 대입하여 도출</li>
<li>코딩테스트에서는 약 2,000만 번 ~ 1억 번의 연산이 대략 1초 정도 걸리나 최악의 케이스로 2,000만 번으로 기준!</li>
</ul>
<h4 id="시간복잡도-예제">시간복잡도 예제</h4>
<ul>
<li>버블 정렬 시간복잡도 공식 = O(N제곱)
  = 1,000,000 * 1,000,000 = 1,000,000,000,000 &gt; 40,000,000 =&gt; 부적합 알고리즘</li>
<li>병합 정렬 시간복잡도 공식 = O(nlogn)
  = 1,000,000 * log2(1,000,000) = 약 20,000,000 &lt; 40,000,000 =&gt; 적합 알고리즘
  ** log2(1,000,000) = 20    </li>
</ul>
<blockquote>
<p>연산 횟수는 1초에 2,000만 번 기준
시간 복잡도는 항상 최악, 즉 데이터의 크기가 가장 클 때를 기준</p>
</blockquote>
<h3 id="시간-복잡도-도출-기준">시간 복잡도 도출 기준</h3>
<ol>
<li>상수는 시간 복잡도 계산에 제외한다.</li>
</ol>
<ul>
<li>연산 횟수 = N<pre><code class="language-python">N = 100000
cnt = 1
</code></pre>
</li>
</ul>
<p>for i in range(N):
    print(&quot;연산횟수&quot; + str(cnt))
    cnt += 1</p>
<pre><code>- 연산 횟수 = 3N
```python
N = 100000
cnt = 1

for i in range(N):
    print(&quot;연산횟수&quot; + str(cnt))
    cnt += 1

for i in range(N):
    print(&quot;연산횟수&quot; + str(cnt))
    cnt += 1

for i in range(N):
    print(&quot;연산횟수&quot; + str(cnt))
    cnt += 1</code></pre><p>위 두 코드는 같은 시간복잡도를 갖는다.
3N의 상수인 3을 무시하는 O(n)으로 같다.</p>
<ol start="2">
<li>가장 많이 <strong>중첩된 반복문</strong>의 수행 횟수가 시간 복잡도의 기준이 된다.</li>
</ol>
<ul>
<li>연산 횟수 = N2(제곱)<pre><code class="language-python">for i in range(N):
  for j in range(N):
      print(&quot;연산 횟수 &quot; + str(cnt))
      cnt += 1</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2309) 일곱난쟁이]]></title>
            <link>https://velog.io/@choi_sujin/%EC%9D%BC%EA%B3%B1%EB%82%9C%EC%9F%81%EC%9D%B4</link>
            <guid>https://velog.io/@choi_sujin/%EC%9D%BC%EA%B3%B1%EB%82%9C%EC%9F%81%EC%9D%B4</guid>
            <pubDate>Mon, 09 Sep 2024 09:27:14 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-문제-탐색하기">📌 문제 탐색하기</h2>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/01df23b8-5864-44f0-a797-31bc80648a6a/image.png" alt=""></p>
<ul>
<li>9명의 난쟁이 중 <strong>키의 합이 100이 되는 7명의 난쟁이</strong>를 구하는 문제</li>
<li>0 &lt; 키 &lt;= 100 자연수</li>
<li>출력은 키 합이 100인 난쟁이 7명 조합 아무거나 단, 오름차순 정렬 </li>
</ul>
<h4 id="가능한-시간복잡도">가능한 시간복잡도</h4>
<p>(이 부분은 조금 더 공부하겠습니다😭)</p>
<h4 id="알고리즘-선택">알고리즘 선택</h4>
<p>📍 해설지 참고</p>
<ul>
<li>브루트포스 알고리즘(완전탐색/전체탐색)</li>
<li>정렬</li>
</ul>
<h2 id="📌-코드-설계하기">📌 코드 설계하기</h2>
<ol>
<li>문제의 input 받아 변수에 저장 (list 사용)</li>
<li>9명의 난쟁이 중 7명의 난쟁이 선택 후 합이 100인지 확인 </li>
<li>합이 100이면 list 오름차순 정렬</li>
<li>출력</li>
</ol>
<p>📍 해설지 참고 후
2번 수정 -&gt; 9명의 난쟁이 중 제외할 2명 구해서 <strong>9명 키 합  - 제외할 2명 키 == 100</strong>인지 확인</p>
<h2 id="📌-시도-회차-수정-사항-optional">📌 시도 회차 수정 사항 (Optional)</h2>
<h3 id="1회차">1회차</h3>
<pre><code class="language-python">## 리스트
heights = []
for i in range(9):
    heights.append(int(input()))

total_sum = 0
for i in range(10):
   result = heights[i : i + 7]
   total_sum = sum(result)

   print(f&quot;i : {i} \n result : {result} \n sum : {total_sum}\n&quot;)

   if total_sum == 100:
     result.sort()
     print(result)</code></pre>
<ul>
<li>리스트에서 7명을 뽑아내 합을 구한 후 100이 넘는지 체크하는 로직으로 구성했다</li>
<li>print 해보니 i가 커질수록 끝값이 인덱스에서 벗어나서 리스트에 7개 미만으로 들어왔다..</li>
</ul>
<h3 id="2회차">2회차</h3>
<pre><code class="language-python">import itertools

## 리스트
heights = []
for i in range(9):
    heights.append(int(input()))

total_sum = 0
result = list(itertools.combinations(heights, 7))

for r in result:
    total_sum = sum(r)

    if total_sum == 100:
        sorted_r = sorted(r)
        print(sorted_r)
        break

</code></pre>
<ul>
<li>heights 리스트에서 7개의 모든 조합을 찾기 위해 구글링..</li>
</ul>
<blockquote>
<p>itertools.combinations(리스트, r):</p>
</blockquote>
<ul>
<li>이 함수는 주어진 리스트에서 r개의 요소를 뽑는 모든 조합을 반환</li>
<li>combinations 객체는 반복자(iterator)이기 때문에, 리스트로 변환하거나 for문으로 순회하여 사용!!!</li>
<li>import itertools 필요</li>
</ul>
<blockquote>
<p>r.sort()는 튜플에서는 사용할 수 없기 때문에 sorted()로 처리!!</p>
</blockquote>
<h3 id="3회차">3회차</h3>
<p>📍 해설지 참고</p>
<ul>
<li>9명의 난쟁이 중 7명을 선택(완전 탐색)하는 것이 아니라, <strong>9명의 난쟁이 중 제외할 2명의 난쟁이를 선택</strong><ul>
<li>생각의 전환 필요!!!</li>
</ul>
</li>
<li>2명의 난쟁이를 따로 뽑을 필요없이, 이중 for문으로 제외한 두명의 키를 9명 전체 합에서 뺐을 때, 100을 만족하는지 확인</li>
</ul>
<blockquote>
<p><strong>완전 탐색</strong>은 input의 크기가 유난히 작으면서 모든 경우의 수를 탐색하는 코드 구현이 가능할 경우에!
모든 경우의 수를 빠뜨리지 않고 탐색할 수 있게 구현하는 것이 중요</p>
</blockquote>
<h2 id="📌-정답-코드">📌 정답 코드</h2>
<pre><code class="language-python">import sys 
def print_result(arr, a, b):
    for i in range(9):
        if i == a or i == b:
            continue
        print(arr[i])

# 1. input 받기
heights = []
for i in range(9):
    heights.append(int(sys.stdin.readline())) # import sys 필요
    # heights.append(int(input()))

# 2. 아홉 난쟁이 키의 합 미리 구해두기
total_sum = sum(heights)
# 3. 미리 정렬
heights.sort()

# 4. 9명 중 2명을 제외하는 모든 경우의 수를 탐색하는 for loop 구현
found = False
for i in range(9):
    if found:
        break
    for j in range(i + 1, 9):
        # 5. 제외된 2명을 빼고 총 합이 100인지 확인
        now = total_sum - heights[i] - heights[j]

        # 6. 100이면 출력, for loop 탈출  
        if now == 100:
            print_result(heights, i, j)
            found = True
            break</code></pre>
<blockquote>
<p>sys.stdin.readline()을 왜 사용하나요?
→ 빠른 입출력을 위해 사용합니다. input()과 정확히 동일한 역할을 하지만 더 빠른 입출력을 지원!</p>
</blockquote>
<h2 id="📌-부족한-점">📌 부족한 점</h2>
<ul>
<li>알고리즘 기법에 대한 이해가 없어서 설계가 너무 부족하다..</li>
<li><strong>완전탐색(브루트 포스) 이론 공부하고 관련 문제 3개 더 풀자</strong></li>
<li>문제를 보는 시선의 전환 또한 필요하다.. 이것도 많이 풀어보면 늘겠지...?</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL) Mac m2 설치 및 시작]]></title>
            <link>https://velog.io/@choi_sujin/MySQL-Mac-m2-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@choi_sujin/MySQL-Mac-m2-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Mon, 17 Jul 2023 06:41:10 GMT</pubDate>
            <description><![CDATA[<h2 id="1-homebrew-설치">1. homebrew 설치</h2>
<p>설치 후,
터미널에 brew -v 명령어를 입력하여 버전 정보가 나오면 된다.</p>
<pre><code>&gt; brew -v
Homebrew 4.0.24</code></pre><h2 id="2-mysql-설치">2. MySQL 설치</h2>
<pre><code>$ brew install mysql</code></pre><ul>
<li>MySQL 시작</li>
</ul>
<pre><code>$ mysql.server start</code></pre><ul>
<li>MySQL 시작 후 기본 설정</li>
</ul>
<pre><code>$ mysql_secure_installation</code></pre><p>순서대로 아래 질문들이 나오면 y 또는 n을 입력하여 설정해 준다.</p>
<blockquote>
<ol>
<li>비밀번호 복잡도 검사 과정 (n)</li>
<li>비밀번호 입력 &amp; 확인</li>
<li>익명 사용자 삭제 (y)</li>
<li>원격 접속 허용하지 않을 것인가? (y)</li>
<li>test DB 삭제 (n)</li>
<li>previlege 테이블을 다시 로드할 것인지 (y)</li>
</ol>
<p>-&gt; 설정을 마치면 All done! 메세지가 출력됩니다.</p>
</blockquote>
<h2 id="3-사용하기">3. 사용하기</h2>
<p>bash에 다음 명령어를 입력하면 MySQL을 사용할 수 있다.</p>
<pre><code>$ mysql -u root -p 
또는
$ mysql -u root -p비밀번호 -&gt; 바로 접속</code></pre><h2 id="추가설정">추가설정</h2>
<p>MySQL 서버가 재부팅 상관없이 켜져있게 한다. (bash에 입력)</p>
<pre><code>$ brew services start mysql</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL) DBMS 기초]]></title>
            <link>https://velog.io/@choi_sujin/MySQL-DBMS-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@choi_sujin/MySQL-DBMS-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Mon, 17 Jul 2023 06:33:34 GMT</pubDate>
            <description><![CDATA[<h2 id="dbms-data-base-management-system">DBMS (Data Base Management System)</h2>
<ul>
<li>데이터베이스(DB)를 관리하는 시스템<ul>
<li>DB : 테이블들이 모여 이루는 데이터 단위</li>
</ul>
</li>
<li>데이터를 저장하고 유지보수(수정,삭제,추가)하고 이를 검색하는 시스템<ul>
<li>CRUD</li>
</ul>
</li>
<li>대량의 데이터를 처리하는 시스템</li>
<li>다양한 자료구조와 검색구조(정렬, 인덱싱, …) 사용해 빠른 검색 가능</li>
<li>대부분의 시스템은 R(검색) &gt;&gt;&gt;&gt;&gt; CUD(업데이트)의 빈도수가 많음</li>
<li><strong>검색에 최적화</strong><ul>
<li>쓰기에 최적화된 시스템은 NoSQL 계열</li>
</ul>
</li>
</ul>
<h3 id="rdbms-관계형-데이터베이스-시스템">RDBMS 관계형 데이터베이스 시스템</h3>
<ul>
<li><p>테이블 기반의 DBMS</p>
<ul>
<li>테이블/컬럼 형태의 데이터 저장 방식<ul>
<li>하나의 테이블은 여러 개의 컬럼으로 구성</li>
</ul>
</li>
<li>테이블과 테이블 간의 연관관계(주로 외래키 형태)를 이용해 필요한 정보를 구하는 방식</li>
<li>테이블끼리의 중복정보는 최소화 → 정규화</li>
</ul>
</li>
<li><p>모델링은 E-R(Entity Relationship) 모델을 사용</p>
</li>
<li><p>테이블을 엔티티(기본)와 릴레이션 테이블로 구분하는 방식</p>
</li>
<li><p>데이터의 검색을 빠르게 하기 위해서 데이터를 변경(추가/업데이트/삭제)할 때 인덱스를 미리 만들어서 데이터의 검색을 빨리 되도록 함</p>
</li>
<li><p>하지만, 데이터의 변경이 많을 경우에는 인덱스 때문에 오히려 성능이 떨어지기도 한다</p>
</li>
</ul>
<h3 id="정렬">정렬</h3>
<ul>
<li>빠른 검색을 위해서는 데이터가 반드시 정렬(Sorting)되어 있어야 함</li>
<li>정렬 되어 있지 않다면 평균적으로 전체 데이터의 절반 필요<ul>
<li>최선 : 1, 최악 : N, 평균 : N/2</li>
</ul>
</li>
<li>정렬되어 있을 경우 데이터를 빠른 시간 안에 찾을 수 있음<ul>
<li>O(NlogN)-O(N2)</li>
</ul>
</li>
<li>퀵정렬/힙정렬 계열이 주로 사용됨</li>
</ul>
<h3 id="인덱스">인덱스</h3>
<ul>
<li>이진검색(Binary Search)<ul>
<li>최대 log2(N)번 내에 검색 가능</li>
<li>데이터를 정렬 후 “test” 단어를 검색하는 경우<ul>
<li>한가운데 값을 확인 → “sample” → 뒤쪽 절반</li>
<li>뒤쪽 중 한가운데 확인 → “yield” → 앞쪽 절반</li>
<li>계속 반복해 “test” 단어가 나올 때까지 계속</li>
</ul>
</li>
</ul>
</li>
<li>🌟 B-Tree 계열 → DBMS의 인덱스 기본!<ul>
<li>사용 DBMS에서 가장 일반적으로 많이 사용됨</li>
<li>이진 검색과 유사하지만 한 번에 비교를 2번 (a,b : a &lt;b)<ul>
<li>작은 값보다 작은 경우 ( x &lt; a )</li>
<li>큰 값과 작은 값 사이인 경우 ( a &lt; x &lt; b )</li>
<li>큰 값보다 큰 경우 ( x &gt; b )</li>
<li>B-트리 계열이 이진검색 계열보다 빠름</li>
<li>데이터가 추가/삭제/변경 될 때마다 a,b 값을 업데이트</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>⇒ 데이터 추가/수정/삭제할 때마다 정렬/인덱스 업데이트가 일어남</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[03. Docker 이미지 관리]]></title>
            <link>https://velog.io/@choi_sujin/03.-Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@choi_sujin/03.-Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Thu, 25 May 2023 01:21:05 GMT</pubDate>
            <description><![CDATA[<h2 id="☑️-도커-이미지-생성-방법">☑️ 도커 이미지 생성 방법</h2>
<ol>
<li><p>기존 이미지로 컨테이너 생성 후 작업 완료된 컨테이너를 다시 이미지로 생성
<img src="https://velog.velcdn.com/images/choi_sujin/post/317ba56f-924a-4386-92ca-9f435fa1a250/image.png" alt=""></p>
</li>
<li><p>Dockerfile로 필요한 패키지, 소스코드, 명령어 등을 작성 후 빌드
<img src="https://velog.velcdn.com/images/choi_sujin/post/eadfc644-e325-46b1-b5f4-bafa41e65c35/image.png" alt=""></p>
</li>
</ol>
<h2 id="📄-dockerfile">📄 Dockerfile</h2>
<ul>
<li>도커 이미지를 생성할 수 있는 설정 파일</li>
<li>사용자가 이미지를 조합하기 위해 명령줄에서 호출할 수 있는 모든 명령을 포함하는 텍스트 문서</li>
<li>완성된 이미지를 생성하기 위해 필요한 컨테이너, 패키지, 소스코드, 명령어 등을 하나의 파일에 기록</li>
<li>도커에서 이 파일을 읽어 자동으로 작업을 수행한 뒤 완성된 이미지로 만들어 줌</li>
<li>깃과 같은 개발도구를 통해 애플리케이션의 빌드 및 배포를 자동화 할 수 있음</li>
</ul>
<blockquote>
<p>📍 Dockerfile 작성</p>
</blockquote>
<ul>
<li>컨테이너에서 수행해야 할 작업을 명시</li>
<li>정해진 형식과 명령어로 작성해야 함</li>
<li>문서 파일로 작성</li>
<li>한 줄에 하나의 명령어로 구성</li>
<li>명령어를 명시하고 뒤에 옵션을 추가</li>
<li>명령어는 대/소문자 상관없음(일반적으로 대문자로 표기)</li>
<li>위에서 아래로 한 줄씩 차례대로 실행됨</li>
<li>주석은 #기호를 사용</li>
</ul>
<h3 id="🌟-dockerfile-명령어">🌟 Dockerfile 명령어</h3>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/5f7b7321-5d2e-43be-bf32-8f156204228d/image.png" alt=""><img src="https://velog.velcdn.com/images/choi_sujin/post/fb2f774d-51cd-4e00-93b6-d84af0d62c2c/image.png" alt="">
ex) </p>
<pre><code># 베이스 이미지를 tomcat:9.0.75-jdk11로 지정
FROM tomcat:9.0.75-jdk11
# 작성자 라벨 생성
LABEL maintainer &quot;kh&lt;kh@iei.com&gt;&quot;
# 버전 라벨 생성
LABEL version=&quot;1.0&quot;
# /usr/local/tomcat/webapps 디렉터리에 ROOT.war 파일 추가
ADD ROOT.war /usr/local/tomcat/webapps
# Timezone 환경변수를 Asia/Seoul로 변경
ENV TZ=Asia/Seoul
# 이미지에서 8080포트 사용
EXPOSE 8080
# 컨테이너 실행 시 catalina.sh 파일 자동 실행
CMD [&quot;catalina.sh&quot;,&quot;run&quot;]
</code></pre><h3 id="🌟-dockerfile-빌드">🌟 Dockerfile 빌드</h3>
<p>작성한 Dockerfile을 이용해 이미지를 생성하는 과정</p>
<pre><code>docker build [옵션] &lt;Dockerfile이 존재하는 디렉터리 경로&gt;
docker build . -f Dockerfile.txt -t mytomcat:1.0</code></pre><p><img src="https://velog.velcdn.com/images/choi_sujin/post/3a26874c-5015-4a76-871b-05a80bcf89a5/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[02. Docker 실습]]></title>
            <link>https://velog.io/@choi_sujin/docker-%EC%8B%A4%EC%8A%B5</link>
            <guid>https://velog.io/@choi_sujin/docker-%EC%8B%A4%EC%8A%B5</guid>
            <pubDate>Wed, 24 May 2023 01:48:31 GMT</pubDate>
            <description><![CDATA[<p>맥북 유저인 나는 이미 colima와 docker를 사용해서 oracle db를 사용하고 있었는데, 사실 알고 설치했다기보다는 써야해서 서치서치하면서 설치 거라 docker에 대한 이해는 거의 없다고 봐도 무방했다.. 그래서 이번 수업을 통해 docker에 대해 열심히 공부했는데 수업은 윈도우 위주라 mac 유저인 나는 수업을 바탕으로 다시 찾아봐야 했다..</p>
<p>수업을 하면서 gui docker desktop으로 컨테이너나 이미지를 확인하는데 이미 설치되어있던 oracle이 컨테이너에 뜨지 않는 것이다.. 하지만 DB는 잘 작동하고 cli로 docker ps로 확인해봐도 잘 작동하고 있었다. 그래서 찾아본 결과 docker context가 colima, desktop-linux, default로 3개이고 내가 설치한 oracle은 colima에 설치되어 있었고, desktop-linux가 docker desktop 부분인 것 같았다. (그럼 여기서 default는..??)</p>
<p>mac은 colima를 이용해서 이미지를 x86_64로 바꿔 ORACLE을 돌려야 한다는 걸 알았지만, 혹시나 하는 마음에 docker desktop에서 설치해보았다.</p>
<pre><code>docker run -d --name mydb -p 40000:1521 -e TZ=Asia/Seoul oracleinanutshell/oracle-xe-11g

docker ps -a

docker cp /Users/sujinchoi/mydb.sql mydb:/root

docker exec -it mydb bash

→ root@48ddec31a221:/# ls

→ root@48ddec31a221:/# ls / root

→ root@48ddec31a221:/# sqlplus sys/oracle as sysdba @/root/mydb.sql

docker run -d --name myweb -p 80:8080 -e TZ=Asia/Seoul --link mydb:db tomcat:9.0.75-jdk11

docker cp /Users/sujinchoi/ROOT.war myweb:/usr/local/tomcat/webapps

docker restart myweb</code></pre><p>sql에서 넘어가지지 않는다.<img src="https://velog.velcdn.com/images/choi_sujin/post/b5b3b35f-8b2c-4227-a56a-b6eedb116b88/image.png" alt=""></p>
<p>안되는 걸 알았지만 이렇게 어떤 과정에서 안되는지 확인해보니 좋았다. 게다가 docker를 공부하는 과정에서 docker desktop gui로 확인하면서 파일이 제대로 복사되었는지 확인할 수 있어서 좋았는데,,, 앞으로 수업 실습을 할 때는 colima 상에서 돌려야 하기 때문에 확인을 할 수 없을 부분이 막막하다..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[01. Docker 기초]]></title>
            <link>https://velog.io/@choi_sujin/docker</link>
            <guid>https://velog.io/@choi_sujin/docker</guid>
            <pubDate>Mon, 22 May 2023 00:45:20 GMT</pubDate>
            <description><![CDATA[<h2 id="🐳-도커docker란">🐳 도커(Docker)란?</h2>
<ul>
<li>애플리케이션을 개발/배포/실행하기 위한 플랫폼!</li>
<li>컨테이너를 사용하여 애플리케이션 및 지원 구성 요소를 개발</li>
<li>리눅스 자체 기능을 사용하여 프로세스 단위의 격리 환경을 제공</li>
<li>배포 용량과 시간을 단축하고, 성능 손실을 최소화시킴</li>
</ul>
<h3 id="도커-엔진">도커 엔진</h3>
<ul>
<li>외부에서 Docker API 요청을 받아 Docker 객체와 서비스들을 관리</li>
<li>컨테이너를 생성하고 관리하는 주체</li>
<li>도커 데몬(demon) : 도커 프로세스가 실행되어 입력받을 준비가 된 상태</li>
<li>도커 클라이언트 : 입력된 명령어를 Docker API 형태로 도커 데몬에게 전달 (-&gt; 도커 엔진의 수행 결과를 반환받아 사용자에게 출력)</li>
<li>도커 레지스트리(Registry): 도커에서 사용되는 이미지들을 저장하고 공유해주는 원격 저장소</li>
</ul>
<h2 id="☑️-도커-이미지-관리">☑️ 도커 이미지 관리</h2>
<h3 id="🌟-도커-이미지">🌟 도커 이미지</h3>
<ul>
<li>컨테이너를 만들고 실행하기 위한 읽기 전용 파일(템플릿)</li>
<li>모든 컨테이너는 이미지 기반으로 생성됨</li>
<li>컨테이너 실행에 필요한 파일과 설정 값 등을 포함하고 있음</li>
</ul>
<blockquote>
<p> &lt;검색 방법&gt;</p>
</blockquote>
<ol>
<li><a href="https://hub.docker.com/">도커 허브</a>에서 이미지 검색</li>
<li>📍 docker search &lt;키워드&gt;</li>
</ol>
<blockquote>
<p>&lt;이미지 다운로드&gt;
📍 docker pull [저장소이름/]&lt;이미지이름&gt;[:태그]
ex) docker pull tomcat:9.0 </p>
</blockquote>
<ul>
<li>저장소 이름 생략 시 도커 허브 공식 이미지로 인식</li>
<li>태그는 버전을 나타냄 (생략시 최신 버전 latest 으로 인식)</li>
</ul>
<h3 id="🌟-도커-이미지와-컨테이너">🌟 도커 이미지와 컨테이너</h3>
<ul>
<li>컨테이너는 필요한 파일과 설정을 이미지에서 읽기전용으로 가져다 사용하고, 변경된 사항만 컨테이너 계층에 별도 저장</li>
<li>하나의 이미지로 여러 컨테이너에서 사용 가능</li>
</ul>
<p><img src="https://velog.velcdn.com/images/choi_sujin/post/d799f77a-1073-4557-93b7-f3c607f7292f/image.png" alt=""></p>
<blockquote>
<ul>
<li>다운받은 이미지 목록 조회
📍 docker images</li>
</ul>
</blockquote>
<ul>
<li>이미지 세부 정보 조회
📍 docker image insepect &lt;이미지 ID&gt;</li>
</ul>
<blockquote>
<ul>
<li>도커 이미지 추출 : 도커 이미지를 별도의 파일로 저장할 때 사용
📍 docker save -o &lt;파일명&gt; &lt;이미지명&gt;[:태그]
ex) docker save -o /Users/sujinchoi/tomcat_image tomcat:9.0</li>
</ul>
</blockquote>
<ul>
<li>도커 이미지 로드 : 추출된 파일을 다시 도커 내 이미지로 로드
📍 docker load -i &lt;파일명&gt;
ex) docker load -i /Users/sujinchoi/tomcat_image</li>
<li>도커 이미지 이름 추가 : 기존 이미지를 새로운 이름으로 추가
📍 docker tag [기존저장소/]&lt;기존이미지명&gt;[:기존태그] [새로운저장소/]&lt;새로운이미지명&gt;[:새로운태그]
ex) docker tag tomcat:9.0 mytom:1</li>
<li><blockquote>
<p>IMAGE ID는 같고 이름만 다른 이미지 추가됨</p>
</blockquote>
</li>
</ul>
<blockquote>
<ul>
<li>도커 이미지 삭제
📍 docker rmi &lt;이미지이름:태그 or IMAGE ID&gt;
ex) docker rmi mytom:1 -&gt; 이름 추가(tag)된 이미지가 있으면 이미지는 삭제되지 않고 이름만 제거(untag) 됨
docker rmi tomcat:9.0 -&gt; 이미지 삭제 </li>
</ul>
</blockquote>
<h2 id="☑️-도커-컨테이너-관리">☑️ 도커 컨테이너 관리</h2>
<h3 id="🌟-도커-컨테이너">🌟 도커 컨테이너</h3>
<ul>
<li>도커 이미지의 실행 가능한 인스턴스</li>
<li>개별 애플리케이션의 실행에 필요한 실행환경을 독립적으로 운용</li>
</ul>
<blockquote>
<ul>
<li>컨테이너 생성
📍 docker run [옵션] [저장소이름/] &lt;이미지이름&gt;[:버전]
ex) docker run -d --name myweb -p 80:8080 tomcat:9.0.75-jdk11
다운받은 이미지가 없는 경우 자동으로 다운받아서 생성됨</li>
<li><blockquote>
<p>이미지 다운로드(pull) + 컨테이너 생성(create) + 실행(start) + 접속(attach)까지 한번에 수행
<img src="https://velog.velcdn.com/images/choi_sujin/post/649eafd8-3940-446b-808b-4234f1d5a8e8/image.png" alt=""></p>
</blockquote>
</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>컨테이너 확인
📍 docker ps [옵션]
ex) docker ps -a : 전체 컨테이너 확인</li>
</ul>
</blockquote>
<ul>
<li>컨테이너 상세 내용 조회
📍 docker inspect &lt;컨테이너 이름 or ID&gt;
ex) docker inspect myweb</li>
<li>컨테이너로 파일 복사
📍 docker cp [옵션] &lt;원본파일경로&gt; &lt;복사할 경로&gt; </li>
<li><blockquote>
<p>경로가 컨테이너 내부일 경우 &lt;컨테이너명:켱로&gt;로 지정
ex) docker cp /Users/sujinchoi/test.txt myweb:/root</p>
</blockquote>
</li>
</ul>
<blockquote>
<ul>
<li>컨테이너 실행/종료
📍 docker start/stop/restart &lt;컨테이너 이름 or ID&gt;</li>
</ul>
</blockquote>
<blockquote>
<p>컨테이너 명령어 실행
📍 docker exec [옵션] &lt;컨테이너이름 or ID&gt; &lt;명령어&gt;
ex) docker exec -it myweb /bin/bash</p>
</blockquote>
<ul>
<li>쉘을 실행하면 컨테이너에 접근 가능</li>
<li>쉘 접근 후 다양한 명령어 사용 가능(종료시 exit)</li>
</ul>
<blockquote>
<p>컨테이너 삭제
📍 docker rm [옵션] &lt;컨테이너이름 or ID&gt; [컨테이너 이름 or ID ...]
ex) docker rm -f myweb</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[09. Spring AOP(Aspect Oriented Programming)]]></title>
            <link>https://velog.io/@choi_sujin/AOP</link>
            <guid>https://velog.io/@choi_sujin/AOP</guid>
            <pubDate>Fri, 12 May 2023 04:50:40 GMT</pubDate>
            <description><![CDATA[<h3 id="spring-aop란-">Spring AOP란 ?</h3>
<ul>
<li>관점 지향 프로그래밍(Aspect Oriented Programming)</li>
<li>일반적으로 사용하는 클래스(Service, DAO 등)에서 중복되는 공통 코드 부분(commit, rollback, log 처리)을 별도의 영역으로 분히</li>
<li>소스 코드의 중복을 줄이고 필요할 때마다 가져다 쓸 수 있게 객체화하는 기술</li>
<li>횡단 관점</li>
</ul>
<blockquote>
<p>&lt;용어 정리&gt;
☑️ Advice : 공통되는 부분을 따로 빼내어 작성한 메소드
☑️ JoinPoint : Advice가 적용될 수 있는 모든 관점(시점, 메소드)
☑️ Pointcut : JoinPoint 중 실제 Advice를 적용할 부분
☑️ Aspect : Advice + Pointcut 
☑️ Weaving : 그 시점에 공통 코드를 끼워 넣는 작업</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[08. Logging]]></title>
            <link>https://velog.io/@choi_sujin/logging</link>
            <guid>https://velog.io/@choi_sujin/logging</guid>
            <pubDate>Fri, 12 May 2023 04:50:25 GMT</pubDate>
            <description><![CDATA[<h2 id="로그log란">로그(log)란?</h2>
<p>기록을 남기는 것 !!!</p>
<h3 id="logging-framework-log4j--logback--slf4j">Logging Framework (log4j / logback / slf4j)</h3>
<p>스프링 프로젝트에는 기본적으로 log4j 라이브러리가 추가되어있고
log4j와 관련된 설정을 담는 log4j.xml 파일을 서버 구동과 동시에 로딩하게 되어 있음</p>
<p>하지만, log4j를 이용하여 많은 양의 로그를 출력하는 경우 성능 저하가 심하다.
그래서 최근에는 logback 이라는 라이브러리를 사용한다(-&gt; 10배 빠름)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[07. Spring DI]]></title>
            <link>https://velog.io/@choi_sujin/Spring-DI</link>
            <guid>https://velog.io/@choi_sujin/Spring-DI</guid>
            <pubDate>Wed, 03 May 2023 01:28:45 GMT</pubDate>
            <description><![CDATA[<h3 id="☑️-spring-annotation-종류">☑️ Spring Annotation 종류</h3>
<p>📍 Bean 등록 시 사용
@Component : 객체(컴포넌트)를 나타내는 일반적인 타입으로 &lt;\bean&gt; 태그와 동일한 역할
@Repository : 퍼시스턴스(persistence) 레이어, 영속성을 가지는 속성(파일, 데이터베이스)를 가진 클래스
@Service : 서비스 레이어, 비즈니스 로직을 가진 클래스
@Controller : 프리젠테이션 레이어, 웹 애플리케이션에서 View에서 전달된 웹 요청과 응답을 처리하는 클래스</p>
<p>=&gt; @Repository, @Service, @Controller는 특정한 객체의 역할에 대한 @Controller의 구체화 형태!</p>
<p>📍 의존성 주입 시 사용
  @Autowired </p>
<ul>
<li>정밀한 의존 관계 주입(DI)이 필요한 경우에 유용하다.</li>
<li>@Autowired는 필드 변수, setter 메소드, 생성자, 일반 메소드에 적용 가능하다.</li>
<li>의존하는 객체를 주입할 때 주로 Type을 이용하게 된다.</li>
<li>@Autowired는 &lt;\property&gt;, &lt;\constructor-arg&gt; 태그와 동일한 역할을 한다.</li>
<li>@Qualifier : @Autowired와 함께 쓰이며, 한 프로젝트 내에 @Autowired로 의존성을 
주입하고자 하는 객체가 여러개 있을 경우, @Qualifier(“name”)를 통해 원하는 객체를 지정하여 주입할 수 있다. </li>
</ul>
<p>@Resource</p>
<ul>
<li>애플리케이션에서 필요로 하는 자원을 자동 연결할 때 사용된다.</li>
<li>@Resource는 프로퍼티, setter 메소드에 적용 가능하다.</li>
<li>의존하는 객체를 주입할 때 주로 Name을 이용하게 된다. </li>
</ul>
<p>@Value</p>
<ul>
<li>단순한 값을 주입할 때 사용되는 어노테이션</li>
<li>@Value(&#39;Spring&#39;)은 &lt;property ... value=&#39;Spring&#39;/&gt;과 동일한 역할</li>
</ul>
<blockquote>
<p> @Autowired와 @Resource 어노테이션</p>
</blockquote>
<ul>
<li>공통점 : @Component로 의존관계를 설정한 객체로부터 의존 관계를 자동으로 주입</li>
<li>차이점 : @Autowired는 타입으로, @Resource는 이름으로 연결</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[06. Redirect vs Forward]]></title>
            <link>https://velog.io/@choi_sujin/06.-Redirect-vs-Forward</link>
            <guid>https://velog.io/@choi_sujin/06.-Redirect-vs-Forward</guid>
            <pubDate>Fri, 28 Apr 2023 06:15:54 GMT</pubDate>
            <description><![CDATA[<p>JSP환경에서 현재 작업중인 페이지에서 다른 페이지로 이동하는 두가지 방식의 페이지 전환 기능!!</p>
<table>
  <tr>
    <th></th>
    <th style="width:230px">리다이렉트 Redirect</th>
    <th style="width:230px;">포워드 Forward</th>
  </tr>
  <tr>
    <td>페이지 전환 주체</td>
    <td style="text-align: center">클라이언트</td>
    <td style="text-align: center">서버</td>
  </tr>
  <tr>
       <td>URL의 변화 여부</td>
    <td style="text-align: center">변화 O</td>
    <td style="text-align: center">변화 X</td>
  </tr>
  <tr>
       <td>객체의 재사용 여부</td>
    <td style="text-align: center">재사용 X</td>
    <td style="text-align: center">재사용 O</td>
  </tr>
</table>

<h2 id="🔅-redirect-리다이렉트">🔅 Redirect 리다이렉트</h2>
<p>: 서버에서 클라이언트에서 요청한 URL에 대한 응답에서 다른 URL로 재접속하라고 명령을 보내는 것 (Re-Direct -&gt; URL을 다시 가리킨다)
즉, 클라이언트는 해당 URL로 다시 요청! 리다이렉트가 일어나면 URL 주소가 바뀌면서 다시 접속되는 것을 확인할 수 있어, 클라이언트 또한 리다이렉션이 일어났음을 알 수 있다.</p>
<p>** 클라이언트 : 웹브라우저 </p>
<ul>
<li>페이지 전환 주체가 클라이언트 : 접속한 URL이 아닌 다른 URL로 직접 접속하는 방법</li>
<li>사용자의 요청 정보가 바뀌어버림<blockquote>
<p>🌟⭐️ 
리다이렉트는 클라이언트의 요청에 의해 서버의 DB에 변화가 생기는 작업에 사용된다!!!(로그인, 회원가입, 글쓰기) 예를 들어 DB 유저 테이블을 변경하는 회원가입과 같은 경우에는 리다이렉트가 사용되어야 요청을 중복해서 보내는 것을 방지할 수 있다.</p>
</blockquote>
</li>
</ul>
<h2 id="🔅-forward-포워드">🔅 Forward 포워드</h2>
<p>: 서버 내부에서 일어나는 호출 -&gt; 클라이언트의 URL에 대한 요청이 들어오면 해당 URL이 다른 URL로 포워딩 된 것이 확인되었을 경우 서버에서 포워딩된 URL의 리소스를 확인하여 클라이언트에 응답한다</p>
<ul>
<li>페이지 전환 주체가 서버 : URL 주소가 바뀌지 않고도 서버 내부의 동작을 통해 다른 응답을 클라이언트에 내려 줄 수 있다</li>
<li>요청 정보는 그대로 유지한 채 서버 내부의 동작만 바뀜</li>
<li>웹 브라우저에는 최초 호출한 URL만 표시되고, 이동한 페이지의 URL 정보는 볼 수가 없다.<blockquote>
<p>🌟⭐️
포워드는 특정 URL에 대해 외부에 공개되지 말아야 하는 부분을 가리는데 사용하거나 조회를 위해 사용된다!!!(리스트보기, 검색)
스프링의 경우, /WEB-INF에 있는 view에 대한 정보들이 외부에 직접 공개되지 말아야 할 때 내부에서 포워딩을 통해 /WEB-INF 경로를 가리키도록 한다. 예를 들어 sujin.com/96로 요청하면 sujin.com/WEB-INF/96을 응답하는 형식이다.</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>