<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>We have happy accidents</title>
        <link>https://velog.io/</link>
        <description>simple is best</description>
        <lastBuildDate>Sun, 02 Jun 2024 15:25:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>We have happy accidents</title>
            <url>https://velog.velcdn.com/images/juhee_bda/profile/f90f33da-fc53-477c-8de4-93f95ccc4068/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. We have happy accidents. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/juhee_bda" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[CS 공부] 좋은 코드란?]]></title>
            <link>https://velog.io/@juhee_bda/%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EB%9E%80</link>
            <guid>https://velog.io/@juhee_bda/%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EB%9E%80</guid>
            <pubDate>Sun, 02 Jun 2024 15:25:02 GMT</pubDate>
            <description><![CDATA[<h3 id="⎷-좋은-코드란-무엇인가">⎷ 좋은 코드란 무엇인가?</h3>
<h4 id="읽었을-때-이해하기-쉽다-가독성">읽었을 때 이해하기 쉽다. (가독성)</h4>
<ul>
<li>변수명, 함수명, 클래스명 등이 명확하고 직관적이어야 한다.</li>
<li>코드의 구조가 잘 정리되어 있어야 한다.</li>
<li>주석을 적절히 사용해서 코드의 의도를 설명한다. (과도한 주석 X)</li>
</ul>
<h4 id="유지보수가-쉽다">유지보수가 쉽다.</h4>
<ul>
<li>코드의 변경 및 확장이 용이해야 한다.</li>
<li>기능별로 나눠진(모듈화 된) 코드 구조는 수정이 용이하다.</li>
<li>코드의 의존성을 최소화하고, 재사용 가능한 모듈(중복 코드 제거 효과)을 작성해야 한다.<blockquote>
<p><strong>코드 의존성이란?</strong>
ex) A가 B를 이용하고 있다면, A는 B에게 의존하고 있는 것이다. A는 B없이 작동할 수 없다. B가 변하면 A도 영향을 받는다.</p>
</blockquote>
</li>
</ul>
<h4 id="성능-측면에서-효율적이다">성능 측면에서 효율적이다.</h4>
<ul>
<li>메모리 사용, 실행 시간 등을 고려하여 최적화된 알고리즘을 사용하는 것이 필요하다.</li>
<li><code>성능 최적화는 위의 가독성과 유지보수성을 해치지 않는 선에서 이뤄져야 한다.</code></li>
</ul>
<h4 id="테스트하기-쉬워야-한다">테스트하기 쉬워야 한다.</h4>
<ul>
<li>유닛 테스트, 통합 테스트 등을 통해서 코드의 기능을 테스트 할 수 있어야 하며, 테스트를 자동화할 수 있는 구조를 갖추는 것이 좋다.</li>
<li>코드의 신뢰성을 높이는데 도움이 된다.<blockquote>
<p><strong>테스트 종류</strong></p>
</blockquote>
<ul>
<li>유닛 테스트 (Unit Test)</li>
<li>통합 테스트 (Integration Test)</li>
<li>인수 테스트 (Acceptance Test)</li>
</ul>
</li>
</ul>
<h4 id="코딩-스타일-및-규칙이-일관되게-유지되어야-한다">코딩 스타일 및 규칙이 일관되게 유지되어야 한다.</h4>
<ul>
<li>규칙과 스타일을 정하고 이를 유지해야 팀원 간 협업이 원활하게 유지될 수 있다.</li>
</ul>
<h4 id="문서화">문서화</h4>
<ul>
<li>다른 개발자가 코드를 이해하고 사용하는 데 도움이 된다.</li>
<li>히스토리 관리에도 도움이 된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 케빈 베이컨의 6단계 법칙 (1389번)]]></title>
            <link>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EC%BC%80%EB%B9%88-%EB%B2%A0%EC%9D%B4%EC%BB%A8%EC%9D%98-6%EB%8B%A8%EA%B3%84-%EB%B2%95%EC%B9%99-1389%EB%B2%88</link>
            <guid>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EC%BC%80%EB%B9%88-%EB%B2%A0%EC%9D%B4%EC%BB%A8%EC%9D%98-6%EB%8B%A8%EA%B3%84-%EB%B2%95%EC%B9%99-1389%EB%B2%88</guid>
            <pubDate>Thu, 16 May 2024 09:19:25 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://www.acmicpc.net/problem/1389">https://www.acmicpc.net/problem/1389</a></p>
<br>

<p>python</p>
<pre><code class="language-python"># 모든 사람은 친구 관계로 연결되어져 있다.

import sys


def solution():
    for k in range(N):
        for i in range(N):
            for j in range(N):
                if graph[i][k] + graph[k][j] &lt; graph[i][j]:
                    graph[i][j] = graph[i][k] + graph[k][j]


if __name__ == &quot;__main__&quot;:
    INF = 1e6

    # N: 사람 수 / M: 친구 관계 수
    N, M = map(int, input().split())

    # 친구 연결 관계
    graph = [[INF] * N for _ in range(N)]
    for i in range(N):
        graph[i][i] = 0

    # 친구 연결 관계 초기 세팅
    for _ in range(M):
        a, b = map(int, sys.stdin.readline().split())
        a -= 1
        b -= 1

        graph[a][b] = 1
        graph[b][a] = 1

    # 최단 관계수 구하기
    solution()

    min_value = INF
    result = 0
    for idx, friend_info in enumerate(graph):
        sum_value = sum(friend_info)
        if sum_value &lt; min_value:
            min_value = sum_value
            result = idx

    print(result + 1)</code></pre>
<pre><code># input

100 132
1 2
1 3
2 4
3 4
4 5
4 6
5 7
6 7
7 8
7 9
8 10
9 10
10 11
10 12
11 13
12 13
13 14
13 15
14 16
15 16
16 17
16 18
17 19
18 19
19 20
19 21
20 22
21 22
22 23
22 24
23 25
24 25
25 26
25 27
26 28
27 28
28 29
28 30
29 31
30 31
31 32
31 33
32 34
33 34
34 35
34 36
35 37
36 37
37 38
37 39
38 40
39 40
40 41
40 42
41 43
42 43
43 44
43 45
44 46
45 46
46 47
46 48
47 49
48 49
49 50
49 51
50 52
51 52
52 53
52 54
53 55
54 55
55 56
55 57
56 58
57 58
58 59
58 60
59 61
60 61
61 62
61 63
62 64
63 64
64 65
64 66
65 67
66 67
67 68
67 69
68 70
69 70
70 71
70 72
71 73
72 73
73 74
73 75
74 76
75 76
76 77
76 78
77 79
78 79
79 80
79 81
80 82
81 82
82 83
82 84
83 85
84 85
85 86
85 87
86 88
87 88
88 89
88 90
89 91
90 91
91 92
91 93
92 94
93 94
94 95
94 96
95 97
96 97
97 98
97 99
98 100
99 100</code></pre><pre><code># output

49</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[python] 함수 인자가 가변 객체를 받는 경우]]></title>
            <link>https://velog.io/@juhee_bda/python-%ED%95%A8%EC%88%98-%EC%9D%B8%EC%9E%90%EA%B0%80-%EA%B0%80%EB%B3%80-%EA%B0%9D%EC%B2%B4%EB%A5%BC-%EB%B0%9B%EB%8A%94-%EA%B2%BD%EC%9A%B0</link>
            <guid>https://velog.io/@juhee_bda/python-%ED%95%A8%EC%88%98-%EC%9D%B8%EC%9E%90%EA%B0%80-%EA%B0%80%EB%B3%80-%EA%B0%9D%EC%B2%B4%EB%A5%BC-%EB%B0%9B%EB%8A%94-%EA%B2%BD%EC%9A%B0</guid>
            <pubDate>Thu, 16 May 2024 08:43:03 GMT</pubDate>
            <description><![CDATA[<h3 id="⎷-불변-객체-vs-가변-객체">⎷ 불변 객체 vs 가변 객체</h3>
<h4 id="불변-객체immutable-object-설명">불변 객체(<code>immutable object</code>) 설명</h4>
<ul>
<li><p>불변 객체란?
생성 후에는 내부 상태를 변경할 수 없는 객체이다.</p>
</li>
<li><p>종류:</p>
<ul>
<li>숫자형: int, float 등등</li>
<li>문자열: str</li>
<li>튜플: tuple</li>
<li>fronzenset</li>
</ul>
</li>
<li><p>예시:</p>
<pre><code class="language-python">a = 10
a = 20  # 새로운 객체를 할당, 이전 객체는 변경되지 않음

b = &quot;hello&quot;
b = &quot;world&quot;  # 새로운 문자열 객체가 생성되고 b가 이를 참조하게 됨

c = (1, 2, 3)
# c[0] = 10  # 튜플은 불변 객체이므로 변경 불가, 이는 에러를 발생시킴</code></pre>
<p>python의 <code>id</code> 함수는 객체의 주소를 반환한다. 처음 객체를 할당받을 때와 새로운 객체를 할당 받을때 id값을 확인해보면 각각 다른것을 확인할 수 있는데, 이는 내부 상태를 변경한 것이 아니라 다른 객체를 새로 참조한 것으로 보면 된다. (a를 예로 들면 10이라는 값 자체를 변경한 것이 아니라, 20 이라는 값으로 참조를 변경한 것을 보면 된다.)</p>
</li>
</ul>
<br>

<h4 id="가변-객체mutable-object-설명">가변 객체(<code>mutable object</code>) 설명</h4>
<ul>
<li><p>가변 객체란?
생성 후에도 내부 상태를 변경할 수 있는 객체이다.</p>
</li>
<li><p>종류:</p>
<ul>
<li>리스트: list</li>
<li>딕셔너리: dict</li>
<li>집합: set</li>
</ul>
</li>
<li><p>예시:</p>
<pre><code class="language-python">a = [1, 2, 3]
a[0] = 10  # 리스트의 첫 번째 요소를 10으로 변경

b = {&#39;key1&#39;: &#39;value1&#39;}
b[&#39;key2&#39;] = &#39;value2&#39;  # 딕셔너리에 새로운 키-값 쌍을 추가

c = {1, 2, 3}
c.add(4)  # 세트에 새로운 요소 추가</code></pre>
<p>수정 전과 후의 객체 id 값을 확인하면 동일하다. 이는 해당 객체의 내부 상태값을 변경한 것이다.</p>
</li>
</ul>
<hr>
<h3 id="⎷-함수-인자가-가변-객체를-받는-경우에-대하여">⎷ 함수 인자가 가변 객체를 받는 경우에 대하여</h3>
<h4 id="예시">예시:</h4>
<pre><code class="language-python">def solution(local_list):
    # 인자로 받은 가변 객체의 상태를 변경
    local_list[0] = 100


global_list = [1, 2, 3, 4, 5]
solution(global_list)</code></pre>
<p><code>global_list</code>를 호출할 경우 어떤 값이 나오는가?</p>
<pre><code class="language-python">print(global_list)

# 1) [1, 2, 3, 4, 5] 
# 2) [100, 2, 3, 4, 5]</code></pre>
<p>정답은 <code>2) [100, 2, 3, 4, 5]</code></p>
<br>

<h4 id="설명">설명:</h4>
<p>변경한 것은 로컬 변수인 local_list 인데, 왜 외부에 있는 global_list 변수가 영향을 받은 것인가? 이는, 함수의 인자로 가변 변수를 받았기 때문이다. </p>
<ul>
<li><p>참조에 의한 전달:</p>
<ul>
<li>파이썬에서 리스트와 같은 가변 객체는 함수의 인자로 전달될 때 <code>객체의 참조(reference)</code>가 전달된다. 즉, 함수 안에서 인자로 받은 리스트(=<code>local_list</code>)는 원래의 리스트(=<code>global_list</code>)를 가리킨다.</li>
</ul>
</li>
<li><p>참조를 통한 변경:</p>
<ul>
<li><code>solution(global_list)</code>를 호출하면 <code>global_list</code>의 참조가 solution 함수의 매개변수 <code>local_list</code>로 전달된다. 이로 인해 <code>global_list</code>와 <code>local_list</code>가 같은 리스트를 참조하게 되는 것이다. (id값 동일)</li>
<li>즉, <code>local_list[0] = 100</code> 으로 변경하는 것은 실제로 <code>global_list[0]</code>을 변경하는 것과 같다.</li>
</ul>
</li>
</ul>
<br>

<h4 id="요약">요약:</h4>
<p>파이썬의 리스트와 같은 가변 객체는 함수에 전달될 때 참조에 의해 전달되므로, 함수 내부에서 리스트의 요소를 변경하면 원래 리스트에도 그 변경이 반영된다.</p>
<br>

<h4 id="인자로-받은-원래의-리스트를-변경하지-않고-새로운-리스트를-반환하도록-하려면">인자로 받은 원래의 리스트를 변경하지 않고, 새로운 리스트를 반환하도록 하려면?</h4>
<p>파이썬에서 함수가 인자로 받은 리스트를 변경하지 않고 새로운 리스트를 반환하도록 하려면, 리스트의 복사본을 생성한 후 해당 복사본을 수정하고 반환하면 된다. 이를 통해 원본 리스트는 변경되지 않고, 수정된 새 리스트를 얻을 수 있다.</p>
<pre><code class="language-python">def solution(local_list):
    # 인자로 받은 가변 객체의 상태를 변경
    local_list = local_list.copy()
    local_list[0] = 100


global_list = [1, 2, 3, 4, 5]
solution(global_list)

print(global_list)</code></pre>
<pre><code># output

[1, 2, 3, 4, 5]</code></pre><p>가변 객체의 구조에 따라, <code>얕은 복사</code>가 아닌 <code>깊은 복사</code>를 사용해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 플로이드 (11404 번)]]></title>
            <link>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-11404-%EB%B2%88</link>
            <guid>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-11404-%EB%B2%88</guid>
            <pubDate>Thu, 16 May 2024 07:20:46 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://www.acmicpc.net/problem/11404">https://www.acmicpc.net/problem/11404</a></p>
<h4 id="회고">회고:</h4>
<ul>
<li>플로이드 와샬 알고리즘으로 해결</li>
</ul>
<br>

<p>python</p>
<pre><code class="language-python">import sys


def solution(graph: list):
    # graph: 간선 정보 / n: 도시 개수
    n = len(graph)

    for k in range(n):
        for i in range(n):
            for j in range(n):
                if graph[i][k] + graph[k][j] &lt; graph[i][j]:
                    graph[i][j] = graph[i][k] + graph[k][j]

    # 이동 불가 지역은 비용을 0 으로 설정
    for i in range(n):
        for j in range(n):
            if graph[i][j] == INF:
                graph[i][j] = 0

    return graph


if __name__ == &quot;__main__&quot;:
    INF = int(1e9)

    # 도시 개수
    N = int(input())

    graph = [[INF] * N for _ in range(N)]
    for i in range(N):
        graph[i][i] = 0

    for _ in range(int(input())):
        start, end, cost = map(int, sys.stdin.readline().split())
        start -= 1
        end -= 1

        graph[start][end] = min(graph[start][end], cost)

    result = solution(graph)
    for i in result:
        sys.stdout.write(&quot; &quot;.join(map(str, i)) + &quot;\n&quot;)</code></pre>
<pre><code># input

5
14
1 2 2
1 3 3
1 4 1
1 5 10
2 4 2
3 4 1
3 5 1
4 5 3
3 5 10
3 1 8
1 4 2
5 1 7
3 4 2
5 2 4</code></pre><pre><code># output

0 2 3 1 4
12 0 15 2 5
8 5 0 1 1
10 7 13 0 3
7 4 10 6 0</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 경로 찾기 (11403번)]]></title>
            <link>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-11403-%EA%B2%BD%EB%A1%9C-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-11403-%EA%B2%BD%EB%A1%9C-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Thu, 16 May 2024 06:47:23 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://www.acmicpc.net/problem/11403">https://www.acmicpc.net/problem/11403</a></p>
<h4 id="회고">회고:</h4>
<ul>
<li>모든 정점에서 모든 정점까지의 가능한 경로를 찾아야 하는 문제이므로, 플로이드 와샬 알고리즘을 사용했다.</li>
<li>다만, 경로 유무만 파악하면 되기 때문에 최단 거리까지는 구하지 않았다.</li>
</ul>
<br>

<p>python</p>
<pre><code class="language-python">import sys


def solution(graph):
    N = len(graph)

    is_exist = &quot;1&quot;

    # k: 거쳐가는 노드
    for k in range(N):
        # i: 출발 노드
        for i in range(N):
            #  j: 도착 노드
            for j in range(N):
                # k를 거쳐가는 노드가 있는지 구한다.
                if graph[i][k] == is_exist and graph[k][j] == is_exist:
                    graph[i][j] = is_exist

    return graph


if __name__ == &quot;__main__&quot;:
    # 정점의 개수
    N = int(input())

    # 노드 간 연결 정보
    graph = []
    for i in range(N):
        graph.append(sys.stdin.readline().split())

    result = solution(graph)
    for row in result:
        sys.stdout.write(&quot; &quot;.join(row) + &quot;\n&quot;)</code></pre>
<pre><code># input

7
0 0 0 1 0 0 0
0 0 0 0 0 0 1
0 0 0 0 0 0 0
0 0 0 0 1 1 0
1 0 0 0 0 0 0
0 0 0 0 0 0 1
0 0 1 0 0 0 0</code></pre><pre><code># output

1 0 1 1 1 1 1
0 0 1 0 0 0 1
0 0 0 0 0 0 0
1 0 1 1 1 1 1
1 0 1 1 1 1 1
0 0 1 0 0 0 1
0 0 1 0 0 0 0</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[플로이드 와샬(Floyd Warshall) 알고리즘 구현 (python)]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%99%80%EC%83%ACFloyd-Warshall-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B5%AC%ED%98%84-python</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%99%80%EC%83%ACFloyd-Warshall-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B5%AC%ED%98%84-python</guid>
            <pubDate>Thu, 16 May 2024 06:31:46 GMT</pubDate>
            <description><![CDATA[<h3 id="목적--특징">목적 &amp; 특징</h3>
<ul>
<li>모든 정점에서 모든 정점으로의 최단 경로를 구한다.</li>
<li>다익스트라 알고리즘이 가장 적은 비용부터 하나씩 선택하는 특징이 있는 반면,
플로이드 와샬 알고리즘은 <code>거쳐가는 정점</code>을 기준으로 알고리즘을 수행하는 특징이 있다.</li>
<li>다익스트라 알고리즘은 다이나믹 프로그래밍을 기반으로 한다.</li>
</ul>
<hr>
<h3 id="방법">방법</h3>
<ol>
<li><p>2차원 배열을 만들어서 각 정점에서, 각 정점까지의 비용을 담는다.
(<code>해당 테이블은 현재까지 계산된 최소 비용을 의미한다</code>. 해당 2차원 배열을 반복적으로 갱신해서 최종적으로는 모든 정점에서 모든 정점으로의 최단 경로를 구하는 것이다. <code>반복의 기준은 거쳐가는 정점이다.</code>)</p>
</li>
<li><p>노드 1번을 거쳐가는 경우에 대한 최소 경로값을 갱신한다. </p>
<ul>
<li>ex) <code>X→Y 가는 최소 비용</code> vs <code>X→1 가는 비용 + 1→X 가는 비용</code></li>
<li>2차원 배열에서 1번 노드가 포함되지 않은 행열에 대해서 위와 같이 비교를 해주면 되며, 더 작은 값으로 갱신한다.</li>
</ul>
</li>
<li><p>2번을 마지막 노드까지 반복한다.</p>
</li>
</ol>
<hr>
<h3 id="예시-및-코드python">예시 및 코드(python)</h3>
<p><img src="https://velog.velcdn.com/images/juhee_bda/post/dce3e2ad-f46e-4097-9f66-85b5750a8e65/image.png" alt=""></p>
<p>python</p>
<pre><code class="language-python">def floyd(graph):
    # 노드 개수
    N = len(graph)

    # k: 거쳐가는 노드
    for k in range(N):
        # i: 출발 노드
        for i in range(N):
            # j: 도착 노드
            for j in range(N):
                if graph[i][k] + graph[k][j] &lt; graph[i][j]:
                    graph[i][j] = graph[i][k] + graph[k][j]

    return graph


if __name__ == &quot;__main__&quot;:
    INF = 1e8

    graph = [
        [0, 5, INF, 8],
        [7, 0, 9, INF],
        [2, INF, 0, 4],
        [INF, INF, 3, 0]
    ]

    result = floyd(graph)
    for i in result:
        print(i)</code></pre>
<pre><code>[0, 5, 11, 8]
[7, 0, 9, 13]
[2, 7, 0, 4]
[5, 10, 3, 0]</code></pre><hr>
<h3 id="참고-링크">참고 링크</h3>
<blockquote>
<ul>
<li><a href="https://www.youtube.com/watch?v=9574GHxCbKc">https://www.youtube.com/watch?v=9574GHxCbKc</a></li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 네트워크 연결 (1922번)]]></title>
            <link>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%97%B0%EA%B2%B0-1922%EB%B2%88</link>
            <guid>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%97%B0%EA%B2%B0-1922%EB%B2%88</guid>
            <pubDate>Tue, 14 May 2024 09:16:07 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://www.acmicpc.net/problem/1922">https://www.acmicpc.net/problem/1922</a></p>
<h4 id="회고">회고:</h4>
<ul>
<li>모든 노드를 최소 비용으로 연결하는 문제로, 크루스칼 알고리즘을 사용하면 됨</li>
</ul>
<br>

<p>python</p>
<pre><code class="language-python"># 가장 비용이 낮은 선 부터 선택하되, 사이클이 생기지 않도록 한다.
# union-find를 이용해서 사이클 생기지 않도록 방지

import sys


def solution(N: int, links: list):
    # union-find 중 find 함수
    def get_parent(node: int) -&gt; int:
        if node == parents[node]:
            return node
        else:
            return get_parent(parents[node])

    # union-find 중 union 함수
    def union_parent(parent_node_a: int, parent_node_b: int):
        nonlocal parents
        parents[max(parent_node_a, parent_node_b)] = min(parent_node_a, parent_node_b)

    # 연결된 부모 노드 (초기엔 자기 자신으로 초기화)
    parents = [i for i in range(N + 1)]

    # 비용 낮은 순서로 정렬
    links.sort(key=lambda x: x[2])

    count = 0  # 연결된 선 개수
    result = 0  # 총 비용
    for node_a, node_b, cost in links:
        # 부모 노드 확인
        parent_node_a = get_parent(node_a)
        parent_node_b = get_parent(node_b)

        # 사이클이 생기지 않는다면 연결한다.
        if parent_node_a != parent_node_b:
            result += cost
            count += 1
            # 부모 노드 변경
            union_parent(parent_node_a, parent_node_b)

        # 선은 N-1개 만큼 연결함
        if count == N - 1:
            break

    return result


if __name__ == &quot;__main__&quot;:
    # 컴퓨터 수
    N = int(input())

    # 연결할 수 있는 선의 수
    M = int(input())

    # 연결 비용 정보 (노드1, 노드2, 비용)
    links = [tuple(map(int, sys.stdin.readline().split())) for _ in range(M)]

    print(solution(N, links))</code></pre>
<pre><code>#  input

6
9
1 2 5
1 3 4
2 3 2
2 4 7
3 4 6
3 5 11
4 5 3
4 6 8
5 6 8</code></pre><pre><code># output

23</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 최소비용 구하기 (1916번)]]></title>
            <link>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EC%B5%9C%EC%86%8C%EB%B9%84%EC%9A%A9-%EA%B5%AC%ED%95%98%EA%B8%B0-1916%EB%B2%88</link>
            <guid>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EC%B5%9C%EC%86%8C%EB%B9%84%EC%9A%A9-%EA%B5%AC%ED%95%98%EA%B8%B0-1916%EB%B2%88</guid>
            <pubDate>Tue, 14 May 2024 04:53:34 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://www.acmicpc.net/problem/1916">https://www.acmicpc.net/problem/1916</a></p>
<p>python</p>
<pre><code class="language-python">import sys
from heapq import heappop, heappush

INF = 1e9


# N: 도시 개수 / start: 시작 도시 번호 / end: 도착 도시 번호
# start -&gt; end 까지의 최단 거리 구하기
def solution(N: int, start: int, end: int) -&gt; int:
    # 시작 위치 기준 최소 거리
    distance = [INF] * (N + 1)
    distance[start] = 0

    queue = []
    for node, value in graph[start]:
        heappush(queue, (value, node))

    while queue:
        value, node = heappop(queue)

        if value &lt; distance[node]:
            distance[node] = value

            for next_node, next_value in graph[node]:
                if value + next_value &lt; distance[next_node]:
                    heappush(queue, (value + next_value, next_node))

    return distance[end]


if __name__ == &quot;__main__&quot;:
    # 도시 개수
    N = int(input())

    # 버스 개수
    M = int(input())

    graph = [[] for _ in range(N + 1)]

    for _ in range(M):
        start, end, value = map(int, sys.stdin.readline().split())
        graph[start].append((end, value))

    start, end = map(int, sys.stdin.readline().split())

    print(solution(N, start, end))</code></pre>
<pre><code># 입력값

5
8
1 2 2
1 3 3
1 4 1
1 5 10
2 4 2
3 4 1
3 5 1
4 5 3
1 5</code></pre><pre><code># 출력값

4</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 게임 (1584번)]]></title>
            <link>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EA%B2%8C%EC%9E%84-1584%EB%B2%88</link>
            <guid>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%EA%B2%8C%EC%9E%84-1584%EB%B2%88</guid>
            <pubDate>Mon, 13 May 2024 08:32:19 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://www.acmicpc.net/problem/1584">https://www.acmicpc.net/problem/1584</a></p>
<h4 id="회고">회고:</h4>
<p><strong>다익스트라로 해결</strong></p>
<ul>
<li><p>안전지역, 위험지역, 죽음지역에 대한 정보를 나타내는 graph 생성:</p>
<ul>
<li>(0, 0) ~ (500, 500) 까지 행/렬 각각 501칸으로 이뤄진 2차원 리스트</li>
<li>안전지역의 값: 0 / 위험지역의 값: 1 / 죽음지역의 값: 2</li>
<li>죽음지역의 값은 지나다니지 못하도록 해야 함
안전지역, 위험지역은 지나가게 될 경우 해당 value 만큼 최소거리가 추가됨</li>
</ul>
</li>
<li><p>최소 거리를 나타내는 distance 생성:</p>
<ul>
<li>graph 변수와 동일한 크기</li>
<li>시작 위치는 (0, 0)이고, 시작 위치까지의 최단거리는 항상 0이다.</li>
<li>ex) distance[x][y]: 시작 위치 (0, 0)으로부터 (x, y)까지의 최단 거리</li>
</ul>
</li>
<li><p>graph 밖으로 벗어나지 않고 죽음 지역이 아닌 경우에 한하여, 동서남북으로 그 다음 최단 거리를 찾아서 heap에 추가. 추가할 때는 (최단 거리 정보, x좌표, y좌표) 정보를 넣어준다. 힙큐를 사용하기 때문에 최단 거리가 짧을 수록 heap의 앞부분으로 정렬되는 점 참고</p>
</li>
<li><p>heap에서 최단 거리가 가장 짧은 것을 꺼내어, 최단 거리 정보를 업데이트 해준다. </p>
</li>
</ul>
<br>

<p>python</p>
<pre><code class="language-python">import sys
from heapq import heappush, heappop

INF = 1e9


def update_graph(danger_value, *args):
    global graph

    x1, y1, x2, y2 = args

    for i in range(min(x1, x2), max(x1, x2) + 1):
        for j in range(min(y1, y2), max(y1, y2) + 1):
            graph[i][j] = danger_value


def solution():
    # 최단 거리 정보
    distance = [[INF] * 501 for _ in range(501)]

    # 시작 위치 거리 설정
    distance[0][0] = 0

    # 방향: 왼쪽, 오른쪽, 아래, 위
    dxs = (0, 0, 1, -1)
    dys = (-1, 1, 0, 0)

    # 시작 위치에 대한 다음 최단 거리 구하기 / heap: (거리, x좌표, y좌표) 들의 리스트
    heap = []
    for x, y in [(0, 1), (1, 0)]:
        if graph[x][y] != 2:
            heappush(heap, (graph[x][y], x, y))

    while heap:
        value, x, y = heappop(heap)

        # 최단 거리 구하기
        if value &lt; distance[x][y]:
            distance[x][y] = value

            if x == 500 and y == 500:
                break

            for dx, dy in zip(dxs, dys):
                nx = x + dx
                ny = y + dy

                if nx &lt; 0 or nx &gt; 500 or ny &lt; 0 or ny &gt; 500:
                    continue

                if graph[nx][ny] != 2 and value + graph[nx][ny] &lt; distance[nx][ny]:
                    heappush(heap, (value + graph[nx][ny], nx, ny))

    return -1 if distance[500][500] == INF else distance[500][500]


if __name__ == &quot;__main__&quot;:
    # 0: 자유 롭게 다닐수 있는 곳, 1: 위험 지역, 2: 죽음 지역
    graph = [[0] * 501 for _ in range(501)]

    # 위험 구역 정보
    for _ in range(int(input())):
        update_graph(1, *map(int, sys.stdin.readline().split()))

    # 죽음 구역 정보
    for _ in range(int(input())):
        update_graph(2, *map(int, sys.stdin.readline().split()))

    print(solution())</code></pre>
<pre><code># 입력값 

1
0 0 499 500
0</code></pre><pre><code># 출력값

499</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 특정 거리의 도시 찾기 (18352번)]]></title>
            <link>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%ED%8A%B9%EC%A0%95-%EA%B1%B0%EB%A6%AC%EC%9D%98-%EB%8F%84%EC%8B%9C-%EC%B0%BE%EA%B8%B0-18352%EB%B2%88</link>
            <guid>https://velog.io/@juhee_bda/%EB%B0%B1%EC%A4%80-%ED%8A%B9%EC%A0%95-%EA%B1%B0%EB%A6%AC%EC%9D%98-%EB%8F%84%EC%8B%9C-%EC%B0%BE%EA%B8%B0-18352%EB%B2%88</guid>
            <pubDate>Mon, 13 May 2024 07:07:47 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://www.acmicpc.net/problem/18352">https://www.acmicpc.net/problem/18352</a></p>
<h4 id="회고">회고:</h4>
<ul>
<li>다익스트라 알고리즘 문제</li>
</ul>
<br>

<p>python</p>
<pre><code class="language-python">import sys
from heapq import heappop, heappush

INF = 1e6


def solution(N: int, M: int, K: int, X: int, graph: list):
    # 최단 거리 테이블 (출발 노드는 거리 0으로 설정, 그 외에는 무한대로 설정)
    distance = [INF] * (N + 1)
    distance[X] = 0

    # 출발 노드와 연결된 최단 노드 확인
    queue = []
    for node in graph[X]:
        heappush(queue, (1, node))

    # 최단 거리 테이블 계산
    while queue:
        value, node = heappop(queue)
        next_value = value + 1

        if value &lt; distance[node]:
            distance[node] = value

            for next_node in graph[node]:
                if next_value &lt; distance[next_node]:
                    heappush(queue, (next_value, next_node))

    # 최단 거리가 K인 도시 개수 구하기
    is_exist = False
    for i in range(1, N + 1):
        if distance[i] == K:
            is_exist = True
            print(i)

    if not is_exist:
        print(-1)


if __name__ == &quot;__main__&quot;:
    # N: 도시 개수, M: 도로 개수, K: 거리, X: 출발 도시 번호
    N, M, K, X = map(int, sys.stdin.readline().split())

    # 도로 정보
    graph = [[] for _ in range(N + 1)]
    for _ in range(M):
        start, end = map(int, sys.stdin.readline().split())
        graph[start].append(end)

    solution(N, M, K, X, graph)</code></pre>
<pre><code># 입력값

4 4 1 1
1 2
1 3
2 3
2 4</code></pre><pre><code># 출력값

2
3</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[강의 공부] 16. @login_required를 이용한 데코레이터 테스트]]></title>
            <link>https://velog.io/@juhee_bda/%EA%B0%95%EC%9D%98-%EA%B3%B5%EB%B6%80-loginrequired%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@juhee_bda/%EA%B0%95%EC%9D%98-%EA%B3%B5%EB%B6%80-loginrequired%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Wed, 08 May 2024 06:35:13 GMT</pubDate>
            <description><![CDATA[<h3 id="⎷-함수에-데코레이터-적용하기">⎷ 함수에 데코레이터 적용하기</h3>
<h4 id="viewspy--hello_world-원래-함수">views.py &gt; hello_world 원래 함수</h4>
<p>로그인하지 않은 사용자가 접근할 때, 로그인 페이지로 리다이렉트함</p>
<pre><code class="language-python"># views.py

def hello_world(request):
    if request.user.is_authenticated:
        if request.method == &quot;POST&quot;:
            text = request.POST.get(&quot;hello_world_input&quot;)

            # DB 저장
            new_hello_world = HelloWorld()
            new_hello_world.text = text
            new_hello_world.save()

            return HttpResponseRedirect(reverse(&#39;accountapp:hello_world&#39;))
        else:
            hello_world_list = HelloWorld.objects.all()
            return render(request, &#39;accountapp/hello_world.html&#39;, context={&#39;hello_world_list&#39;: hello_world_list})
    else:
        return HttpResponseRedirect(reverse(&#39;accountapp:login&#39;))</code></pre>
<br>

<h4 id="login_required-데코레이터-사용"><code>@login_required</code> 데코레이터 사용</h4>
<p><code>login_required</code> 데코레이터 특징</p>
<ul>
<li>로그인한 사용자만 접근할 수 있게 함</li>
<li>로그인하지 않은 사용자가 접근하면 자동으로 로그인 페이지로 리다이렉션됨<pre><code class="language-python">from django.contrib.auth.decorators import login_required

</code></pre>
</li>
</ul>
<p>@login_required
def hello_world(request):
    # request.user.is_authenticated 비교 로직 제거함
    if request.method == &quot;POST&quot;:
        text = request.POST.get(&quot;hello_world_input&quot;)</p>
<pre><code>    # DB 저장
    new_hello_world = HelloWorld()
    new_hello_world.text = text
    new_hello_world.save()

    return HttpResponseRedirect(reverse(&#39;accountapp:hello_world&#39;))
else:
    hello_world_list = HelloWorld.objects.all()
    return render(request, &#39;accountapp/hello_world.html&#39;, context={&#39;hello_world_list&#39;: hello_world_list})</code></pre><pre><code>&lt;br&gt;

#### 로그인하지 않은 사용자가 접근했을 때, 로그인 페이지가 아닌 &quot;다른 페이지&quot;로 리다이렉션 하고 싶다면?

1) 간단한 테스트 페이지 만들기
```python
# view.py

def test(request):
    return render(request, &#39;accountapp/test.html&#39;)</code></pre><pre><code class="language-html">&lt;!-- template --&gt;

{% extends &quot;base.html&quot; %}

{% block content %}
    &lt;div style=&quot;text-align: center;&quot;&gt;
        &lt;h1&gt;TEST PAGE&lt;/h1&gt;
    &lt;/div&gt;
{% endblock %}</code></pre>
<pre><code class="language-python"># urls.py

from django.urls import path

from accountapp.views import hello_world, test

app_name = &quot;accountapp&quot;

urlpatterns = [
    path(&#39;hello_world/&#39;, hello_world, name=&#39;hello_world&#39;),
    path(&#39;test/&#39;, test, name=&#39;test&#39;),
]</code></pre>
<p><img src="https://velog.velcdn.com/images/juhee_bda/post/69a6f840-c07e-467f-bbfc-b6f84c3fda14/image.png" alt=""></p>
<br>

<p>2) 로그인페이지가 아닌 다른 페이지(위의 테스트 페이지)로 리다이렉트 시키기</p>
<ul>
<li>views.py &gt; <code>@login_required</code> 데코레이터 사용</li>
<li>settigns.py &gt; <code>login_url</code> 설정<pre><code class="language-python"># views.py
</code></pre>
</li>
</ul>
<p>from django.contrib.auth.decorators import login_required</p>
<p>@login_required
def hello_world(request):
    if request.method == &quot;POST&quot;:
        text = request.POST.get(&quot;hello_world_input&quot;)</p>
<pre><code>    # DB 저장
    new_hello_world = HelloWorld()
    new_hello_world.text = text
    new_hello_world.save()

    return HttpResponseRedirect(reverse(&#39;accountapp:hello_world&#39;))
else:
    hello_world_list = HelloWorld.objects.all()
    return render(request, &#39;accountapp/hello_world.html&#39;, context={&#39;hello_world_list&#39;: hello_world_list})</code></pre><pre><code>```python
# settings.py

LOGIN_URL = reverse_lazy(&#39;accountapp:test&#39;)</code></pre><br>

<p>3) 테스트
로그인 되지 않은 상태에서 <code>/accounts/hello_world</code> url로 접근하면 <code>/accounts/test</code> url로 리다이렉트 됨</p>
<hr>
<h3 id="⎷-참고-reverse-reverse_lazy-함수">⎷ 참고 (reverse, reverse_lazy 함수)</h3>
<h4 id="어째서-settignspy-에서는-장고의-reverse를-사용하지-않고-reverse_lazy를-사용해야-하는가">어째서 settigns.py 에서는 장고의 reverse를 사용하지 않고 reverse_lazy를 사용해야 하는가?</h4>
<blockquote>
<p><strong>reverse, reverse_lazy 공통점</strong>
장고의 <code>reverse</code>, <code>reverse_lazy</code> 함수는 URL 이름을 바탕으로 URL을 동적으로 생성해주는 역할을 한다.
<br>
<strong>reverse, reverse_lazy 차이점 (호출시점 반환방식에 차이 O)</strong>
<strong>(1) reverse</strong>:
호출 시 바로 URL을 반환해야 한다. 따라서 reverse를 사용하기 위해서는 호출 시점에 URLConf가 완전히 로드되어 있어야 한다.
<strong>(2) reverse_lazy</strong>: 
URL을 즉시 생성하지 않고, 필요할 때까지 생성을 지연한다.</p>
</blockquote>
<p>settings.py에서 reverse_lazy를 사용하는 이유는 django의 로딩순서 때문이다. settigns.py는 프로젝트의 구성 설정을 포함하며, 프로젝트가 실행될 때 가장 먼저 로드된다. 때문에 설정파일이 완전히 로드되기 전까지는 URLConf가 완전히 로드되지 않을 수 있다. reverse함수의 경우 URLConf가 완전히 로드가 되어야만 정상적으로 사용할 수 있기 때문에 settigns.py에서는 사용하지 않는다.</p>
<hr>
<h3 id="⎷-클래스에-데코레이터-적용하기">⎷ 클래스에 데코레이터 적용하기</h3>
<h4 id="각-클래스뷰-기능">각 클래스뷰 기능</h4>
<ul>
<li><code>AccountUpdateView</code>: 회원 정보 계정 수정</li>
<li><code>AccountDeleteView</code>: 회원 계정 삭제</li>
</ul>
<h4 id="상황">상황</h4>
<ul>
<li>회원 정보 계정을 수정하고, 계정을 삭제할 때 <code>로그인한 상태로 접근을 했는지 여부</code>와 <code>로그인한 유저와 접근하려는 대상의 정보가 일치하는지 여부</code>를 확인한다. (나는 내 정보만 수정하거나 삭제가 가능해야 한다. 남의 정보를 조회할 수 없도록 해야 함)</li>
<li>따라서 각 클래스뷰에 대해서 get, post 함수가 아래와 같이 확장되어 있는 상태</li>
<li>코드 중복이 발생하여 이를 데코레이터로 수정할 예정</li>
</ul>
<pre><code class="language-python"># views.py

class AccountUpdateView(UpdateView):
    model = User
    context_object_name = &#39;target_user&#39;
    form_class = AccountUpdateForm
    success_url = reverse_lazy(&#39;accountapp:hello_world&#39;)
    template_name = &#39;accountapp/update.html&#39;

    def get(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().get(*args, **kwargs)
        else:
            return HttpResponseForbidden(&quot;허용되지 않는 접근입니다.&quot;)

    def post(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().post(*args, **kwargs)
        else:
            return HttpResponseForbidden(&quot;허용되지 않는 접근입니다.&quot;)


class AccountDeleteView(DeleteView):
    model = User
    context_object_name = &#39;target_user&#39;
    success_url = reverse_lazy(&#39;accountapp:login&#39;)
    template_name = &#39;accountapp/delete.html&#39;

    def get(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().get(*args, **kwargs)
        else:
            return HttpResponseForbidden(&quot;허용되지 않는 접근입니다.&quot;)

    def post(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().post(*args, **kwargs)
        else:
            return HttpResponseForbidden(&quot;허용되지 않는 접근입니다.&quot;)</code></pre>
<br>

<h4 id="클래스에-데코레이터-적용하기">클래스에 데코레이터 적용하기</h4>
<ul>
<li><p>데코레이터 함수 역할</p>
<ul>
<li><code>login_required</code>: 장고에서 지원하는 함수로, 로그인한 상태로 접근하고 있는지 확인함</li>
<li><code>account_ownership_required</code>: 로그인한 유저와 접근하려는 대상이 동일한지 확인</li>
</ul>
</li>
<li><p>클래스 메서드에는 직접적으로 데코레이터를 사용할 수가 없다. 대신 <code>method_decorator</code>를 이용하면 클래스 메서드에 데코레이터를 적용시킬 수 있다.</p>
</li>
<li><p><code>@method_decorator(데코레이터함수, &#39;클래스메서드&#39;)</code></p>
</li>
</ul>
<pre><code class="language-python"># decorator.py

from django.contrib.auth.models import User
from django.http import HttpResponseForbidden


# 로그인한 유저와 접근하려는 대상의 정보가 일치하는지 여부 확인
def account_ownership_required(func):
    def wrapper(request, *args, **kwargs):
        user = User.objects.get(pk=kwargs[&quot;pk&quot;])

        if request.user == user:
            return func(request,*args, **kwargs)
        else:
            return HttpResponseForbidden(&quot;허용되지 않는 접근입니다.&quot;)

    return wrapper</code></pre>
<pre><code class="language-python"># views.py 

from django.contrib.auth.decorators import login_required


@method_decorator(login_required, &#39;get&#39;)
@method_decorator(login_required, &#39;post&#39;)
@method_decorator(account_ownership_required, &#39;get&#39;)
@method_decorator(account_ownership_required, &#39;post&#39;)
class AccountUpdateView(UpdateView):
    model = User
    context_object_name = &#39;target_user&#39;
    form_class = AccountUpdateForm
    success_url = reverse_lazy(&#39;accountapp:hello_world&#39;)
    template_name = &#39;accountapp/update.html&#39;


@method_decorator(login_required, &#39;get&#39;)
@method_decorator(login_required, &#39;post&#39;)
@method_decorator(account_ownership_required, &#39;get&#39;)
@method_decorator(account_ownership_required, &#39;post&#39;)
class AccountDeleteView(DeleteView):
    model = User
    context_object_name = &#39;target_user&#39;
    success_url = reverse_lazy(&#39;accountapp:login&#39;)
    template_name = &#39;accountapp/delete.html&#39;</code></pre>
<br>

<h4 id="좀-더-간결하게-만들기">좀 더 간결하게 만들기</h4>
<ul>
<li>두 클래스 뷰는 공통적으로 <code>login_required</code>, <code>account_ownership_required</code> 데코레이터를 사용한다.</li>
<li>아래 <code>has_ownership</code> 변수와 같이 데코레이터 함수를 리스트에 담아서 사용하면 보다 간결하게 사용할 수 있다.</li>
</ul>
<pre><code class="language-python"># views.py 

from django.contrib.auth.decorators import login_required

# login_required 먼저 순차적으로 실행됨
has_ownership = [login_required, account_ownership_required]


@method_decorator(has_ownership, &#39;get&#39;)
@method_decorator(has_ownership, &#39;post&#39;)
class AccountUpdateView(UpdateView):
    model = User
    context_object_name = &#39;target_user&#39;
    form_class = AccountUpdateForm
    success_url = reverse_lazy(&#39;accountapp:hello_world&#39;)
    template_name = &#39;accountapp/update.html&#39;


@method_decorator(has_ownership, &#39;get&#39;)
@method_decorator(has_ownership, &#39;post&#39;)
class AccountDeleteView(DeleteView):
    model = User
    context_object_name = &#39;target_user&#39;
    success_url = reverse_lazy(&#39;accountapp:login&#39;)
    template_name = &#39;accountapp/delete.html&#39;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 개인정보 수집 유효기간]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4-%EC%88%98%EC%A7%91-%EC%9C%A0%ED%9A%A8%EA%B8%B0%EA%B0%84</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4-%EC%88%98%EC%A7%91-%EC%9C%A0%ED%9A%A8%EA%B8%B0%EA%B0%84</guid>
            <pubDate>Fri, 03 May 2024 14:08:56 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/150370">https://school.programmers.co.kr/learn/courses/30/lessons/150370</a></p>
<h4 id="회고">회고:</h4>
<ul>
<li><p><strong>(python) f-string 활용</strong></p>
<ul>
<li>아래 소스코드의 <code>f&quot;{term_year}.{term_month:0&gt;2}.{day:0&gt;2}&quot;</code></li>
<li>ex) <code>term_year=2000</code>, <code>term_month=1</code>, <code>day=12</code> 라고 한다면, <code>&quot;2000.01.12&quot;</code>라는 문자열을 만드는 역할을 한다.</li>
<li><code>{변수:0&gt;길이값}</code> : 변수에 대해서 중앙 정렬이 아닌 <code>(&gt;)오른쪽으로 정렬</code>을 해주는데, <code>폭을 길이값</code>으로 하고, <code>부족한 부분은 0으로</code> 채워넣는다는 의미</li>
</ul>
</li>
</ul>
<br>

<p>python</p>
<pre><code class="language-python"># 개인정보 n개 (고객의 약관 동의를 얻어 수집됨)
# 약관 종류 다양, 각 약관별 보관 유효기간 따로따로 정해져 있음

def solution(today, terms, privacies):
    year, month, day = map(int, today.split(&quot;.&quot;))
    day += 1

    expiration_date = {}
    for term in terms:
        term_type, term_month = term.split()
        term_month = int(term_month)

        if day == 29:
            term_month += 1

        term_month = month - term_month
        term_year = year

        if term_month &lt;= 0:
            term_year -= -term_month // 12 + 1
            term_month = 12 - (-term_month % 12)

        expiration_date[term_type] = f&quot;{term_year}.{term_month:0&gt;2}.{day:0&gt;2}&quot;

    # 파기해야 할 개인정보
    result = []
    for idx, privacy in enumerate(privacies):
        regist_date, regist_term = privacy.split()

        if regist_date &lt; expiration_date[regist_term]:
            result.append(idx + 1)

    return result


if __name__ == &quot;__main__&quot;:
    result = solution(
        today=&quot;2020.05.17&quot;,
        terms=[&quot;A 3&quot;, &quot;B 12&quot;],
        privacies=[&quot;2020.01.01 A&quot;, &quot;2020.05.16 B&quot;],
    )

    print(result)</code></pre>
<pre><code>[1]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 신고 결과 받기]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Fri, 03 May 2024 13:19:48 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/92334">https://school.programmers.co.kr/learn/courses/30/lessons/92334</a></p>
<br>

<p>python</p>
<pre><code class="language-python">def solution(id_list, report, k):
    # 유저: 해당 유저가 신고한 유저들
    reporter_dict = {name: set() for name in id_list}

    # 유저: 신고당한 횟수
    reportee_dict = {name: 0 for name in id_list}

    for report_content in report:
        reporter, reportee = report_content.split(&quot; &quot;)

        if reportee not in reporter_dict[reporter]:
            reporter_dict[reporter].add(reportee)
            reportee_dict[reportee] += 1

    # 각 유저별 처리 결과 메일 받은 횟수 확인
    result = []
    for id in id_list:
        count = 0
        for reportee in reporter_dict[id]:
            if reportee_dict[reportee] &gt;= k:
                count += 1

        result.append(count)

    return result


if __name__ == &quot;__main__&quot;:
    result = solution(
        id_list=[&quot;muzi&quot;, &quot;frodo&quot;, &quot;apeach&quot;, &quot;neo&quot;],
        report=[&quot;muzi frodo&quot;, &quot;apeach frodo&quot;, &quot;frodo neo&quot;, &quot;muzi neo&quot;, &quot;apeach muzi&quot;],
        k=2,
    )

    print(result)</code></pre>
<pre><code>[2, 1, 1, 0]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 제일 작은 수 제거하기]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%9C%EC%9D%BC-%EC%9E%91%EC%9D%80-%EC%88%98-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%9C%EC%9D%BC-%EC%9E%91%EC%9D%80-%EC%88%98-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 03 May 2024 13:01:12 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12935">https://school.programmers.co.kr/learn/courses/30/lessons/12935</a></p>
<br>

<p>python</p>
<pre><code class="language-python">def solution(arr):
    if len(arr) == 1:
        return [-1]
    else:
        idx = arr.index(min(arr))
        return arr[:idx] + arr[idx + 1:]


if __name__ == &quot;__main__&quot;:
    result = solution([4, 3, 2, 1])
    print(result)</code></pre>
<pre><code>[4, 3, 2]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 시저 암호]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%8B%9C%EC%A0%80-%EC%95%94%ED%98%B8</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%8B%9C%EC%A0%80-%EC%95%94%ED%98%B8</guid>
            <pubDate>Fri, 03 May 2024 12:50:08 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12926">https://school.programmers.co.kr/learn/courses/30/lessons/12926</a></p>
<br>

<p>python</p>
<pre><code class="language-python">def solution(s, n):
    upper_case = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
    upper_case_dict = {c: idx for idx, c in enumerate(upper_case)}

    lower_case = &quot;abcdefghijklmnopqrstuvwxyz&quot;
    lower_case_dict = {c: idx for idx, c in enumerate(lower_case)}

    result = []
    for c in s:
        if not c.isalpha():
            result.append(c)
        elif c.islower():
            result.append(lower_case[(lower_case_dict[c] + n) % 26])
        else:
            result.append(upper_case[(upper_case_dict[c] + n) % 26])

    return &quot;&quot;.join(result)


if __name__ == &quot;__main__&quot;:
    result = solution(&quot;AB&quot;, 1)
    print(result)</code></pre>
<pre><code>BC</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[강의 공부] 15. CBV에서 get/post 요청 구분하여 확장하기]]></title>
            <link>https://velog.io/@juhee_bda/%EA%B0%95%EC%9D%98-%EA%B3%B5%EB%B6%80-CBV%EC%97%90%EC%84%9C-getpost-%EC%9A%94%EC%B2%AD-%EA%B5%AC%EB%B6%84%ED%95%98%EC%97%AC-%ED%99%95%EC%9E%A5%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@juhee_bda/%EA%B0%95%EC%9D%98-%EA%B3%B5%EB%B6%80-CBV%EC%97%90%EC%84%9C-getpost-%EC%9A%94%EC%B2%AD-%EA%B5%AC%EB%B6%84%ED%95%98%EC%97%AC-%ED%99%95%EC%9E%A5%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 02 May 2024 09:06:23 GMT</pubDate>
            <description><![CDATA[<p><strong>class view에서 get/post 요청 구분하는 방법 예시</strong>
아래 소스코드의 get(), post() 함수 참고</p>
<p>&lt; view.py &gt;</p>
<pre><code class="language-python">class AccountUpdateView(UpdateView):
    model = User
    context_object_name = &#39;target_user&#39;
    form_class = AccountUpdateForm
    success_url = reverse_lazy(&#39;accountapp:hello_world&#39;)
    template_name = &#39;accountapp/update.html&#39;

    # GET Method
    def get(self, *args, **kwargs):
        # 로그인 상태 여부 확인 / 요청한 유저 객체와 로그인된 유저 객체가 동일한지 확인
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            # UpdateView의 Get 함수를 그대로 따름
            return super().get(*args, **kwargs)
        else:
            # 403 에러코드 리턴 (권한이 옳지 않은 경우)
            return HttpResponseForbidden(&quot;허용되지 않는 접근입니다.&quot;)

    # POST Method
    def post(self, *args, **kwargs):
        if self.request.user.is_authenticated and self.get_object() == self.request.user:
            return super().post(*args, **kwargs)
        else:
            return HttpResponseForbidden(&quot;허용되지 않는 접근입니다.&quot;)</code></pre>
<br>

<p><strong>참고</strong>)
<strong>self.get_object() 메서드</strong>:</p>
<ul>
<li>Django의 클래스 기반 뷰(Class-Based View, CBV)에서 self.get_object() 메소드는 주로 상세 조회 페이지(DetailView)나 수정 페이지(UpdateView), 삭제 페이지(DeleteView)와 같이 특정 모델 인스턴스에 접근이 필요한 경우에 사용된다. </li>
<li>이 메소드는 <code>현재 URL에서 캡처된 파라미터를 기반으로 데이터베이스에서 객체를 조회</code>하고, 객체가 존재하지 않을 경우 404 에러를 자동으로 반환한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[LeetCode] 570. Managers with at Least 5 Direct Reports]]></title>
            <link>https://velog.io/@juhee_bda/LeetCode-570.-Managers-with-at-Least-5-Direct-Reports</link>
            <guid>https://velog.io/@juhee_bda/LeetCode-570.-Managers-with-at-Least-5-Direct-Reports</guid>
            <pubDate>Thu, 02 May 2024 06:42:33 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://leetcode.com/problems/managers-with-at-least-5-direct-reports/description/?envType=study-plan-v2&amp;envId=top-sql-50">https://leetcode.com/problems/managers-with-at-least-5-direct-reports/description/?envType=study-plan-v2&amp;envId=top-sql-50</a></p>
<h4 id="회고-문제를-풀면서-의식의-흐름">회고 (문제를 풀면서 의식의 흐름):</h4>
<ul>
<li><p>IN절로 비교할 때, 인덱스가 설정되어 있다면 비교가 빨라진다.</p>
</li>
<li><p>하지만 비교해야 하는 값이 많거나, 서브쿼리가 포함되어 있는 경우 성능이 저하될 수 있다.</p>
</li>
<li><p>아래 문제는 IN절을 사용할 때 서브쿼리가 포함되고, 데이터셋이 많아지면 비교 대상이 많아지기 때문에 성능이 저하될 것 같다고 생각했다. 이런 경우엔 EXISTS가 더 효율적이지 않을까?</p>
</li>
<li><p><strong>EXISTS 특징 정리</strong></p>
<ul>
<li>EXISTS는 하위 쿼리가 적어도 하나 이상의 결과를 반환하는지 확인하는 데 사용된다. 주로 조건의 충족 여부만 중요할 때 사용한다.</li>
<li>EXISTS는 하위 쿼리 결과의 양과 상관없이 최초의 일치에서 처리를 중단하기 때문에, 특히 하위 쿼리가 복잡하거나 많은 데이터를 스캔해야 하는 경우 더 효율적일 수 있다.    </li>
<li>EXISTS는 일반적으로 해당 조건과 관련된 데이터의 존재 유무만을 확인하기 때문에 IN보다 빠를 수 있다.</li>
</ul>
</li>
<li><p>그래서 IN과 EXISTS 각각 사용해서 문제를 풀어봤는데, 예상과 달리 IN조건으로 푼 풀이가 6배는 빠르네..</p>
</li>
<li><p>서브쿼리로 나온 비교대상이 내 예상보다 많지 않았고, IN 조건에 걸린 컬럼이 PK라서 IN이 훨씬 빨랐던 것일까?</p>
</li>
</ul>
<br>

<p>MySQL - <code>IN()</code> 활용 (runtime: <strong>605ms</strong>)</p>
<pre><code class="language-sql">SELECT T101.NAME
FROM Employee T101
WHERE T101.id IN (
        SELECT DISTINCT (T102.managerId)
        FROM Employee T102
        GROUP BY T102.managerId
        HAVING COUNT(T102.id) &gt; 4
        )</code></pre>
<br>

<p>MySQL - <code>EXISTS()</code> 활용 (runtime: <strong>3705ms</strong>)</p>
<pre><code class="language-sql">SELECT T102.NAME
FROM Employee T102
WHERE EXISTS (
        SELECT 1
        FROM Employee T101
        WHERE T102.id = T101.managerId
        GROUP BY T101.managerId
        HAVING COUNT(T101.id) &gt;= 5
        )</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 2개 이하로 다른 비트]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-2%EA%B0%9C-%EC%9D%B4%ED%95%98%EB%A1%9C-%EB%8B%A4%EB%A5%B8-%EB%B9%84%ED%8A%B8</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-2%EA%B0%9C-%EC%9D%B4%ED%95%98%EB%A1%9C-%EB%8B%A4%EB%A5%B8-%EB%B9%84%ED%8A%B8</guid>
            <pubDate>Thu, 02 May 2024 05:29:37 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/77885">https://school.programmers.co.kr/learn/courses/30/lessons/77885</a></p>
<h4 id="회고">회고:</h4>
<ul>
<li><p><strong>풀이 방법</strong>:</p>
<ul>
<li>10진수를 2진수로 바꾼다.</li>
<li>맨 오른쪽 숫자가 <code>0</code>이라면 해당 숫자만 <code>1</code>로 변경한다.</li>
<li>그렇지 않다면, 오른쪽부터 왼쪽으로 <code>01</code>이라는 숫자를 찾고 <code>10</code> 으로 바꾼다.</li>
<li>다시 10진수로 바꾼다.</li>
</ul>
</li>
</ul>
<br>

<p>python</p>
<pre><code class="language-python">def solution(numbers):
    result = []
    for number in numbers:
        binary_numbers = [&quot;0&quot;] + list(bin(number)[2:])
        length = len(binary_numbers)

        for i in range(length - 1, -1, -1):
            if binary_numbers[i] == &quot;0&quot;:
                binary_numbers[i] = &quot;1&quot;
                if i != length - 1 and binary_numbers[i + 1] == &quot;1&quot;:
                    binary_numbers[i + 1] = &quot;0&quot;

                break

        result.append(int(&quot;0b&quot; + &quot;&quot;.join(binary_numbers), 2))

    return result


if __name__ == &quot;__main__&quot;:
    result = solution([2, 7])
    print(result)</code></pre>
<pre><code>[3, 11]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] JadenCase 문자열 만들기]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-JadenCase-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-JadenCase-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Thu, 02 May 2024 04:59:15 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12951#">https://school.programmers.co.kr/learn/courses/30/lessons/12951#</a></p>
<br>

<p>python</p>
<pre><code class="language-python"># s 구성 요소: 공백, 알파벳, 숫자
# 공백 문자가 연속해서 나올 수 있다.
def solution(s):
    words = []
    for idx, c in enumerate(s):
        if not c.isalpha():
            words.append(c)
        elif idx == 0 or (idx &gt; 0 and s[idx - 1] == &quot; &quot;):
            words.append(c.upper())
        else:
            words.append(c.lower())

    return &quot;&quot;.join(words)


if __name__ == &quot;__main__&quot;:
    result = solution(&quot;3people unFollowed me&quot;)
    print(result)</code></pre>
<pre><code>3people Unfollowed Me</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 자릿수 더하기]]></title>
            <link>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%9E%90%EB%A6%BF%EC%88%98-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@juhee_bda/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%9E%90%EB%A6%BF%EC%88%98-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 02 May 2024 04:30:47 GMT</pubDate>
            <description><![CDATA[<h4 id="문제-링크">문제 링크:</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12931?language=python3">https://school.programmers.co.kr/learn/courses/30/lessons/12931?language=python3</a></p>
<br>

<p>python</p>
<pre><code class="language-python">def solution(n):
    answer = 0
    while n != 0:
        answer += n % 10
        n //= 10

    return answer</code></pre>
<pre><code>6</code></pre>]]></description>
        </item>
    </channel>
</rss>