<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>MEIN_FIGUR.daily_log</title>
        <link>https://velog.io/</link>
        <description>Growing Developer</description>
        <lastBuildDate>Sun, 06 Feb 2022 13:44:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>MEIN_FIGUR.daily_log</title>
            <url>https://images.velog.io/images/mein-figur/profile/baa754df-a6fe-4e8a-9f5d-1a8adae053b5/프로필사진.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. MEIN_FIGUR.daily_log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mein-figur" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[URI & URL & URN]]></title>
            <link>https://velog.io/@mein-figur/URI-URL-URN</link>
            <guid>https://velog.io/@mein-figur/URI-URL-URN</guid>
            <pubDate>Sun, 06 Feb 2022 13:44:33 GMT</pubDate>
            <description><![CDATA[<h1 id="uri--url--urn">URI &amp; URL &amp; URN</h1>
<br>

<h2 id="uriuniform-resource-identifier">URI(Uniform Resource Identifier)</h2>
<ul>
<li>통합 자원 식별자</li>
<li>위치나 이름, 또는 둘 다를 기준으로 자원을 식별한다.</li>
<li>URI에는 URL, URN이 존재한다.(URI의 하위 개념이 URL, URN)<ul>
<li>URN과 URL은 모두 URI이며, 특정 URI는 URL이자 URN이 될 수 있다.</li>
<li>URL는 URI이다.</li>
<li>URI가 반드시 URL일 필요는 없다.</li>
</ul>
</li>
</ul>
<br>

<h2 id="urluniform-resource-locator">URL(Uniform Resource Locator)</h2>
<ul>
<li>식별된 자원을 사용할 수 있는 위치와 이를 검색하는 매커니즘을 지정하는 URI의 하위 집합</li>
<li>자원을 얻을 수 있는 방법을 정의</li>
<li>식별된 자원의 가용성을 의미하지 않는다.</li>
</ul>
<p><img src="https://media.vlpt.us/images/shleecloud/post/27525e87-d8a9-486a-ac24-99bbe2764cfc/uri.png" alt=""></p>
<ul>
<li>protocol(scheme): 통신 프로토콜</li>
<li>host: 웹 페이지, 이미지, 동영상 등의 파일이 위치한 웹 서버, 도메인 또는 IP</li>
<li>port: 웹 서버에 접속하기 위한 통로</li>
<li>path: 웹 서버의 루트 디렉토리로부터 웹 페이지, 이미지, 동영상 등의 파일 위치까지의 경로</li>
<li>query string: 웹 서버에 전달하는 추가 질문</li>
</ul>
<br>

<h2 id="urnuniform-resource-name">URN(Uniform Resource Name)</h2>
<ul>
<li>리소스를 영구적이고 유일하게 식별할 수 있는 URI</li>
<li>URN 체계를 사용하는 URI</li>
<li>URN이 “what”을 의미한다면, URL은 “where”를 의미한다.</li>
<li><code>urn : &#39;이름공간식별자&#39; : &#39;이름공간에 대한 특별 문자열&#39;</code> 과 같은 형태로 구성된다.</li>
</ul>
<br>

<pre><code>URL: ftp://ftp.is.co.za/rfc/rfc1808.txt
URL: http://www.ietf.org/rfc/rfc2396.txt
URL: ldap://[2001:db8::7]/c=GB?objectClass?one
URL: mailto:John.Doe@example.com
URL: news:comp.infosystems.www.servers.unix
URL: telnet://192.0.2.16:80/
URN (not URL): urn:oasis:names:specification:docbook:dtd:xml:4.1.2
URN (not URL): tel:+1-816-555-1212 (disputed, see comments)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Java]파일의 Mime Type을 알아내는 방법]]></title>
            <link>https://velog.io/@mein-figur/Java%ED%8C%8C%EC%9D%BC%EC%9D%98-Mime-Type%EC%9D%84-%EC%95%8C%EC%95%84%EB%82%B4%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@mein-figur/Java%ED%8C%8C%EC%9D%BC%EC%9D%98-Mime-Type%EC%9D%84-%EC%95%8C%EC%95%84%EB%82%B4%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 24 Jan 2022 16:25:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>아래와 같은 방법을 통해 file의 mime type을 알 수 있다.</p>
</blockquote>
<p><br><br></p>
<h3 id="probecontenttype">probeContentType</h3>
<ul>
<li><code>Files.probeContentType(path)</code><ul>
<li><strong>OS에 따라 작동하지 않을 수 있음</strong>을 주의해야 한다.</li>
</ul>
</li>
</ul>
<pre><code class="language-java">class ProbeTest {
    @Test
    public void whenUsingJava7_thenSuccess() {
        Path path = new File(&quot;product.png&quot;).toPath();
        String mimeType = Files.probeContentType(path);

        assertEquals(mimeType, &quot;image/png&quot;);
    }
}</code></pre>
<p><br><br></p>
<h3 id="urlconnetion">URLConnetion</h3>
<ul>
<li><code>getContentType()</code><ul>
<li><strong>속도가 느리다</strong>는 단점이 있다.</li>
</ul>
</li>
</ul>
<pre><code class="language-java">class UrlConnectionTest {
    @Test
    public void whenUsingGetContentType_thenSuccess() {
        File file = new File(&quot;product.png&quot;);
        URLConnection connection = file.toURL().openConnection();
        String mimeType = connection.getContentType();

        assertEquals(mimeType, &quot;image/png&quot;);
    }
}</code></pre>
<ul>
<li><code>guessContentTypeFromName()</code><ul>
<li>내부의 FileNameMap을 통해 type을 알아내는 방식</li>
</ul>
</li>
</ul>
<pre><code class="language-java">class UrlConnectionTest2{
    @Test
    public void whenUsingGuessContentTypeFromName_thenSuccess(){
        File file = new File(&quot;product.png&quot;);
        String mimeType = URLConnection.guessContentTypeFromName(file.getName());

        assertEquals(mimeType, &quot;image/png&quot;);
    }
</code></pre>
<ul>
<li><code>getFileNameMap()</code><ul>
<li><code>URLConnection</code>을 활용해서 Mime Type을 찾는 방식 중 빠른 방식</li>
</ul>
</li>
</ul>
<pre><code class="language-java">class UrlConnectionTest2{
    @Test
    public void whenUsingGetFileNameMap_thenSuccess(){
        File file = new File(&quot;product.png&quot;);
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String mimeType = fileNameMap.getContentTypeFor(file.getName());

        assertEquals(mimeType, &quot;image/png&quot;);
    }
}</code></pre>
<ul>
<li><p>내장된 테이블은 <code>JRE_HOME/lib</code>의 <code>content-types.properties</code>를 활용하는데, type이 다소 제한된다는 점이 있다.</p>
</li>
<li><p><code>content.types.user.table property</code>를 활용하여 사용자 테이블을 설정할 수 있다.</p>
<pre><code class="language-java">  System.setProperty(&quot;content.types.user.table&quot;,&quot;&lt;path-to-file&gt;&quot;);</code></pre>
</li>
</ul>
<p><br><br></p>
<h3 id="mimetypesfiletypemap">MimeTypesFileTypeMap</h3>
<ul>
<li>Java 6에서 온 클래스로, JDK 1.6에서 편리하다.</li>
<li><code>mime.types</code> 파일을 찾아 타입을 알아내는 방식으로, 파일을 찾을 수 없으면 <code>application/octet-stream</code>을 반환한다.<ul>
<li><code>mime.types</code> 파일을 찾는 방식은 다음과 같다.</li>
</ul>
</li>
</ul>
<p><img src="https://images.velog.io/images/mein-figur/post/764c552c-f9ac-48b0-83a6-4b6efe5e045d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-24%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.03.52.png" alt=""></p>
<pre><code class="language-java">class UrlConnectionTest2{
    @Test
    public void whenUsingMimeTypesFileTypeMap_thenSuccess() {
        File file = new File(&quot;product.png&quot;);
        MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
        String mimeType = fileTypeMap.getContentType(file.getName());

        assertEquals(mimeType, &quot;image/png&quot;);
    }
}</code></pre>
<p><br><br></p>
<h3 id="jmiemagic">jMieMagic</h3>
<ul>
<li>build.gradle 에 추가한 이후 활용<ul>
<li><code>net.sf.jmimemagic:jmimemagic</code></li>
</ul>
</li>
</ul>
<pre><code class="language-java">class JMimeMagicTest{
    @Test
    public void whenUsingJmimeMagic_thenSuccess() {
        File file = new File(&quot;product.png&quot;);
        Magic magic = new Magic();
        MagicMatch match = magic.getMagicMatch(file, false);

        assertEquals(match.getMimeType(), &quot;image/png&quot;);
    }
}</code></pre>
<p><br><br></p>
<h3 id="apache-tika">Apache Tika</h3>
<ul>
<li>build.gradle에 추가한 이후 활용<ul>
<li><code>org.apache.tika:tika-core</code></li>
<li>Mime type을 찾는 메서드만 활용하기 위해, <code>tika-core</code> 적용</li>
</ul>
</li>
</ul>
<pre><code class="language-java">class TikaTest{
    @Test
    public void whenUsingTika_thenSuccess() {
        File file = new File(&quot;product.png&quot;);
        Tika tika = new Tika();
        String mimeType = tika.detect(file);

        assertEquals(mimeType, &quot;image/png&quot;);
    }
}</code></pre>
<p><br><br></p>
<h3 id="reference">REFERENCE</h3>
<ul>
<li><a href="https://www.baeldung.com/java-file-mime-type">https://www.baeldung.com/java-file-mime-type</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] 이미 업로드 된 원격 저장소 파일 지우기]]></title>
            <link>https://velog.io/@mein-figur/Git-%EC%9D%B4%EB%AF%B8-%EC%97%85%EB%A1%9C%EB%93%9C-%EB%90%9C-%EC%9B%90%EA%B2%A9-%EC%A0%80%EC%9E%A5%EC%86%8C-%ED%8C%8C%EC%9D%BC-%EC%A7%80%EC%9A%B0%EA%B8%B0</link>
            <guid>https://velog.io/@mein-figur/Git-%EC%9D%B4%EB%AF%B8-%EC%97%85%EB%A1%9C%EB%93%9C-%EB%90%9C-%EC%9B%90%EA%B2%A9-%EC%A0%80%EC%9E%A5%EC%86%8C-%ED%8C%8C%EC%9D%BC-%EC%A7%80%EC%9A%B0%EA%B8%B0</guid>
            <pubDate>Tue, 16 Nov 2021 13:20:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/31949092-1e21-48b9-b676-3562a8beb45b/image.png" alt=""></p>
<h3 id="원격-저장소에-이미-업로드-된-파일을-지우는-방법">원격 저장소에 이미 업로드 된 파일을 지우는 방법</h3>
<ul>
<li>로컬에서는 지우지 않고, 원격에서만 지우는 방법</li>
<li><strong>원격 저장소에 이미 push된 파일을 .gitignore에 추가하는 경우 자주 사용</strong></li>
<li>하단에 써있는 방법은 캐시를 통째로 날리는 방법</li>
</ul>
<pre><code>$ git rm -r --cached .
$ git add .
$ git commit -m &quot;commit message&quot;
$ git push</code></pre><p>위 코드에서, 핵심은 다음 코드이다.</p>
<pre><code>$ git rm -r --cached .</code></pre><p>현재 코드 상으로는 원격 저장소의 전체 파일을 삭제하는 방식이며, <code>.</code> 자리에 지우고자 하는 디렉토리나 파일이 오게 설정할 수도 있다.</p>
<pre><code>$ git rm -r --cached &lt;file&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Database]Redis]]></title>
            <link>https://velog.io/@mein-figur/DatabaseRedis</link>
            <guid>https://velog.io/@mein-figur/DatabaseRedis</guid>
            <pubDate>Wed, 03 Nov 2021 14:44:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/b6eeb653-6a8e-4d37-a471-e6046640dd2c/image.png" alt=""></p>
<h1 id="redis">Redis</h1>
<hr>
<ul>
<li>Redis❓</li>
<li>Redis 사용 용도🔍</li>
<li>Redis 특징🔍</li>
<li>주의사항⚠</li>
</ul>
<br>

<h2 id="redis❓">Redis❓</h2>
<hr>
<blockquote>
<p>Redis는 Remote dictionary server의 약자로써,  <code>키-값</code>구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터베이스 관리 시스템(<code>DBMS</code>)이다. 모든 데이터를 메모리에 저장하고 조회하기에 빠른 Read, Write 속도를 보장하는 비 관계형 데이터베이스이다. </p>
</blockquote>
<ul>
<li>크게 5가지 형식을 지원한다.<ul>
<li><code>String</code>, <code>Set</code>, <code>Sorted Set</code>, <code>Hash</code>, <code>List</code></li>
</ul>
</li>
<li>I/O가 빈번히 발생해 다른 저장 방식을 사용하면 효율이 떨어지는 경우에 사용</li>
</ul>
<br>

<h2 id="redis-사용-용도🔍">Redis 사용 용도🔍</h2>
<hr>
<ul>
<li>Message Queue</li>
<li>Shared Memory</li>
<li>Remote Dictionary<ul>
<li>RDBMS의 캐시 솔루션으로 사용 용도가 높음</li>
<li>Disk에서 데이터를 꺼내오는 것이 Memory에서 읽어들이는 것보다 천 배 가량 더 느림</li>
</ul>
</li>
</ul>
<br>

<h2 id="redis-특징🔍">Redis 특징🔍</h2>
<hr>
<ul>
<li>영속성(Persistance)을 지원하는 인메모리 데이터 저장소<ul>
<li>Redis는 데이터를 disk에 저장할 수 있음</li>
<li>저장하는 방식으로 <code>snapshot</code>, <code>AOF</code> 방식 활용</li>
<li>Redis 공식문서의 권장사항은 두 방식을 혼용해서 사용하는 것<ul>
<li>주기적으로 snapshot으로 백업하고, 다음 snapshot까지의 저장을 AOF방식으로 수행</li>
</ul>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>snapshot: 특정 시점의 데이터를 disk에 옮겨담는 방식으로, Blocking 방식의 SAVE와 Non-blocking 방식의 BGSAVE가 있음</p>
<p>AOF: Redis의 모든 write/update 연산 자체를 모두 log 파일에 기록하는 형태, 서버가 재시작할 시 write/update를 순차적으로 재실행, 데이터를 복구</p>
</blockquote>
<ul>
<li>읽기 성능 증대를 위한 서버 측 복제를 지원</li>
<li>쓰기 성능 증대를 위한 클라이언트 측 샤딩(Sharding)을 지원</li>
<li>다양한 데이터 타입</li>
<li>C언어로 작성되어 가비지 컬렉션 동작에 따른 성능 문제 등에서 자유로움</li>
</ul>
<br>

<h2 id="주의사항⚠">주의사항⚠</h2>
<hr>
<ul>
<li>서버에 장애가 생기는 경우, 데이터 유실이 발생하므로, snapshot과 AOF기능을 통한 복구 시나리오를 제대로 세워야 함</li>
<li>잘못된 데이터가 캐싱되지 않아야 함<ul>
<li>레디스와 캐싱하고자 하는 데이터 저장소의 데이터가 서로 일치하는지 주기적인 모니터링과 솔루션 필요</li>
</ul>
</li>
<li>생성한 키를 선택적으로 삭제하기 어려움<ul>
<li>일괄 삭제, 일정 시간 이후 삭제, 기간 만료 후 삭제 등 3가지 방법을 활용해 키를 삭제할 수 있음</li>
</ul>
</li>
</ul>
<br>

<br>

<h3 id="reference">REFERENCE</h3>
<ul>
<li><a href="https://brunch.co.kr/@skykamja24/575">레디스(Redis)는 언제 어떻게 사용하는 게 좋을까</a></li>
<li><a href="https://engkimbs.tistory.com/869">[Redis, 레디스] 레디스 소개 및 아키텍처, 주의할 점(Redis Overview, Redis Architecture, Tool Tip)</a></li>
<li><a href="https://jyejye9201.medium.com/%EB%A0%88%EB%94%94%EC%8A%A4-redis-%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-2b7af75fa818">레디스(Redis)란 무엇인가?</a></li>
<li><a href="https://ko.wikipedia.org/wiki/%EB%A0%88%EB%94%94%EC%8A%A4">레디스</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Data Structure]Trie]]></title>
            <link>https://velog.io/@mein-figur/Data-StructureTrie</link>
            <guid>https://velog.io/@mein-figur/Data-StructureTrie</guid>
            <pubDate>Wed, 20 Oct 2021 12:43:13 GMT</pubDate>
            <description><![CDATA[<h1 id="trie">Trie</h1>
<br>

<ul>
<li>Trie❓</li>
<li>시간 복잡도⏱</li>
<li>Code in Python🖋</li>
<li>Test</li>
</ul>
<br>

<h2 id="trie❓">Trie❓</h2>
<blockquote>
<p>입력되는 문자열을 트리 형식으로 만들어 보다 빠르게 문자열 검색을 가능하게 한 자료구조로, radix tree, 또는 prefix tree라고도 한다.</p>
<p>문자열을 검색할 때, 문자열이 많을 경우 자주 사용되며, 시간복잡도가 빠르기 때문에 검색엔진 사이트에서 제공하는 자동 완성 및 검색어 추천 기능에서도 사용되는 경우가 있다. 하지만, 각 노드에서 자식들에 대한 포인터들을 배열로 모두 저장하고 있다는 점에서 저장 공간의 크기가 크다는 단점도 존재한다.</p>
</blockquote>
<p><img src="https://camo.githubusercontent.com/7024b55e64516062054e9b5bccf35dc72d5e7a4cca88c8f57810804b955cb849/68747470733a2f2f74312e6461756d63646e2e6e65742f6366696c652f746973746f72792f323433353445333335383333413743463137" alt="img"></p>
<ul>
<li>Tree 구조로 이루어져 있다.</li>
<li>root 노드는 비어있다.</li>
<li>문자열의 끝을 알리는 flag가 존재</li>
</ul>
<br>

<h3 id="시간-복잡도⏱">시간 복잡도⏱</h3>
<ul>
<li>문자열의 길이가 <code>m</code>이라고 하였을 때, <code>O(m)</code>의 시간 복잡도를 가진다.</li>
</ul>
<br>

<br>

<h2 id="code-in-python🖋">Code in Python🖋</h2>
<ul>
<li>클래스 <code>Node</code>, <code>Trie</code>가 필요</li>
<li><code>Node</code>는 <code>key</code>, <code>data</code>, <code>children</code>으로 이루어져 있음<ul>
<li><code>key</code>: 현재 노드가 가지고 있는 문자</li>
<li><code>data</code>: 문자열이 끝난 경우, 해당 문자열을 <code>data</code>에 기록<ul>
<li>default값으로 None을 가지고 있음</li>
</ul>
</li>
<li><code>children</code>: 자식 노드들이 저장되는 딕셔너리<ul>
<li>key는 문자, value는 해당 문자를 key로 가진 노드</li>
</ul>
</li>
</ul>
</li>
<li><code>Trie</code>는 <code>head</code>만 가지고 있으며, <code>insert</code>, <code>search</code>함수가 기본적으로 존재<ul>
<li><code>head</code>는 루트 노드를 의미</li>
<li><code>insert</code>: <code>word</code>를 추가하는 함수, 각 문자열을 하나씩 확인하며, 없는 경우 새로운 노드를 연결하여 추가하는 방식, 마지막 노드의 <code>data</code>에 <code>word</code>를 저장</li>
<li><code>search</code>: <code>Trie</code>에 해당 <code>word</code>가 존재하는 지 유무를 확인, 각 문자를 하나씩 탐색하며 끝까지 도달한 후, 해당 노드의 <code>data</code>에 <code>word</code>가 저장된 경우만 <code>True</code>로 반환</li>
</ul>
</li>
</ul>
<pre><code class="language-python">class Node:
    def __init__(self, key, data=None):
        self.key = key # 현재 노드의 문자
        self.data = data # 단어가 끝나는 경우, 해당 단어를 data에 저장
        self.children = {} # 자식 노드들이 저장되는 딕셔너리, key는 문자, value는 노드


class Trie:
    def __init__(self):
        self.head = Node(None) # 루트 노드

    def insert(self, word): # 단어 추가용 함수
        current = self.head

        for w in word:
            if w not in current.children: # 해당 문자열이 없는 경우, 노드 생성 후 자식에 추가
                current.children[w] = Node(w)
            current = current.children[w] # 자식 노드로 이동
        current.data = word # 마지막 노드에 데이터 저장

    def search(self, word): # 단어 탐색용 함수
        current = self.head

        for w in word:
            if w in current.children: # 자식에 문자열이 있는 경우, 자식노드로 이동
                current = current.children[w]
            else: # 없는 경우, 단어가 없으므로 False
                return False

        if current.data: # 데이터가 저장되어 있는 경우에만 단어가 존재
            return True
        else: # 데이터가 저장되어 있지 않으면, 마지막 노드가 아니므로 False
            return False
</code></pre>
<br>

<h3 id="test">Test</h3>
<pre><code class="language-python">trie = Trie()
words = [&#39;cart&#39;, &#39;cow&#39;, &#39;call&#39;, &#39;cartoon&#39;]
for word in words:
    trie.insert(word)

print(trie.search(&#39;cart&#39;)) # True
print(trie.search(&#39;car&#39;)) # False
print(trie.search(&#39;calling&#39;)) # False</code></pre>
<br>

<br>

<br>

<h3 id="reference">REFERENCE</h3>
<ul>
<li><a href="https://ko.wikipedia.org/wiki/%ED%8A%B8%EB%9D%BC%EC%9D%B4_(%EC%BB%B4%ED%93%A8%ED%8C%85)">트라이, 컴퓨팅</a></li>
<li><a href="https://velog.io/@gojaegaebal/210126-%EA%B0%9C%EB%B0%9C%EC%9D%BC%EC%A7%8050%EC%9D%BC%EC%B0%A8-%ED%8A%B8%EB%9D%BC%EC%9D%B4Trie-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%85%90-%EB%B0%8F-%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0feat.-Class">트라이 알고리즘 개념 및 파이썬 구현하기</a></li>
<li><a href="https://m.blog.naver.com/cjsencks/221740232900">[Python/파이썬] Trie 알고리즘</a></li>
<li><a href="https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Data%20Structure/Trie.md">트라이(Trie)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SWEA][Python]#1486. 장훈이의 높은 선반]]></title>
            <link>https://velog.io/@mein-figur/SWEAPython1486.-%EC%9E%A5%ED%9B%88%EC%9D%B4%EC%9D%98-%EB%86%92%EC%9D%80-%EC%84%A0%EB%B0%98</link>
            <guid>https://velog.io/@mein-figur/SWEAPython1486.-%EC%9E%A5%ED%9B%88%EC%9D%B4%EC%9D%98-%EB%86%92%EC%9D%80-%EC%84%A0%EB%B0%98</guid>
            <pubDate>Sun, 10 Oct 2021 15:13:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/22287277-b132-4cdf-8b13-d42b9402f426/image.png" alt=""></p>
<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>Bit Masking 사용하여 경우의 수 판단</li>
<li>계산한 높이 <code>tmp</code>가 <code>B</code>보다 크거나 같으면서 가장 낮은 탑 <code>res</code>보다 낮은 경우, <code>tmp</code>를 <code>res</code>에 저장</li>
</ul>
<pre><code class="language-python">T = int(input())
for tc in range(1, T+1):
    N, B = map(int, input().split())
    emps = list(map(int, input().split()))

    res = 10000*N # 변수 초기화

    # Bit Masking
    for i in range(1, 2**N): 
        tmp = 0
        for j in range(N):
            if i &amp; (1&lt;&lt;j):
                tmp += emps[j]

        if tmp &gt;= B and res &gt; tmp :
            res = tmp

    print(f&#39;#{tc} {res-B}&#39;)
</code></pre>
<br>
<br>

<h3 id="📌후기">📌후기</h3>
<hr>
<p>비트마스킹을 써본 횟수가 적어서 아쉬웠는데, 이 기회에 비트마스킹을 써볼 수 있어서 좋았다. 다른 경우에서도 더 많이 활용해 봐야겠다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Network]Load Balancing, Load Balancer]]></title>
            <link>https://velog.io/@mein-figur/NetworkLoad-Balancing-Load-Balancer</link>
            <guid>https://velog.io/@mein-figur/NetworkLoad-Balancing-Load-Balancer</guid>
            <pubDate>Thu, 07 Oct 2021 17:12:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/cbabd700-8d48-4130-a00c-3e7bfbd0473a/image.png" alt=""></p>
<h1 id="load-balancing">Load Balancing</h1>
<ul>
<li>Load Balancing❓, Load Balancer❓</li>
<li>Scale-up &amp; Scale-out🔍</li>
<li>Load Balancing의 종류🔍</li>
<li>Load Balancer 주요 기능✔</li>
<li>Load Balancer 동작 방식🔍</li>
<li>Load Balancing Algorithm🔍</li>
<li>Load Balancer 오류 대비⚠</li>
</ul>
<br>

<br>

<h2 id="load-balancing❓-load-balancer❓">Load Balancing❓, Load Balancer❓</h2>
<blockquote>
<p>로드밸런싱(load balancing, 또는 부하 분산)은 컴퓨터 네트워크 기술의 일종으로, 둘 혹은 셋 이상의 중앙처리장치 혹은 저장치와 같은 컴퓨터 자원들에게 작업을 나누는 것을 의미한다.</p>
<p>쏟아지는 트래픽을 여러 대의 서버로 분산해주는 기술이 없다면, 한 곳의 서버에 모든 트래픽이 몰리는 상황이 발생한다. 아무리 성능이 뛰어난 서버도 모든 트래픽을 감당할 수 없기에, 여러 대의 서버를 구축하여 수많은 트래픽을 효과적으로 다뤄야 할 필요성이 있다. 이 때 필요한 기술이 로드 밸런싱이다.</p>
<p>로드밸런서는 <strong>서버에 가해지는 부하를 분산해주는 장치 또는 기술</strong>을 말한다. </p>
</blockquote>
<p><img src="https://post-phinf.pstatic.net/MjAxOTEyMTBfMjE3/MDAxNTc1OTU0ODk1ODQ3.-GJxkoK7Apn4l0K5L1OXN4NFGsseRoaNhW2r0KIQJdog.0BchcWEI-WS-uEb3iRRrD0JyO_6eZoIWh7xf4f4J2fMg.JPEG/%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%84%9C_%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98.jpg?type=w1200" alt="img"></p>
<ul>
<li>클라이언트와 서버풀(분산 네트워크를 구성하는 서버들의 그룹) 사이에 위치</li>
<li>한 대의 서버로 부하가 집중되지 않도록 트래픽을 관리해 각각의 서버가 최적의 퍼포먼스를 보일 수 있도록 함</li>
</ul>
<br>

<br>

<h2 id="scale-up--scale-out-🔍">Scale-up &amp; Scale-out 🔍</h2>
<blockquote>
<p>사업의 규모가 확장되고, 클라이언트의 수가 늘어나면 기존 서버로 증가된 트래픽에 대처할 수 없다. 이 때, 대처할 수 있는 방법은 크게 2가지가 있는데, 그것이 바로 <strong>Scale-up</strong>, <strong>Scale-out</strong> 이다.</p>
</blockquote>
<p><img src="https://post-phinf.pstatic.net/MjAxOTEyMTBfMjk1/MDAxNTc1OTU1MDI2NTY4.Zxj8nWGb6G6jtHDAZPPDf-dPZnpb_hsd7ydWw5lW7vAg.AucOXPJnmLyGiHr8KpVD9Dsy59FsWv5p7qJnSyW_YFAg.JPEG/%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1_%EC%8A%A4%EC%BC%80%EC%9D%BC.jpg?type=w1200" alt="img"></p>
<ul>
<li>Scale-up<ul>
<li>서버가 더 빠르게 동작하기 위해 하드웨어 성능을 올리는 방식</li>
<li>서버 자체의 성능을 확장</li>
</ul>
</li>
<li>Scale-out<ul>
<li>기존 서버와 동일하거나 낮은 성능의 서버를 두 대 이상 증설하여 운영</li>
<li>로드밸런싱이 반드시 필요</li>
</ul>
</li>
</ul>
<br>

<br>

<h2 id="load-balancing의-종류🔍">Load Balancing의 종류🔍</h2>
<ul>
<li>OSI 7계층에 따라 나뉨<ul>
<li>L2(Data Link): MAC 주소 기반 로드 밸런싱</li>
<li>L3(Network): IP주소 기반 로드 밸런싱</li>
<li>L4(Transport): 포트 번호 기반 로드 밸런싱</li>
<li>L7(Application): URL, HTTP 헤더, 쿠키 등 사용자의 요청을 기준으로 로드 밸런싱 </li>
</ul>
</li>
</ul>
<br>

<h3 id="l4-load-balancer">L4 Load Balancer</h3>
<ul>
<li>TCP/UDP 포트 정보를 바탕으로 함</li>
<li>데이터를 들여다보지 않고 패킷 레벨에서 로드를 분산하기 때문에 속도가 빠르고 효율이 높음</li>
<li>데이터의 내용을 복호화할 필요가 없어 안전함</li>
<li>패킷의 내용을 볼 수 없어 섬세한 라우팅 불가능</li>
<li>사용자의 IP가 수시로 바뀌는 경우라면 연속적인 서비스를 제공하기 어려움</li>
</ul>
<p><img src="https://post-phinf.pstatic.net/MjAxOTEyMTBfNCAg/MDAxNTc1OTU1MzY3OTM2.nG91HOEOh6Sc1AuUgbN3O4pcnEI-rh24UKSrrrjkrcsg.VcG18MidW4az7Oh0RQfRPLDBHNRyGayE1BsQxDImL3Ig.JPEG/L4-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1.jpg?type=w1200" alt="img"></p>
<br>

<h3 id="l7-load-balancer">L7 Load Balancer</h3>
<ul>
<li>TCP/UDP 정보는 물론 HTTP의 URL, FTP의 파일명, 쿠키 정보 등을 바탕으로 함</li>
<li>상위 계층에서 로드를 분산하므로 섬세한 라우팅 가능</li>
<li>캐싱 기능 제공</li>
<li>비정상적인 트래픽 사전에 필터링할 수 있어 서비스 안정성이 높음</li>
<li>클라이언트가 로드밸런서와 인증서를 공유하기 때문에 공격자가 로드밸런서를 통해 클라이언트의 데이터에 접근할 수 있는 보안 상의 위험성 존재</li>
</ul>
<p><img src="https://post-phinf.pstatic.net/MjAxOTEyMTBfMjA1/MDAxNTc1OTU1MzgxODY5.odnG4CRES0e5bH7sOKyWRP1c8uO_XC4VX9A3HPeI1JQg.lNL2eJYbMz6NX1e5YFzfHDMQHn4YrdOJR2VYHmq5e1Ig.JPEG/L7-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1.jpg?type=w1200" alt="img"></p>
<br>

<br>

<h2 id="load-balancer-주요-기능✔">Load Balancer 주요 기능✔</h2>
<ul>
<li>NAT(Network Address Translation)<ul>
<li>IP주소를 변환해주는 기능</li>
<li>Private IP를 Public IP로 변경(반대도 가능)</li>
</ul>
</li>
<li>Tunneling<ul>
<li>데이터를 캡슐화해서 연결된 상호 간에만 캡슐화된 패킷을 구별하여 해제 가능</li>
</ul>
</li>
<li>DSR(Direct Server Routing)<ul>
<li>서버에서 클라이언트로 되돌아가는 경우(요청에 대한 응답), 목적지를 클라이언트로 설정한 다음 네트워크 장비나 로드밸런서를 거치지 않고 바로 클라이언트로 찾아감</li>
<li>로드밸런서의 부하를 줄여줌</li>
</ul>
</li>
</ul>
<br>

<br>

<h2 id="load-balancer-동작-방식🔍">Load Balancer 동작 방식🔍</h2>
<ul>
<li>Bridge/Transparent Mode<ol>
<li>유저가 로드 밸런서로 요청 전송</li>
<li>로드 밸런서는 NAT 적용하여 IP/MAC 주소 변조, 실제 서버로 트래픽 요청</li>
<li>서버가 받은 요청에 대한 응답 전송</li>
<li>로드 밸런서는 NAT 적용하여 출발지 IP주소를 로드밸런서의 가상 IP주소로 변조하여 유저에게 전달</li>
</ol>
</li>
<li>Router Mode</li>
<li>One Arm Mode</li>
<li>DSR Mode</li>
</ul>
<br>

<br>

<h2 id="load-balancing-algorithm🔍">Load Balancing Algorithm🔍</h2>
<ul>
<li>라운드 로빈(Round Robin)<ul>
<li>서버에 들어온 요청을 순서대로 돌아가며 배정하는 방식</li>
<li>여러 대의 서버가 동일한 스펙을 갖고 있고, 서버와의 연결이 오래 지속되지 않는 경우 적합</li>
</ul>
</li>
<li>가중 라운드 로빈(Weighted Round Robin)<ul>
<li>각각의 서버마다 가중치를 매기고 가중치가 높은 서버에 요청을 우선적으로 배분</li>
<li>서버들의 트래픽 처리 능력이 다른 경우 사용되는 방식</li>
</ul>
</li>
<li>IP 해시(IP Hash, Source Hash Scheduling)<ul>
<li>클라이언트의 IP주소를 특정 서버로 매핑하여 요청 </li>
<li>사용자가 항상 동일한 서버로 연결되는 것을 보장</li>
</ul>
</li>
<li>최소 연결(Least Connection)<ul>
<li>요청이 들어온 시점에 가장 적은 연결상태를 보이는 서버에 우선적으로 배분</li>
<li>세션이 길어지거나, 분배된 트래픽이 일정하지 않은 경우에 적합</li>
</ul>
</li>
<li>최소 리스폰 타임(Least Response Time)<ul>
<li>서버의 현재 연결 상태와 응답 시간을 고려하여 트래픽 배분</li>
<li>가장 적은 연결 상태와 가장 짧은 응답시간을 보이는 서버에 우선적으로 로드를 배분</li>
</ul>
</li>
</ul>
<br>

<br>

<h2 id="load-balancer-오류-대비⚠">Load Balancer 오류 대비⚠</h2>
<ul>
<li>Load Balancer를 이중화하여 장애를 대비</li>
</ul>
<p><img src="https://nesoy.github.io/assets/posts/20180602/8.gif" alt="No Image"></p>
<ul>
<li>이중화된 Load Balancer들은 서로 Health Check를 함</li>
<li>Primary Load Balancer가 동작하지 않으면, 여분의 Load Balancer로 변경 후 운영</li>
</ul>
<br>

<br>

<h3 id="reference">REFERENCE</h3>
<ul>
<li><a href="https://ko.wikipedia.org/wiki/%EB%B6%80%ED%95%98%EB%B6%84%EC%82%B0">부하분산-위키백과</a></li>
<li><a href="https://m.post.naver.com/viewer/postView.nhn?volumeNo=27046347&amp;memberNo=2521903">로드밸런서(Load Balancer)의 개념과 특징</a></li>
<li><a href="https://nesoy.github.io/articles/2018-06/Load-Balancer">로드 밸런서(Load Balancer)란?</a></li>
<li><a href="https://vaert.tistory.com/189">로드밸런서란?(L4, L7)</a></li>
<li><a href="https://deveric.tistory.com/91">로드밸런서의 종류와 동작방식</a></li>
<li><a href="https://stevenjlee.net/2020/06/30/%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%98-%EB%B6%80%ED%95%98%EB%B6%84%EC%82%B0-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1-load-balancing-%EA%B7%B8/">네트워크의 부하분산, 로드밸런싱(Load Balancing) 그리고 로드밸런서(Load Balancer)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Network]Proxy Server]]></title>
            <link>https://velog.io/@mein-figur/NetworkProxy-Server</link>
            <guid>https://velog.io/@mein-figur/NetworkProxy-Server</guid>
            <pubDate>Wed, 06 Oct 2021 16:45:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/fa7a7384-d510-4945-8302-66a119c0e1ee/image.png" alt=""></p>
<h1 id="proxy-server">Proxy Server</h1>
<br>

<ul>
<li>Proxy Server❓</li>
<li>Forward Proxy🔍</li>
<li>Reverse Proxy🔍</li>
</ul>
<br>

<br>

<h2 id="proxy-server❓">Proxy Server❓</h2>
<blockquote>
<p>프록시 서버(Proxy Server)는 클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용 프로그램을 가리킨다. 서버와 클라이언트 사이에 중계기로서 대리로 통신을 수행하는 것을 가리켜 &#39;프록시&#39;, 그 중계 기능을 하는 것을 프록시 서버라고 부른다.</p>
</blockquote>
<ul>
<li>인터넷에서 유저를 대신해서 가져오는 서버<ul>
<li>클라이언트와 서버 사이의 통신에 중계 역할</li>
<li>클라이언트 - 프록시 서버 - 서버 의 구조를 지님</li>
</ul>
</li>
</ul>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/Open_proxy_h2g2bob.svg/350px-Open_proxy_h2g2bob.svg.png" alt="img"></p>
<ul>
<li><p>프록시 서버 중 일부는 서버에 요청된 내용들을 <code>캐시</code>를 이용하여 저장</p>
<ul>
<li>캐시 안의 정보를 요청하는 경우, 바로 정보를 제공함으로써 시간 절약</li>
</ul>
</li>
<li><p>외부와의 트래픽을 줄이게 됨으로써 네트워크 병목 현상 방지</p>
</li>
<li><p>프록시 서버를 활용함으로써, 클라이언트 또는 서버의 정보를 숨길 수 있음</p>
</li>
</ul>
<br>

<br>

<h2 id="forward-proxy🔍">Forward Proxy🔍</h2>
<blockquote>
<p>클라이언트가 인터넷에 직접 접근하는 것이 아닌, Forward Proxy Server가 요청을 받고, 인터넷에 연결하여 결과를 다시 클라이언트에 전달해준다.</p>
</blockquote>
<ul>
<li>클라이언트가 요청하는 End Point: 실제 서버 도메인</li>
<li>Forward Proxy에서는 클라이언트의 정보가 감춰짐<ul>
<li>요청을 받는 서버는 클라이언트가 누구인지 알 수 없음</li>
</ul>
</li>
</ul>
<p><img src="https://github.com/ParkJiwoon/PrivateStudy/raw/master/images/forward-proxy.png" alt="img"></p>
<br>

<br>

<h2 id="reverse-proxy🔍">Reverse Proxy🔍</h2>
<blockquote>
<p>클라이언트가 인터넷에 데이터를 요청하면 Reverse Proxy Server가 요청을 받아 내부 서버에서 데이터를 받은 후 클라이언트에 전달</p>
</blockquote>
<ul>
<li>클라이언트가 요청하는 End Point: 프록시 서버의 도메인</li>
<li>Reverse Proxy에서는 서버의 정보가 감춰짐<ul>
<li>클라이언트는 실제 서버의 정보를 알 수 없음</li>
</ul>
</li>
</ul>
<p><img src="https://github.com/ParkJiwoon/PrivateStudy/raw/master/images/reverse-proxy.png" alt="img"></p>
<br>

<br>

<h3 id="reference">Reference</h3>
<ul>
<li><a href="https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9D%EC%8B%9C_%EC%84%9C%EB%B2%84">프록시 서버</a></li>
<li><a href="https://liveyourit.tistory.com/251">프록시 서버란? 원리와 사용 목적</a></li>
<li><a href="https://bcp0109.tistory.com/194">Forward Proxy, Reverse Proxy 정의와 차이점</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Python]표 편집]]></title>
            <link>https://velog.io/@mein-figur/ProgrammersPython%ED%91%9C-%ED%8E%B8%EC%A7%91</link>
            <guid>https://velog.io/@mein-figur/ProgrammersPython%ED%91%9C-%ED%8E%B8%EC%A7%91</guid>
            <pubDate>Wed, 29 Sep 2021 11:43:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/efe3abbe-41a7-4eab-92d4-cab9ce7f02ea/image.png" alt=""></p>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/81303?language=python3">https://programmers.co.kr/learn/courses/30/lessons/81303?language=python3</a></p>
<br>

<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이실패">내가 쓴 풀이(실패)</h4>
<ul>
<li>리스트의 인덱스를 활용하여 구현</li>
<li><code>C</code>의 경우, <code>O</code>이 나올때까지 현재 위치에서 뒤로 밀다가 없으면 앞쪽에서 찾는 방식 활용<ul>
<li>사라진 인덱스는 <code>trash</code>에 저장</li>
<li>해당 인덱스의 <code>table</code>값은 <code>X</code>로 변경</li>
</ul>
</li>
<li><code>Z</code>의 경우, <code>trash</code>에 저장한 인덱스를 꺼내 <code>table</code>의 값을 <code>O</code>로 변경</li>
<li><code>U</code>, <code>D</code>의 경우, <code>X</code>인 경우를 배제하고 움직이는 횟수를 활용하여 구현</li>
<li>정확도는 통과하였으나, 효율성에서 5개의 테스트 케이스만 통과</li>
</ul>
<pre><code class="language-python">def solution(n, k, cmd):
    table = [&#39;O&#39; for _ in range(n)]
    trash = []
    for c in cmd :
        if c == &#39;C&#39;:
            trash.append(k)
            table[k] = &#39;X&#39;
            # k 위치 변경
            while k &lt; n and table[k] == &#39;X&#39; :
                k += 1
            if k == n:
                k -= 1
            while 0 &lt;= k and table[k] == &#39;X&#39;:
                k -= 1

        elif c == &#39;Z&#39;:
            table[trash.pop()] = &#39;O&#39;
        else:
            flag = 1 if c[0] == &#39;D&#39; else 0
            move, cnt = int(c[2:]), 0
            while cnt &lt; move :
                k = k+1 if flag else k-1
                if table[k] == &#39;O&#39;:
                    cnt += 1



    return &#39;&#39;.join(table)</code></pre>
<br>


<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>링크드 리스트 활용<ul>
<li>딕셔너리의 key를 인덱스값으로, value를 [앞의 값, 뒤의 값] 의 쌍으로 구현</li>
</ul>
</li>
<li><code>C</code>의 경우, 해당 인덱스를 <code>trash</code>에 저장<ul>
<li>결과값도 <code>X</code>로 변경</li>
<li>앞의 노드와 뒤의 노드를 연결</li>
<li>현재 노드가 맨 앞, 맨 뒤인 경우를 고려하며, <code>k</code>값도 맞춰서 이동</li>
</ul>
</li>
<li><code>Z</code>의 경우, <code>trash</code>에서 <code>pop</code><ul>
<li>결과값 <code>O</code>로 변경</li>
<li>꺼내온 노드의 위치를 파악하여 사이에 넣고 연결</li>
</ul>
</li>
<li><code>U</code>, <code>D</code>의 경우, 이전, 이후 값들을 보며 노드를 횟수만큼 이동</li>
</ul>
<pre><code class="language-python">def solution(n, k, cmd):
    res = [&#39;O&#39; for _ in range(n)]
    linked_list = {i:[i-1,i+1] for i in range(n)}
    trash = []

    for c in cmd:
        now = c[0]
        if now == &#39;D&#39;:
            move = int(c[2:])
            for _ in range(move):
                k = linked_list[k][1]
        elif now == &#39;U&#39;:
            move = int(c[2:])
            for _ in range(move):
                k = linked_list[k][0]
        elif now == &#39;C&#39;:
            pre,nex = linked_list[k][0], linked_list[k][1]
            trash.append(k)
            res[k] = &#39;X&#39;
            if pre &gt;= 0:
                linked_list[pre][1] = nex

            if nex &lt; n :
                linked_list[nex][0] = pre
                k = nex
            else :
                k = pre

        else :
            now = trash.pop()
            res[now] = &#39;O&#39;
            pre, nex = linked_list[now][0], linked_list[now][1]
            if pre &gt;= 0 :
                linked_list[pre][1] = now

            if nex &lt; n:
                linked_list[nex][0] = now

    return &#39;&#39;.join(res)</code></pre>
<br>
<br>



<h3 id="📌후기">📌후기</h3>
<hr>
<p>링크드 리스트를 쉽게 구현할 수 있는 방법을 알았던 문제였다. 문제를 해결하는 동안, 정말 많은 시간이 소요되었지만 링크드 리스트 활용법을 알게 되었다는 점은 상당히 만족스럽다. 이전에 링크드 리스트를 활용할 때는 객체를 직접 만들어 활용하였는데, 간단한 경우 딕셔너리를 통해 쉽게 만들 수 있다는 것을 알게 되었다! 효율성과 같은 문제에서 자주 활용할 수 있을 것이라고 생각한다.</p>
<p>카카오 테크 블로그의 풀이를 보면서, <strong>Fenwick Tree</strong>를 활용하여 문제를 해결할 수 있다는 것도 읽었는데, 아직 그 방법에 대해서는 잘 모르겠다. 한번 연구해 봐야 겠다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Python]로또의 최고 순위와 최저 순위]]></title>
            <link>https://velog.io/@mein-figur/ProgrammersPython%EB%A1%9C%EB%98%90%EC%9D%98-%EC%B5%9C%EA%B3%A0-%EC%88%9C%EC%9C%84%EC%99%80-%EC%B5%9C%EC%A0%80-%EC%88%9C%EC%9C%84</link>
            <guid>https://velog.io/@mein-figur/ProgrammersPython%EB%A1%9C%EB%98%90%EC%9D%98-%EC%B5%9C%EA%B3%A0-%EC%88%9C%EC%9C%84%EC%99%80-%EC%B5%9C%EC%A0%80-%EC%88%9C%EC%9C%84</guid>
            <pubDate>Mon, 27 Sep 2021 13:21:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/69c76acc-580e-41b4-a301-5dfcc94d2e77/image.png" alt=""></p>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/77484">https://programmers.co.kr/learn/courses/30/lessons/77484</a></p>
<br>

<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li><p>공통으로 가지고 있는 숫자, 0의 개수를 통해 등수를 판단 가능</p>
</li>
<li><p><code>same</code> : set을 활용하여 공통적으로 갖고 있는 숫자의 개수를 확인</p>
</li>
<li><p><code>offset</code>: <code>lottos</code>에서 0의 갯수 확인</p>
</li>
<li><p><code>minimum</code>: 일치하는 숫자가 2 미만인 경우 6등, 이외의 경우는 7-<code>same</code></p>
</li>
<li><p><code>maximum</code>: <code>offset</code>이 6인 경우 무조건 1등, 그 외의 경우는 <code>minimum</code>-<code>offset</code></p>
</li>
</ul>
<pre><code class="language-python">def solution(lottos, win_nums):
    same = len(set(lottos) &amp; set(win_nums))
    offset = lottos.count(0)
    minimum = 7-same if same &gt; 1 else 6
    maximum = minimum - offset if offset &lt; 6 else 1
    return [maximum, minimum]</code></pre>
<br>

<br>



<h3 id="📌후기">📌후기</h3>
<hr>
<p>레벨1 문제, 무난하게 해결했다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NETWORK] HTTP & HTTPS]]></title>
            <link>https://velog.io/@mein-figur/NETWORK-HTTP-HTTPS</link>
            <guid>https://velog.io/@mein-figur/NETWORK-HTTP-HTTPS</guid>
            <pubDate>Sun, 26 Sep 2021 14:00:04 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/bead20d6-45a0-4811-91bb-615fc6523289/NETWORK.png" alt=""></p>
<h1 id="📌http--https">📌HTTP &amp; HTTPS</h1>
<hr>
<ul>
<li>HTTP<ul>
<li>HTTP의 정의</li>
<li>HTTP의 특징</li>
<li>HTTP의 문제점</li>
</ul>
</li>
<li>HTTPS<ul>
<li>HTTPS의 정의</li>
<li>공개키/개인키</li>
</ul>
</li>
<li>HTTP, HTTPS의 차이</li>
</ul>
<br>

<br>

<h2 id="http❓">HTTP❓</h2>
<hr>
<blockquote>
<p>HTTP란 HypterText Transfer Protocol의 약자로, 웹 상에서 클라이언트와 서버가 서로 정보를 주고받을 수 있는 프로토콜입니다. TCP/IP 기반으로 서버와 클라이언트 간의 요청과 응답을 전송한다. HTTP에서는 80번 포트를 통해 클라이언트는 자원을 요청하고, 서버는 자원을 제공한다. </p>
</blockquote>
<p><img src="https://images.velog.io/images/mein-figur/post/d92593f9-3f86-4f78-a798-35161a80e9a0/image.png" alt=""></p>
<br>

<h3 id="http의-특징🔍">HTTP의 특징🔍</h3>
<ul>
<li>TCP 기반의 통신</li>
<li>비연결 지향 (connectionless)<ul>
<li>서버는 요청에 대한 응답을 보낸 후 연결을 끊음</li>
</ul>
</li>
<li>무상태 (stateless)<ul>
<li>연결을 끊는 순간 클라이언트와 서버 간의 통신이 끝나며 상태 정보가 유지되지 않음</li>
<li>클라이언트와 서버가 주고 받는 메세지들은 서로 완전히 독립적</li>
</ul>
</li>
<li>클라이언트와 서버의 지속적인 관계 유지를 위해, <strong>쿠키</strong>와 <strong>세션</strong>이 존재 </li>
</ul>
<br>

<h3 id="http의-문제점⚠">HTTP의 문제점⚠</h3>
<ul>
<li>완전성을 증명할 수 없어 변조 가능</li>
<li>도청 가능</li>
<li>통신 상대를 확인하지 않기에 위장 가능</li>
</ul>
<br>

<br>

<h2 id="https❓">HTTPS❓</h2>
<hr>
<blockquote>
<p>HTTPS란 HyperText Transfer Protocol over Secure socket layer의 약자입니다. 일반 HTTP 프로토콜에서는 서버에서 브라우저로 전송되는 정보가 암호화되지 않는다는 문제점이 존재하였는데, 이를 SSL이나 TSL 프로토콜을 활용해 보안을 강화시킨 프로토콜이다. 즉, HTTP에 데이터 암호화가 추가된 프로토콜이라고 볼 수 있으며, HTTPS에서 HTTP는 SSL과 통신하고, SSL이 TCP와 통신하게 된다. HTTP와 다르게 443번 포트를 활용하며, 네트워크 상에서 중간에 제 3자가 정보를 볼 수 없도록 공개키 암호화를 지원하고 있다. </p>
<p>HTTPS는 HTTP 자체를 암호화하는 것이 아니라, HTTP를 사용해서 운반하는 내용(Body)를 암호화한다. HTTP Header는 암호화하지 않는다.</p>
</blockquote>
<ul>
<li>SSL이 점차 폭넓게 사용되면서, 표준화 기구인 IETF의 관리로 TLS라는 이름으로 바뀌었다.<ul>
<li>TLS 1.0은 SSL 3.0을 계승함</li>
</ul>
</li>
<li>SSL(TLS)에서 사용하는 인증서로 상대방을 확인</li>
</ul>
<p><img src="https://images.velog.io/images/mein-figur/post/a71d4b8c-f392-42ca-b83d-25fde3777f0e/image.png" alt=""></p>
<br>

<h3 id="공개키개인키🔍">공개키/개인키🔍</h3>
<ul>
<li>HTTPS는 공개키/개인키 암호화 방식을 사용하여 데이터를 암호화하며, 공개키와 개인키는 서로를 위한 1쌍의 키이다.</li>
<li>HTTPS에서는 대칭키 암호화 기법을 사용한다.<ul>
<li>공개키의 신뢰성을 위해 CA 인증서를 사용</li>
<li>인증 과정<ol>
<li>서버의 공개키를 인증 기관(CA)에 등록</li>
<li>인증 기관은 해당 서버의 유효성을 판단한 후, <strong>인증 기관의 비밀키로 서버의 공개키에 디지털 서명으로 공개키 인증서를 작성</strong> 후 등록
<strong><code>공개키 인증서</code> = <code>서버의 공개키</code> + <code>인증 기관의 디지털 서명</code>+ <code>암호화 된 사이트 정보</code></strong>
인증 기관의 공개키는 사전에 브라우저에 내장되어 있음</li>
<li>클라이언트가 서버에 접속요청을 하면 서버는 인증 기관에서 받은 인증서를 전송</li>
<li>클라이언트는 <strong>브라우저에 내장된 인증 기관의 공개키로 디지털 서명을 검증해 신뢰할 수 있는 공개키인지 확인</strong></li>
<li>클라이언트는 대칭키 생성(공개키, 비밀키)</li>
<li>클라이언트는 생성한 <strong>공개키를 서버의 공개키로 암호화해 서버에게 전송</strong></li>
<li>서버는 자신의 <strong>비밀키로 해당 내용을 복호화하고 그 대칭키를 가지고 리소스 교환</strong></li>
</ol>
</li>
</ul>
</li>
</ul>
<br>

<br>

<h2 id="http-https의-차이정리✔">HTTP, HTTPS의 차이(정리)✔</h2>
<ul>
<li><p>HTTP는 암호화가 추가되지 않아 보안에 취약함</p>
</li>
<li><p>HTTPS는 안전하게 데이터를 주고 받을 수 있음</p>
</li>
<li><p>HTTPS는 HTTP에 비해 처리 속도가 느림</p>
<ul>
<li>SSL을 통해 통신이 이루어지는 과정에서 리소스를 소비하며, 통신 속도가 떨어짐</li>
<li>최근에는 CPU의 성능 향상, 메모리의 용량 증가로 속도의 차이가 줄어듦</li>
</ul>
</li>
<li><p>HTTPS는 인증서를 발급하고, 유지하기 위한 추가 비용 발생</p>
</li>
</ul>
<br>

<br>

<br>



<h3 id="reference">REFERENCE</h3>
<ul>
<li><a href="https://mangkyu.tistory.com/98">(Web) HTTP와 HTTPS 및 차이점</a></li>
<li><a href="http://blog.wishket.com/http-%ea%b7%b8%eb%a6%ac%ea%b3%a0-https%ec%9d%98-%ec%9d%b4%ed%95%b4/">HTTP, 그리고 HTTPS의 이해</a></li>
<li><a href="http://blog.wishket.com/http-vs-https-%EC%B0%A8%EC%9D%B4-%EC%95%8C%EB%A9%B4-%EC%82%AC%EC%9D%B4%ED%8A%B8%EC%9D%98-%EB%A0%88%EB%B2%A8%EC%9D%B4-%EB%B3%B4%EC%9D%B8%EB%8B%A4/">HTTP VS HTTPS 차이, 알면 사이트의 레벨이 보인다</a></li>
<li><a href="https://github.com/WooVictory/Ready-For-Tech-Interview/blob/master/Network/HTTP%2C%20HTTPS.md">HTTP, HTTPS</a></li>
<li><a href="https://velog.io/@ss-won/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP%EC%99%80-HTTPS">HTTP와 HTTPS</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Python]광고 삽입]]></title>
            <link>https://velog.io/@mein-figur/ProgrammersPython%EA%B4%91%EA%B3%A0-%EC%82%BD%EC%9E%85</link>
            <guid>https://velog.io/@mein-figur/ProgrammersPython%EA%B4%91%EA%B3%A0-%EC%82%BD%EC%9E%85</guid>
            <pubDate>Fri, 24 Sep 2021 13:43:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/86194d3d-de82-4325-a6d9-1704024f0aa8/image.png" alt=""></p>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/72414">https://programmers.co.kr/learn/courses/30/lessons/72414</a></p>
<br>

<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li><code>time_to_sec</code> : <code>00:00:00</code>로 표기된 시간을 초로 변환</li>
<li><code>sec_to_time</code>: 초로 표기된 시간을 <code>00:00:00</code>의 형태로 변환</li>
<li><code>DP</code>를 활용하여 해결</li>
<li><code>logs</code>의 값들을 통해 시작 시간, 끝나는 시간을 확인하고, 초기화 한 리스트 <code>times</code>에 추가<ul>
<li>시작 시간 + 1, 끝나는 시간 -1</li>
<li>모든 <code>logs</code>의 내용을 처리한 후, <code>times</code>의 값을 처음부터 읽으며 값을 누적시킴</li>
</ul>
</li>
<li><code>times</code>의 시간들을 읽어가며, 최대값이 나타나는 구간을 확인<ul>
<li>그 때의 시작 값을 <code>00:00:00</code>의 형태로 리턴</li>
<li>앞의 값을 빼주고, 뒤에 값을 더해주는 과정으로 진행</li>
</ul>
</li>
</ul>
<pre><code class="language-python"># 시간을 초로 변환
def time_to_sec(time):
    return int(time[:2])*3600 + int(time[3:5])*60 + int(time[6:])

# 초를 시간으로 변환
def sec_to_time(sec):
    hour, sec = sec//3600, sec%3600
    minute, sec = sec//60, sec%60
    hour = str(hour).rjust(2, &#39;0&#39;) # 일의 자리인 경우를 고려
    minute = str(minute).rjust(2, &#39;0&#39;)
    sec = str(sec).rjust(2,&#39;0&#39;)
    return f&#39;{hour}:{minute}:{sec}&#39;

def solution(play_time, adv_time, logs):
    # 플레이 시간, 광고 시간을 초로 변환
    # 전체 플레이 시간 기준으로 dp 구현
    play_sec = time_to_sec(play_time)
    adv_sec = time_to_sec(adv_time)
    times = [0 for _ in range(play_sec+1)]

    # 시작점에 +1, 끝점에 -1 설정
    for log in logs:
        start, end = log[:8], log[9:]
        times[time_to_sec(start)] += 1
        times[time_to_sec(end)] -= 1

    # 앞서 설정한 값들을 기준으로, 해당 시간대의 총 재생기록 표시
    for idx in range(1, play_sec+1):
        times[idx] += times[idx-1]

    # 0초 기준으로 초기화
    now = sum(times[:adv_sec]) # 현재 누적 재생 시간
    result = now # 최대 누적 재생 시간
    answer = 0 # 최적의 위치
    for idx in range(1, play_sec+2-adv_sec) :
        now += times[idx+adv_sec-1]-times[idx-1] # 맨 앞 값 제거, 맨 뒤 값 추가
        if result &lt; now : # 크기 비교
            answer, result = idx, now

    return sec_to_time(answer)</code></pre>
<p><br><br></p>
<h3 id="📌후기">📌후기</h3>
<hr>
<p>마지막의 최대 값을 구하는 과정에서, 처음에 <code>sum</code>을 다수 활용했었는데, 시간 초과 이슈가 발생했었다. 이러한 문제를 해결하고자, 인덱스를 이동하며 <code>sum</code>을 하는 과정을 앞의 값을 빼고, 뒤의 값을 더하는 방식으로 구현하였다. 전체적인 구조는 <code>DP</code>를 활용하여 잘 해결할 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Python]빛의 경로 사이클]]></title>
            <link>https://velog.io/@mein-figur/ProgrammersPython%EB%B9%9B%EC%9D%98-%EA%B2%BD%EB%A1%9C-%EC%82%AC%EC%9D%B4%ED%81%B4</link>
            <guid>https://velog.io/@mein-figur/ProgrammersPython%EB%B9%9B%EC%9D%98-%EA%B2%BD%EB%A1%9C-%EC%82%AC%EC%9D%B4%ED%81%B4</guid>
            <pubDate>Tue, 21 Sep 2021 15:06:17 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/2fc60dab-6090-4d9e-a788-9979cab2357b/image.png" alt="">
<a href="https://programmers.co.kr/learn/courses/30/lessons/86052">https://programmers.co.kr/learn/courses/30/lessons/86052</a></p>
<br>

<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>각 방향 이동 방법을 저장한 리스트 <code>d</code></li>
<li>격자의 값이 <code>R</code>, <code>L</code>인 경우, 경로의 변경 방법이 적힌 딕셔너리 <code>left</code>, <code>right</code><ul>
<li>ex) <code>right</code>에서  key인 0은 d[0]을 말하고, d[0] 방향은 <code>right</code>을 만나면 value인 3, 즉 d[3] 방향으로 바뀜을 의미</li>
</ul>
</li>
<li>각 격자에서 모든 방향 탐색을 하였는지 판단하기 위한 리스트 <code>case</code><ul>
<li>모든 값을 1로 초기화</li>
</ul>
</li>
<li>각 격자에서 모든 방향을 탐색(Brute Force)<ul>
<li>해당 <code>case</code>값이 0인 경우, 이미 탐색한 경로이므로 <code>continue</code></li>
<li>탐색하지 않은 경우, 길이 판단을 위해 변수 <code>cnt</code>를 0으로 설정</li>
<li>경로를 계속 이동하며, 처음 위치로 돌아올 때 까지 <code>while</code>문 진행</li>
<li>위치를 계속 바꾸기 위한 변수 <code>tx</code>, <code>ty</code>, <code>ti</code><ul>
<li><code>ti</code>는 방향을 말함</li>
</ul>
</li>
<li><code>tx</code>, <code>ty</code>, <code>ti</code>가 격자를 만나며 다음 경로와 방향을 다시 <code>tx</code>, <code>ty</code>, <code>ti</code>에 저장</li>
</ul>
</li>
</ul>
<pre><code class="language-python">def solution(grid):
    # 이동 방향용 리스트 d
    d = [[-1, 0], [1, 0], [0, 1], [0, -1]]
    # 격자의 값에 따른 방향 이동 방법
    right = {0: 3, 1: 2, 2: 0, 3: 1}
    left = {0: 2, 1:3, 2: 1, 3: 0}

    answer = []
    w, h = len(grid[0]), len(grid)
    # 각 격자에서의 모든 방향을 이동하였는지 판단하는 리스트 case
    cases = [[[1]*4 for _ in range(w)] for _ in range(h)]
    for y in range(h):
        for x in range(w):
            for i in range(4):
                # 이미 이동한 적 있는 방향은 판단 X
                if not cases[y][x][i]:
                    continue
                cnt = 0 # 길이 판단을 위한 변수
                ty, tx, ti = y, x, i # 위치 ty, tx, 방향 ti
                while True:
                    cases[ty][tx][ti] -= 1
                    cnt += 1
                    now = grid[ty][tx]
                    # 현재 격자의 값을 확인하여 방향 결정
                    if now == &#39;L&#39;:
                        ti = left[ti]
                    elif now == &#39;R&#39; :
                        ti = right[ti]
                    tx, ty = (tx+d[ti][1])%w, (ty+d[ti][0])%h
                    # 처음 출발점에 도착하면 완료
                    if tx == x and ty == y and ti == i:
                        break
                answer.append(cnt)

    # 값을 정렬 후 리턴
    answer.sort()
    return answer</code></pre>
<p><br><br></p>
<h3 id="📌후기">📌후기</h3>
<hr>
<p>문제를 처음 해결할 당시, 잘 해결이 되지 않아 상당히 고민했던 문제였다! 결과적으로는 문제를 제대로 읽지 않아서 처음에 한동한 해결하지 못했었다.... 문제를 똑바로 봐야 한다는 것을 다시 한 번 확실히 깨달은 문제였다!</p>
<p>완전 탐색을 통해 해결하였는데, 당시 문제를 풀 때 1등분이 엄청 빠르게 해결하던데,,,, 방법이 무엇인지 알고 싶다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ][Python]체스판 다시 칠하기 #1018]]></title>
            <link>https://velog.io/@mein-figur/BOJPython%EC%B2%B4%EC%8A%A4%ED%8C%90-%EB%8B%A4%EC%8B%9C-%EC%B9%A0%ED%95%98%EA%B8%B0-1018</link>
            <guid>https://velog.io/@mein-figur/BOJPython%EC%B2%B4%EC%8A%A4%ED%8C%90-%EB%8B%A4%EC%8B%9C-%EC%B9%A0%ED%95%98%EA%B8%B0-1018</guid>
            <pubDate>Sun, 19 Sep 2021 15:49:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/e907c368-5868-4e1f-a304-616cd9024a3e/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/1018">https://www.acmicpc.net/problem/1018</a></p>
<br>

<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>범위 내에서 가능한 모든 체스판 확인(Brute Force)</li>
<li><code>tmp1</code>은 <code>W</code>로 시작하는 체스판, <code>tmp2</code>는 <code>B</code>로 시작하는 체스판</li>
<li><code>c1</code>은 <code>tmp1</code>로 색칠할 때 바꿔야 하는 판 개수, <code>c2</code>는 <code>tmp2</code>로 색칠할 때 바꿔야 하는 판 개수</li>
<li>가장 작은 판 개수 찾아서 출력</li>
</ul>
<pre><code class="language-python">n, m = map(int, input().split())
l1, l2 = &#39;WB&#39;*4, &#39;BW&#39;*4
arr = [input() for _ in range(n)]
res = 64
for iy in range(n-8+1):
    for ix in range(m-8+1):
        c1, c2 = 0, 0

        for y in range(8):
        #tmp1은 W로 시작하는 체스판, tmp2는 B로 시작하는 체스판
            if y % 2: 
                tmp1, tmp2 = l1, l2
            else:
                tmp2, tmp1 = l1, l2
            for x in range(8):
                if arr[iy+y][ix+x] != tmp1[x]:
                    c1 += 1
                elif arr[iy+y][ix+x] != tmp2[x]:
                    c2 += 1

        res = min(res, c1, c2)

print(res)
</code></pre>
<p><br><br></p>
<h3 id="📌후기">📌후기</h3>
<hr>
<p>완전 탐색으로 해결하였다! 탐색하는 방법이 어렵지 않아서 무난하게 해결할 수 있었다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ][Python]DFS와 BFS #1260]]></title>
            <link>https://velog.io/@mein-figur/BOJPythonDFS%EC%99%80-BFS-1260</link>
            <guid>https://velog.io/@mein-figur/BOJPythonDFS%EC%99%80-BFS-1260</guid>
            <pubDate>Sun, 19 Sep 2021 14:06:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/3c1a54fd-eeac-4b13-836d-0c2449ebe800/image.png" alt=""></p>
<p><a href="https://www.acmicpc.net/problem/1260">https://www.acmicpc.net/problem/1260</a></p>
<br>

<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>각 정점에 연결된 정점들의 리스트를 딕셔너리로 구현</li>
<li>정점의 번호가 작은 것부터 탐색한다고 하였으므로, 각 리스트들을 정렬</li>
<li>dfs, bfs 진행</li>
</ul>
<pre><code class="language-python">from collections import deque

n, m, v = map(int, input().split())
connected = {i: [] for i in range(1, n + 1)}
for _ in range(m):
    n1, n2 = map(int, input().split())
    connected[n1].append(n2)
    connected[n2].append(n1)

for n in range(1, n+1):
    connected[n].sort()


def bfs(v):
    res = []
    visited = [0] * n
    dq = deque()
    dq.append(v)
    while dq:
        now = dq.popleft()
        res.append(now)
        visited[now - 1] = 1
        for node in connected[now]:
            if not visited[node - 1] and node not in dq:
                dq.append(node)
    return res


def dfs(v, visited=[]):
    visited.append(v)
    for node in connected[v]:
        if node not in visited:
            dfs(node, visited)
    return visited


print(*dfs(v))
print(*bfs(v))</code></pre>
<p><br><br></p>
<h3 id="📌후기">📌후기</h3>
<hr>
<p>Django 공부하느라 알고리즘 감이 다 죽었다.... 문제를 더 많이 풀어야 겠다ㅠㅠㅠㅠ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Python]합승 택시 요금]]></title>
            <link>https://velog.io/@mein-figur/ProgrammersPython%ED%95%A9%EC%8A%B9-%ED%83%9D%EC%8B%9C-%EC%9A%94%EA%B8%88</link>
            <guid>https://velog.io/@mein-figur/ProgrammersPython%ED%95%A9%EC%8A%B9-%ED%83%9D%EC%8B%9C-%EC%9A%94%EA%B8%88</guid>
            <pubDate>Thu, 09 Sep 2021 09:54:13 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/e51f8e50-c087-4fb7-a132-be7cabceb010/image.png" alt=""></p>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/72413">https://programmers.co.kr/learn/courses/30/lessons/72413</a></p>
<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>플로이드-워셜 알고리즘 활용</li>
</ul>
<pre><code class="language-python">from math import inf

#플로이드-워셜 알고리즘 활용

def solution(n, s, a, b, fares):
    answer = inf
    # 경로의 최소값을 저장하기 위한 리스트
    costs = [[inf]*n for _ in range(n)]

    # fares에서 불러온 경로값을 저장
    for c, d, f in fares :
        costs[c-1][d-1] = costs[d-1][c-1] = f

    for i in range(n):
        costs[i][i] = 0 # 본인에서 본인으로 가는 경로는 0

    for k in range(n):
        for i in range(n):
            for j in range(n):
                # 더 작은 값이 있는 경우, 이를 저장
                #costs[i][j] = min(costs[i][j], costs[i][k] + costs[k][j])
                if costs[i][j] &gt; costs[i][k] + costs[k][j] :
                    costs[i][j] = costs[i][k] + costs[k][j]

    # 다른 경로를 거쳐서 가는 방법 중 가장 작은 경우 확인
    for i in range(n):
        #answer = min(answer, costs[s-1][i] + costs[i][a-1] + costs[i][b-1])
        if answer &gt; costs[s-1][i] + costs[i][a-1] + costs[i][b-1]: 
            answer = costs[s-1][i] + costs[i][a-1] + costs[i][b-1]


    return answer</code></pre>
<p><br><br></p>
<h3 id="📌후기">📌후기</h3>
<hr>
<p>이전에 풀어볼 때는 다익스트라, 힙 구조를 활용하여 풀었었는데, 다른 사람들의 풀이 중 플로이드-워셜 알고리즘을 활용하여 해결한 경우가 있어 이를 적용하여 보았다. 다른 사람들의 풀이를 보면서 배워야 할 점이 상당히 많음을 다시 한 번 느낄 수 있었고, 코드를 구현하는 과정에서 <code>min</code>을 활용하는 것보다 if문을 활용하여 <code>min</code> 역할을 하게 하는 것이 시간적인 측면에서 더 효율적이라는 결과도 볼 수 있었다.</p>
<p><code>itertools</code>의 <code>product</code>를 활용하는 알고리즘도 있었는데, 이 방법도 한번 찾아봐야겠다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python]Kruskal Algorithm]]></title>
            <link>https://velog.io/@mein-figur/PythonKruskal-Algorithm</link>
            <guid>https://velog.io/@mein-figur/PythonKruskal-Algorithm</guid>
            <pubDate>Tue, 07 Sep 2021 13:40:39 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/970e0957-7078-4d53-aff0-14058101233f/image.png" alt=""></p>
<h1 id="kruskal-algorithm">Kruskal Algorithm</h1>
<ul>
<li>최소 비용 신장 부분 트리를 찾는 알고리즘</li>
<li>그래프의 모든 정점들을 최소의 비용으로 연결하기 위해 사용</li>
<li>Greedy 알고리즘 기반</li>
</ul>
<br>

<h3 id="✔시간-복잡도">✔시간 복잡도</h3>
<hr>
<ul>
<li>간선의 개수 <code>E</code>, 정점의 개수 <code>V</code>를 기준으로, <code>O(ElogV)</code>의 시간복잡도를 가지고 있다.</li>
</ul>
<br>

<h3 id="🔍신장-트리와-mst">🔍신장 트리와 MST</h3>
<hr>
<ul>
<li>신장 트리(Spanning Tree)</li>
</ul>
<blockquote>
<p>신장 트리(Spanning Tree)는 그래프 내의 모든 정점을 포함하고, 사이클이 없는 그래프를 말합니다.</p>
<p>n개의 정점(Vertex)가 있다면, 신장 트리의 간선(Edge) 수는 n-1이 됩니다.</p>
</blockquote>
<ul>
<li>MST(Minimum Spanning Tree)</li>
</ul>
<blockquote>
<p>최소 신장 트리(Minimum Spanning Tree)는 각 간선이 가지고 있는 가중치의 합이 최소가 되는 신장 트리를 말합니다.</p>
</blockquote>
<br>

<h3 id="📌진행-방식">📌진행 방식</h3>
<hr>
<ul>
<li>그래프의 간선들로 이루어진 리스트가 있다고 가정</li>
<li>그래프 간선들의 가중치를 <strong>오름차순</strong>으로 정렬, 가중치가 가장 적은 간선부터 탐색</li>
</ul>
<ol>
<li>가장 작은 가중치의 간선을 리스트에서 빼냄</li>
<li>해당 간선이 어떤 두 트리를 연결한다면, 합쳐서 하나의 트리로 바꿈(<strong>Union &amp; Find</strong>)</li>
<li>(2)의 조건을 만족하지 않는다면, 버림</li>
</ol>
<ul>
<li>위의 1~3의 과정을 진행하면서, n 개의 정점 기준 n-1 개의 간선이 남게 된다.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/44635266/66712118-cf661680-edd2-11e9-952c-b043e2bcdb8a.gif" alt="KruskalDemo"></p>
<p><br><br></p>
<h2 id="🖋-code">🖋 Code</h2>
<ul>
<li>코드는 <a href="https://programmers.co.kr/learn/courses/30/lessons/42861">프로그래머스: 섬 연결하기</a> 문제를 따왔다.<ul>
<li>MST를 찾고, 그때의 모든 가중치의 합을 구하는 문제</li>
</ul>
</li>
<li><code>cost</code>인 가중치를 작은 값 기준으로 정렬</li>
<li>부모 노드를 설정하는 <code>parent</code> 리스트<ul>
<li>초기 값은 본인으로 설정</li>
</ul>
</li>
<li><code>union</code> 함수와 <code>find</code> 함수를 통해 <strong>Union&amp;Find</strong> 구현<ul>
<li>Union: 서로 다른 두 트리를 합치는 함수(루트 노드를 하나로 설정)</li>
<li>Find: 해당 노드의 루트 노드를 찾는 함수</li>
</ul>
</li>
<li>간선에서의 두 노드의 루트 노드가 다른 경우, 하나의 트리로 합치고, 해당 가중치를 추가</li>
</ul>
<pre><code class="language-python">def solution(n, costs):
    answer = 0
    parent = [i for i in range(n)] # 부모 노드를 설정하기 위한 리스트
    costs.sort(key=lambda x:x[2]) # cost가 작은 값 기준으로 정렬

    def find(a): # 루트 노드를 찾는 함수
        if parent[a] == a: # 본인이 루트 노드인 경우
            return a
        parent[a] = find(parent[a])
        return parent[a] # 루트노드를 찾아 저장하고 리턴

    def union(a, b): # Tree 두개를 합치는 과정
        pa, pb = find(a), find(b) # 각 노드의 루트 노드
        if pa == pb : # 루트 노드가 같다는 것은 같은 트리
            return
        elif pa &lt; pb : # 노드값이 더 낮은 트리쪽으로 합침
            parent[pb] = pa
        else :
            parent[pa] = pb
        return   

    for n1, n2, c in costs:
        if find(n1) != find(n2): # 루트 노드가 다르면 연결 후 경로 값 추가
            union(n1, n2)
            answer += c

    return answer</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Python]행렬 테두리 회전하기]]></title>
            <link>https://velog.io/@mein-figur/ProgrammersPython%ED%96%89%EB%A0%AC-%ED%85%8C%EB%91%90%EB%A6%AC-%ED%9A%8C%EC%A0%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mein-figur/ProgrammersPython%ED%96%89%EB%A0%AC-%ED%85%8C%EB%91%90%EB%A6%AC-%ED%9A%8C%EC%A0%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 06 Sep 2021 10:40:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/d7da05ae-8f04-4003-bc73-d40153e3ba8c/image.png" alt=""></p>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/77485">https://programmers.co.kr/learn/courses/30/lessons/77485</a></p>
<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>값을 확인하기 위해, <code>box</code> 행렬 구현</li>
<li>문제에서 주어진 조건처럼 값을 회전시키고, 가장 작은 값 <code>answer</code>에 추가</li>
</ul>
<pre><code class="language-python">def solution(rows, columns, queries):
    answer = []
    box =[] # 행렬 값 설정
    for i in range(rows) :
        box.append([])
        for j in range(columns) :
            box[i].append((i)*columns+j+1)

    for y1, x1, y2, x2 in queries:
        # x, y : 현재 인덱스 위치
        # tmp에 값을 저장하며 위치를 변경
        # 변경하는 과정에서 더 작은 값이 나오면 num을 변경
        x, y = x1-1, y1-1
        num = tmp = box[y][x]
        for _ in range(x2-x1):
            nx = x+1
            box[y][nx], tmp = tmp, box[y][nx]
            x = nx
            num = min(num, tmp)
        for _ in range(y2-y1):
            ny = y+1
            box[ny][x], tmp = tmp, box[ny][x]
            y = ny
            num = min(num, tmp)
        for _ in range(x2-x1):
            nx = x-1
            box[y][nx], tmp = tmp, box[y][nx]
            x = nx
            num = min(num, tmp)
        for _ in range(y2-y1):
            ny = y-1
            box[ny][x], tmp = tmp, box[ny][x]
            y = ny
            num = min(num, tmp)
        answer.append(num)    # num 추가

    return answer</code></pre>
<p><br><br></p>
<h3 id="📌후기">📌후기</h3>
<hr>
<p>코드가 너무 투박한 것 같다....</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers][Python]섬 연결하기]]></title>
            <link>https://velog.io/@mein-figur/ProgrammersPython%EC%84%AC-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mein-figur/ProgrammersPython%EC%84%AC-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 05 Sep 2021 12:55:09 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/mein-figur/post/7f3225e9-1996-4186-937c-2e4512b2b668/image.png" alt=""></p>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/42861">https://programmers.co.kr/learn/courses/30/lessons/42861</a></p>
<h3 id="📌풀이">📌풀이</h3>
<hr>
<h4 id="내가-쓴-풀이성공">내가 쓴 풀이(성공)</h4>
<ul>
<li>kruskal 알고리즘 활용<ul>
<li><code>costs</code>를 cost가 작은 값 기준으로 정렬</li>
</ul>
</li>
<li>부모 노드를 저장하는 리스트 <code>parent</code> 활용</li>
<li><code>find</code>: 해당 노드의 루트 노드를 찾는 함수(재귀 활용)</li>
<li><code>union</code>: 두 노드의 루트 노드를 확인하고, 다른 경우 하나로 합치는 함수</li>
</ul>
<pre><code class="language-python">def solution(n, costs):
    answer = 0
    parent = [i for i in range(n)] # 부모 노드를 설정하기 위한 리스트
    costs.sort(key=lambda x:x[2]) # cost가 작은 값 기준으로 정렬

    def find(a): # 루트 노드를 찾는 함수
        if parent[a] == a: # 본인이 루트 노드인 경우
            return a
        parent[a] = find(parent[a])
        return parent[a] # 루트노드를 찾아 저장하고 리턴

    def union(a, b): # Tree 두개를 합치는 과정
        pa, pb = find(a), find(b) # 각 노드의 루트 노드
        if pa == pb : # 루트 노드가 같다는 것은 같은 트리
            return
        elif pa &lt; pb : # 노드값이 더 낮은 트리쪽으로 합침
            parent[pb] = pa
        else :
            parent[pa] = pb
        return   

    for n1, n2, c in costs:
        if find(n1) != find(n2): # 루트 노드가 다르면 연결 후 경로 값 추가
            union(n1, n2)
            answer += c

    return answer</code></pre>
<p><br><br></p>
<h3 id="📌후기">📌후기</h3>
<hr>
<p>kruskal 알고리즘이 무엇인지 배운 적이 있는데, 오랜 시간이 지나 사용하는 방법이나 활용하는 방법을 잊었었다. 이 문제를 통해 다시 한 번 이해할 수 있었고, kruskal 알고리즘과 관련된 내용을 정리해야겠다고 생각했다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Django]Project 설정하기(1)]]></title>
            <link>https://velog.io/@mein-figur/DjangoProject-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B01</link>
            <guid>https://velog.io/@mein-figur/DjangoProject-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B01</guid>
            <pubDate>Sat, 04 Sep 2021 06:34:31 GMT</pubDate>
            <description><![CDATA[<h1 id="📌django-project-setting1">📌Django Project Setting(1)</h1>
<hr>
<p><br><br></p>
<h2 id="사전-설정">사전 설정</h2>
<hr>
<h3 id="gitignore">.gitignore</h3>
<ul>
<li><code>.gitignore</code> (선택)</li>
<li>git에 업로드 하는 과정에서, git에 올리지 않을 내용들을 설정</li>
</ul>
<blockquote>
<p>가상환경을 위한 <code>venv</code>, 언어 환경을 위한 <code>Python</code>, <code>Django</code>, <code>VisualStudioCode</code>, <code>Windows</code> 추가</p>
</blockquote>
<p><a href="https://www.toptal.com/developers/gitignore">https://www.toptal.com/developers/gitignore</a> 접속 후 프로젝트에 맞는 설정 적용
<img src="https://images.velog.io/images/mein-figur/post/5c9959f7-2592-4a4c-8631-8b16eb37d056/image-20210902134435451.png" alt=""></p>
<p>생성된 결과를 <code>.gitignore</code>파일을 프로젝트 폴더에 생성 후 작성</p>
<br>

<h3 id="가상환경-venv">가상환경 venv</h3>
<ul>
<li><code>venv</code></li>
</ul>
<p>bash 창에 venv 생성 커맨드 작성</p>
<p>cmd 창 표시를 위해 <code>$</code> 를 해놨으므로, 실제로 bash에 작성을 할 때는 쓰지 말 것</p>
<pre><code>$ python -m venv venv</code></pre><ul>
<li>가상 환경 활성화</li>
</ul>
<pre><code>$ source venv/Scripts/activate</code></pre><blockquote>
<p>상단에 <code>(venv)</code> 표시를 통해 가상환경 활성화 여부 확인 가능</p>
</blockquote>
<p><img src="https://images.velog.io/images/mein-figur/post/66b4bfb9-8801-4331-9e9e-6fffb0244c97/image-20210902135732018.png" alt=""></p>
<br>

<ul>
<li>Django 모듈 설치 후 <code>pip list</code>를 통해 설치 여부 확인</li>
</ul>
<pre><code>$ pip install django</code></pre><ul>
<li>설치된 모듈 확인 방법</li>
</ul>
<pre><code>$ pip list</code></pre><p><img src="https://images.velog.io/images/mein-figur/post/0c0f5c25-4b6a-44b2-b3c0-8ef94c1aaa49/image-20210902140444507-16305590869091.png" alt=""></p>
<ul>
<li>설치된 모듈 리스트를 저장하는 방법(<code>requirements.txt</code> 에 저장)</li>
</ul>
<pre><code>$ pip freeze &gt; requirements.txt</code></pre><ul>
<li>주어진 모듈 리스트들을 통해 모듈을 설치하는 방법 (<code>requirements.txt</code>에 저장되어있다는 가정)</li>
</ul>
<pre><code>$ pip install -r requirements.txt</code></pre><p><br><br></p>
<h2 id="📌프로젝트-시작하기">📌프로젝트 시작하기</h2>
<hr>
<ul>
<li>Project<ul>
<li>Application의 집합</li>
<li>여러 앱이 포함될 수 있음</li>
<li>앱은 여러 프로젝트에 있을 수 있음</li>
</ul>
</li>
</ul>
<ul>
<li>프로젝트 이름은 <code>crud</code> 로 많이 설정</li>
</ul>
<pre><code>$ django-admin startproject crud .</code></pre><blockquote>
<p>프로젝트가 생성되면, 다음과 같이 <code>crud</code> 폴더와 <code>manage.py</code> 파일이 생성된 것을 확인할 수 있다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/mein-figur/post/7e44c1e3-6d7a-49f3-a699-fa1bfd3b44e6/image-20210902142721657.png" alt=""></p>
<ul>
<li><code>__init__.py</code></li>
</ul>
<p>Python에게 이 디렉토리를 하나의 Python 패키지로 다루도록 지시</p>
<ul>
<li><code>asgi.py</code></li>
</ul>
<p>Asynchronous Server Gateway Interface
django 어플리케이션이 비동기식 웹 서버와 연결 및 소통하는 것을 도와줌</p>
<ul>
<li><code>settings.py</code></li>
</ul>
<p>어플리케이션의 모든 설정(중요✔)</p>
<ul>
<li><code>urls.py</code></li>
</ul>
<p>사이트의 url과 적절한 views의 연결을 지정</p>
<ul>
<li><code>wsgi.py</code></li>
</ul>
<p>Web Server Gateway Interface
Django 어플리케이션이 웹서버와 연결 및 소통하는 것을 도와줌</p>
<ul>
<li><code>manage.py</code></li>
</ul>
<p>Django 프로젝트와 다양한 방법으로 상호작용하는 커맨드라인 유틸리티</p>
<p><br><br></p>
<h2 id="📌application-생성">📌Application 생성</h2>
<hr>
<ul>
<li>Application<ul>
<li>실제 요청을 처리하고 페이지를 보여주는 등의 역할 담당</li>
<li>하나의 프로젝트는 여러 앱을 가짐</li>
<li>일반적으로 앱은 하나의 역할 및 기능 단위로 작성</li>
</ul>
</li>
</ul>
<ul>
<li>Application 이름은 복수형 권장</li>
</ul>
<p>예시는 <code>articles</code>로 구현</p>
<pre><code>$ python manage.py startapp articles</code></pre><blockquote>
<p>Application이 생성되면, 앱 이름으로 된 폴더가 생성된 것을 확인할 수 있다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/mein-figur/post/74dbffd4-9c35-43bf-b351-f6e627d22e06/image-20210902144006084.png" alt=""></p>
<ul>
<li><code>admin.py</code></li>
</ul>
<p>관리자용 페이지를 설정</p>
<ul>
<li><code>apps.py</code></li>
</ul>
<p>앱의 정보가 작성된 곳</p>
<ul>
<li><code>models.py</code></li>
</ul>
<p>앱에서 활용하는 Model을 정의</p>
<ul>
<li><code>tests.py</code></li>
</ul>
<p>프로젝트의 테스트 코드를 작성</p>
<ul>
<li><code>views.py</code></li>
</ul>
<p>view 함수들 정의</p>
<br>

<h3 id="application-등록">Application 등록</h3>
<ul>
<li><strong>반드시 생성 후 등록</strong><ul>
<li>먼저 작성하고 생성하려면 앱이 생성되지 않음</li>
</ul>
</li>
<li><code>settings.py</code>의 <code>INSTALLED_APPS</code>에 추가<ul>
<li>Local apps, Third party apps, Django apps의 순서로 등록하는 것을 권장</li>
</ul>
</li>
</ul>
<p><img src="https://images.velog.io/images/mein-figur/post/dbafe94f-bdaf-4b39-9e5b-bb4215be76e2/image-20210902144734108.png" alt=""></p>
<br>

<h3 id="정상적인-생성-여부-확인">정상적인 생성 여부 확인</h3>
<ul>
<li>서버실행</li>
</ul>
<pre><code>$ python manage.py runserver</code></pre><ul>
<li><a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a> 를 통해 정상적으로 생성되었는지 확인 가능</li>
</ul>
<p><img src="https://images.velog.io/images/mein-figur/post/c395195d-a6cc-4484-b175-4d97b1458001/image-20210902153946255.png" alt=""></p>
<p><br><br></p>
<h2 id="📌basehtml-생성">📌base.html 생성</h2>
<hr>
<ul>
<li><p>html파일들에서 공통적인 형식이 나타남</p>
</li>
<li><p>반복적으로 작성하는 것을 줄이고자 <code>base.html</code>생성 </p>
</li>
<li><p><code>templates</code> 폴더를 생성 후, <code>base.html</code> 파일 생성</p>
</li>
</ul>
<p><img src="https://images.velog.io/images/mein-figur/post/c4f0b134-289f-4bd4-8b0f-9cdad465c79e/image-20210902145753834.png" alt=""></p>
<br>

<h4 id="basehtml">base.html</h4>
<ul>
<li>Bootstrap을 활용하기 위해, css, js 파일 적용</li>
<li><code>body</code>쪽 파트에, 내용을 넣고자 <code>block</code> 생성 </li>
</ul>
<pre><code class="language-django">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;title&gt;Document&lt;/title&gt;
  &lt;link href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css&quot; rel=&quot;stylesheet&quot; integrity=&quot;sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC&quot; crossorigin=&quot;anonymous&quot;&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div class=&quot;container&quot;&gt;
    {% block content %}
    {% endblock content %}
  &lt;/div&gt;

  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<br>

<h4 id="디렉토리-추가">디렉토리 추가</h4>
<ul>
<li><code>settings.py</code>의 <code>TEMPLATES</code>에 디렉토리 추가</li>
<li><code>DIRS</code>에 추가</li>
<li><code>BASE_DIR</code>은 가장 앞쪽 디렉토리를 말함<ul>
<li>현재 위치의 parent(crud)의 parent</li>
</ul>
</li>
</ul>
<p><img src="https://images.velog.io/images/mein-figur/post/7f165aa9-6048-46d8-b301-a87fcc97bff2/image-20210902151006636.png" alt=""></p>
<ul>
<li>추가한 결과</li>
</ul>
<p><img src="https://images.velog.io/images/mein-figur/post/4931045a-bcc5-40b8-8c42-3604cbf8040f/image-20210902150812126.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>