<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>water-beetle.log</title>
        <link>https://velog.io/</link>
        <description>Hello ~</description>
        <lastBuildDate>Mon, 10 Oct 2022 10:56:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>water-beetle.log</title>
            <url>https://images.velog.io/images/water-beetle/profile/9868aaf1-3ee4-468e-815f-5d8e71b84a0a/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. water-beetle.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/water-beetle" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Knowledge Distillation 간단 공부]]></title>
            <link>https://velog.io/@water-beetle/Knowledge-Distillation-%EA%B0%84%EB%8B%A8-%EA%B3%B5%EB%B6%80</link>
            <guid>https://velog.io/@water-beetle/Knowledge-Distillation-%EA%B0%84%EB%8B%A8-%EA%B3%B5%EB%B6%80</guid>
            <pubDate>Mon, 10 Oct 2022 10:56:40 GMT</pubDate>
            <description><![CDATA[<h1 id="knowledge-distillation">Knowledge Distillation</h1>
<p>출처 : (<a href="https://light-tree.tistory.com/196">https://light-tree.tistory.com/196</a>) 
pretrained된 Teacher network(큰 모델)의 학습된 정보를 추출해서 
student network(작은 모델) 학습시키는데 이용하는 것.
그냥 작은 모델로 학습하는 것 보다 더 높은 정확도를 얻을 수 있음</p>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/ed035d25-f7ef-4a17-9be6-1398df9ad52c/image.png" alt=""></p>
<p><strong>Soft label</strong> : [0, 0, 0, 1] 처럼 원핫 인코딩된 결과가 아니라 [0.1, 0.2, 0.1, 0.6] 처럼 확률로
나타낸 라벨값
<strong>soft predictions</strong> : softmax한 값에 T를 나눠주어 극단적인 값의 분포를 완화해줌
<strong>hard prediction</strong> : 그냥 softmax한 값</p>
<p>결과적으로 distillation loss + student loss 값을 이용해 student모델을 학습시킴으로써 
teacher model의 정보를 이용할 수 있다</p>
<h1 id="knowledge-distillation-코드-구현">Knowledge Distillation 코드 구현</h1>
<p>코드 출처 : (<a href="https://keras.io/examples/keras_recipes/better_knowledge_distillation/">https://keras.io/examples/keras_recipes/better_knowledge_distillation/</a>) 
<strong>사용할 데이터셋</strong> : oxford_flowers102
<strong>Teacher model</strong> : Pretrained된 BiT ResNet152x2 모델
(<a href="https://www.kaggle.com/datasets/spsayakpaul/bitresnet101x3flowers102">https://www.kaggle.com/datasets/spsayakpaul/bitresnet101x3flowers102</a>)
<strong>Student model</strong>: ResNet50V2
<img src="https://velog.velcdn.com/images/water-beetle/post/37ca77fe-7765-406b-9820-d9db40da4ff5/image.png" alt=""></p>
<p><strong>1. Distillation Loss 구현</strong>
<img src="https://velog.velcdn.com/images/water-beetle/post/a62c3b10-2c10-4324-a233-b87009345e5b/image.png" alt="">
<img src="https://velog.velcdn.com/images/water-beetle/post/6655665e-ba14-461c-ac98-2aacc57436a1/image.png" alt="">
Teacher model과 student model의 softmax값에 T를 나누어줘 값을 평탄화 해주었고,
    distillation_loss_fn(KL divergence)를 이용해 두 값의 분포 차이값을 계산함.
    그리고 나서 student_loss와 distillation_loss값을 alpha로 비율을 조정해서 값을 더해
    최종 loss값을 계산함.</p>
<p>** 2.    계산한 loss값을 이용해 가중치 업데이트**
<img src="https://velog.velcdn.com/images/water-beetle/post/bff3b140-dcfb-47b0-9445-b251cdb2f122/image.png" alt=""></p>
<p>** 3.    Knowledge distillation을 이용핸 student model의 결과 **</p>
<p>한시간(20 epoch)만큼 모델을 돌린 결과  <img src="https://velog.velcdn.com/images/water-beetle/post/4fd534c6-c421-45fc-98b9-64e77f180808/image.png" alt=""></p>
<p>매우 안 좋은 결과가 나왔다.</p>
<p><a href="https://git.io/JBO3Y%EC%97%90%EC%84%9C">https://git.io/JBO3Y에서</a> 해당 Distillation을 100000 epoch만큼 훈련시킨 모델을 얻을 수 있는데 여기에서는 95.54%가 나왔다.</p>
<p>결론 : Knowledge distillation을 이용해 모델 크기를 줄일수는 있지만 학습 시키는 시간은
더 크게 해야 좋은 결과를 내는 작은 모델을 얻을 수 있을 것 같다.</p>
<h1 id="sr에서의-knowledge-distillation">SR에서의 Knowledge Distillation</h1>
<p>Image Super-Resolution Using Knowledge Distillation(10.1007/978-3-030-20890-5_34) 참고</p>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/a990beb2-2d8d-4096-96e6-074e48a57598/image.png" alt=""></p>
<p>Teacher model에서 각각 T1, T2, T3의 statistical map을, Student model에서 s1, s2, s3의 
statistical map을 추출해서 loss(Teacher output, Student output) + loss(t1, s1) + loss(t2, s2) + loss(t3, s3)를 loss로 계산해서 knowledge distillation을 구현</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Transformer 간단 공부]]></title>
            <link>https://velog.io/@water-beetle/Transformer-%EA%B0%84%EB%8B%A8-%EA%B3%B5%EB%B6%80</link>
            <guid>https://velog.io/@water-beetle/Transformer-%EA%B0%84%EB%8B%A8-%EA%B3%B5%EB%B6%80</guid>
            <pubDate>Mon, 10 Oct 2022 10:49:25 GMT</pubDate>
            <description><![CDATA[<h1 id="transformer-구현-및-코드-분석">Transformer 구현 및 코드 분석</h1>
<p>Vision Transformer를 이해하기 위해 Transformer를 직접 코드로 구현해보면서
모델을 이해해 봄(출처 : 딥러닝을 이용한 자연어처리 입문, <a href="https://wikidocs.net/31379">https://wikidocs.net/31379</a>)</p>
<h2 id="포지셔널-인코딩">포지셔널 인코딩</h2>
<p>입력 데이터의 위치정보를 입력데이터에 추가함
<img src="https://velog.velcdn.com/images/water-beetle/post/feee1646-e733-4b1b-9fa4-3e97716e5054/image.png" alt="">
위 수식을 인덱스에 따른 위치정보로 표현해서 임베딩된 데이터에 추가해줌
<img src="https://velog.velcdn.com/images/water-beetle/post/dca8a8f6-b909-4e83-90cb-c0f83c8e7d68/image.png" alt=""></p>
<h2 id="scaled-dot-product-attention">Scaled dot-product Attention</h2>
<p>입력데이터에서 구한 Q, K, V를 입력하면 값(셀프 어텐션 값)을 계산해줌
<img src="https://velog.velcdn.com/images/water-beetle/post/7c1608e1-2d67-4c04-bdce-693f77cb47fb/image.png" alt="">
<img src="https://velog.velcdn.com/images/water-beetle/post/43a72ef8-4e26-48b7-98cd-8ccfe9a33212/image.png" alt=""></p>
<h2 id="multi-head-attention">Multi-head Attention</h2>
<p>위에서 한 코드는 한번의 attention인데 여러 번의 attention을 병렬로 사용,
병렬로 attention한 결과들을 합쳐 새로운 가중치 행렬 W를 곱해줌
먼저 input에 Q, K, V를 각각 만드는 dense layer를 곱함 -&gt; Q, K, V 생성됨
Q, K, V를 각각 num_heads만큼 나누어서 (input_dim / num_heads)의 차원을 가지는 
num_heads만큼의 attention을 만듬.
각각의 attention을 Scaled dot-product후 합친 후 W 곱해줌</p>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/9a221e63-5562-48cc-9a17-a9f8994a8c15/image.png" alt=""></p>
<h2 id="인코더-구현">인코더 구현</h2>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/9b29ff18-3c29-41bc-b1d9-2e0eee967ba9/image.png" alt="">
위 이미지처럼 인코더 블록 하나를 구현하고 num_layers만큼 쌓아주엇음
<img src="https://velog.velcdn.com/images/water-beetle/post/2a0cb99b-3236-41d0-b66a-6d8f128fbb40/image.png" alt=""></p>
<h1 id="vision-transformer-구현-및-코드-분석">Vision Transformer 구현 및 코드 분석</h1>
<p>(출처 : <a href="https://keras.io/examples/vision/image_classification_with_vision_transformer/">https://keras.io/examples/vision/image_classification_with_vision_transformer/</a>)
<img src="https://velog.velcdn.com/images/water-beetle/post/6510c960-7b1f-443f-b8ff-fbb44ea8eb49/image.png" alt="">
Transformer 모델을 이미지에 적용시킨 모델
이미지를 여러 개의 patch로 나누고, 시퀸스 데이터처럼 만듬
그 후 Position Embedding을 더한 다음 Transformer Encoder를 통과시킨다</p>
<h2 id="이미지를-여러-patch-나누기--position-embedding">이미지를 여러 Patch 나누기 + Position Embedding</h2>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/0e7c193b-75f4-4a49-a3b8-b50d4ae01d9b/image.png" alt="">
<img src="https://velog.velcdn.com/images/water-beetle/post/7a33a9a5-d32c-4304-bf20-53b2f79615c8/image.png" alt="">
tf.image.extract_patches 함수를 사용해 이미지를 여러 Patch로 나눔,
나눈 patch들을 projection + position embedding으로 값을 바꿔줌</p>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/8e724242-bbb5-471e-9fd6-9a68987f03ef/image.png" alt="">
transformer에서는 position embedding을 sin, cos함수로 표현했는데,
ViT에서는 embedding함수로 위치 정보 파라미터를 업데이트 할 수 있도록  구현한 것 같음.</p>
<h2 id="vit-모델-구현">ViT 모델 구현</h2>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/0a886ea0-77be-4892-a8c0-a4b3807327b3/image.png" alt="">
Transformer에서는 Multi Head Attention을 직접 구현해 봤는데
ViT에서는 tensorflow에서 구현된 함수를 사용하였다.</p>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/08227c57-6830-4fdb-a981-c1997171ea51/image.png" alt=""></p>
<h2 id="최종-구현">최종 구현</h2>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/6d81453c-b0b2-4458-a3fb-9e8941cb3840/image.png" alt="">
1, 2에서 만든 코드를 합치고, 마지막에 일반 분류문제처럼 Layer를 추가 해 주어서
최종 ViT 모델을 구현하였다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 19번 : 역순 연결 리스트 2]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-19%EB%B2%88-%EC%97%AD%EC%88%9C-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8-2</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-19%EB%B2%88-%EC%97%AD%EC%88%9C-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8-2</guid>
            <pubDate>Fri, 30 Sep 2022 08:29:29 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/reverse-linked-list-ii/">https://leetcode.com/problems/reverse-linked-list-ii/</a>
인덱스 m에서 n까지를 역순으로 만들어라. 인덱스 m은 1부터 시작한다</p>
<pre><code class="language-python">class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

Input: head = [1,2,3,4,5], left = 2, right = 4
Output: [1,4,3,2,5]

Input: head = [5], left = 1, right = 1
Output: [5]</code></pre>
<h1 id="풀이">풀이</h1>
<h2 id="내풀이">내풀이</h2>
<p>한번에 맞게 풀었지만 깔끔하지 못하고 그냥 주먹구구식으로 풀어서 너무 아쉽다...
그냥 count 변수를 추가해서 n, m일때 연결리스트를 뒤집어 주었는데
뒤집어 줄때 n==m인경우, n=1경우를 하드코딩해서 깔끔하지 않은것 같다.</p>
<pre><code class="language-python">class Solution:
    def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -&gt; Optional[ListNode]:
        prev_head, trav = None, head
        count = 1

        while count != left:
            count += 1
            prev_head, trav = trav, trav.next

        reverse_end = prev = trav

        # reverse
        if trav.next:
            prev, trav = trav, trav.next
            count += 1

        while count != right+1:
            count += 1
            next, trav.next = trav.next, prev
            prev, trav = trav, next

        if prev_head:
            prev_head.next = prev
        reverse_end.next = trav

        if left == 1:
            return prev
        else:
            return head</code></pre>
<h2 id="책-풀이">책 풀이</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 18번 : 홀짝 연결 리스트]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-18%EB%B2%88-%ED%99%80%EC%A7%9D-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-18%EB%B2%88-%ED%99%80%EC%A7%9D-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 29 Sep 2022 12:37:20 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/odd-even-linked-list/">https://leetcode.com/problems/odd-even-linked-list/</a></p>
<pre><code class="language-python">class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next</code></pre>
<p>The first node is considered odd, and the second node is even, and so on.
연결 리스트를 홀수 노드 다음에 짝수 노드가 오도록 재구성하라.
공간 복잡도 O(1), 시간복잡도 O(n)에 풀이하라</p>
<h1 id="풀이">풀이</h1>
<h2 id="내-풀이">내 풀이</h2>
<p>책 풀이랑 거의 똑같이 푼 것 같다.
공간복잡도가 O(n)이라 새로운 연결리스트로 홀수, 짝수 나눈게 아니라
원래 있던 연결리스트에 값을 계속 업데이트 해주었다.
-&gt;<code>98 ms</code></p>
<pre><code class="language-python">class Solution:
    def oddEvenList(self, head: Optional[ListNode]) -&gt; Optional[ListNode]:

        if not head:
            return head

        odd = odd_head = head
        even = even_head = head.next

        while even and even.next:
            odd.next, even.next = odd.next.next, even.next.next
            odd, even = odd.next, even.next

        odd.next = even_head

        return odd_head</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 17번 : 페어의 노드 스왑]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-17%EB%B2%88-%ED%8E%98%EC%96%B4%EC%9D%98-%EB%85%B8%EB%93%9C-%EC%8A%A4%EC%99%91</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-17%EB%B2%88-%ED%8E%98%EC%96%B4%EC%9D%98-%EB%85%B8%EB%93%9C-%EC%8A%A4%EC%99%91</guid>
            <pubDate>Tue, 27 Sep 2022 03:52:14 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/swap-nodes-in-pairs/">https://leetcode.com/problems/swap-nodes-in-pairs/</a></p>
<pre><code class="language-python">class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next</code></pre>
<p>연결 리스트를 입력받아 페어 단위로 스왑하라</p>
<pre><code class="language-python">Input: head = [1,2,3,4]
Output: [2,1,4,3]

Input: head = [1]
Output: [1]</code></pre>
<h1 id="풀이">풀이</h1>
<p>재귀를 이용해서 리스트 노드 2개씩 보면서 두 개를 바꾸어주었다.</p>
<pre><code class="language-python">class Solution:

    def swap(self, head: Optional[ListNode]) -&gt; Optional[ListNode]:
        if not head or not head.next:
            return head

        first, second = head, head.next
        first.next, second.next = second.next, first

        first.next = self.swap(first.next)

        return second



    def swapPairs(self, head: Optional[ListNode]) -&gt; Optional[ListNode]:
        return self.swap(head)</code></pre>
<p>이번에는 책 풀이랑 비슷하게 풀어 깔끔하게 잘 푼것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TecoGAN 모델 사용해보기]]></title>
            <link>https://velog.io/@water-beetle/TecoGAN-%EB%AA%A8%EB%8D%B8-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@water-beetle/TecoGAN-%EB%AA%A8%EB%8D%B8-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Mon, 26 Sep 2022 08:52:06 GMT</pubDate>
            <description><![CDATA[<h1 id="github에-구현된-tecogan-다운로드">Github에 구현된 TecoGAN 다운로드</h1>
<p><strong>clone 후 코드를 실행해보면 정상 실행이 되지 않아 오류 발생 및 해결방법 정리</strong></p>
<p><strong>오류 1</strong> - tecogan의 구현코드는 tensorflow 1.x버전이라 2.x에서 실행 불가
<strong>해결 1</strong> - 해당 깃허브의 pull requests를 찾아보던 중 누가 2.x에 호환되도록 
request한 코드가 있었음(<a href="https://github.com/RAFALAMAO/TecoGAN">https://github.com/RAFALAMAO/TecoGAN</a>), 해당 코드로 교체함</p>
<p><strong>오류 2</strong> - python3 runGan.py 1 실행시 라이브러리 설치했음에도 불구하고 cannot import 오류발생
<strong>해결 2</strong> - python3 대신 python으로 실행, runGan.py에서 python3으로 적힌 실행코드들을
모두 python으로 바꾸어줌</p>
<p><strong>오류 3</strong> - python runGan.py 2 실행 중 cannot import name &#39;compare_ssim&#39; from &#39;skimage.measure&#39;
<strong>해결 3</strong> - TecoGAN/LPIPSmodels/util.py와 TecoGAN/metrics.py에서
from skimage.measure import compare_ssim의 코드를
from skimage.metrics import structural_similarity로 바꿈</p>
<h1 id="예제-lr-이미지들을-pretrained된-모델에-돌려보기">예제 LR 이미지들을 Pretrained된 모델에 돌려보기</h1>
<h2 id="예제-이미지-다운로드">예제 이미지 다운로드</h2>
<p><strong>python runGan.py 0</strong> 실행 -&gt; wget 오류 발생(코드 실행환경은 리눅스, 현재환경은 윈도우)
runGan.py코드를 보고 pretrained model과 예제 이미지를 직접 다운로드</p>
<ol>
<li>TecoGAN/model에 파일 넣기 <a href="https://ge.in.tum.de/download/data/TecoGAN/model.zip">https://ge.in.tum.de/download/data/TecoGAN/model.zip</a></li>
<li>TecoGAN/LR에 파일 넣기 <a href="https://ge.in.tum.de/download/data/TecoGAN/vid3_LR.zip">https://ge.in.tum.de/download/data/TecoGAN/vid3_LR.zip</a><pre><code>                    https://ge.in.tum.de/download/data/TecoGAN/tos_LR.zip</code></pre></li>
<li>TecoGAN/HR에 파일 넣기 <a href="https://ge.in.tum.de/download/data/TecoGAN/vid4_HR.zip">https://ge.in.tum.de/download/data/TecoGAN/vid4_HR.zip</a><pre><code>                    https://ge.in.tum.de/download/data/TecoGAN/tos_HR.zip</code></pre></li>
</ol>
<h2 id="lr이미지들을-pretrained-모델에-입력으로-넣어-hr영상으로-출력">LR이미지들을 pretrained 모델에 입력으로 넣어 HR영상으로 출력</h2>
<p><strong>python runGan.py 1</strong> 실행
현재는 TecoGAN/LR/calendar 영상이 입력으로 들어감
runGan.py 파일에서 testpre에 학습시키고 싶은 LR데이터셋의 경로를 넣을 수 있음
<img src="https://velog.velcdn.com/images/water-beetle/post/0a63b4a3-ea12-4c10-acb0-c5dd7b448206/image.png" alt="">
<strong>결과(Calendar dataset)</strong></p>
<center>원본 이미지
  <img src="https://velog.velcdn.com/images/water-beetle/post/aed53286-a80f-47bd-afba-8f0c9565f648/image.png" width="250px"> 
SR된 이미지
    <img src="https://velog.velcdn.com/images/water-beetle/post/7722f2a7-7e09-4662-b7fd-681ffb4ff66f/image.png" width="250px">
LR 이미지
    <img src="https://velog.velcdn.com/images/water-beetle/post/64452e9b-b0c8-44b4-9db9-d86fde71638e/image.png" width="250px">
</center>




<h2 id="sr된-이미지와-원본-이미지를-비교해-평가지표-출력">SR된 이미지와 원본 이미지를 비교해 평가지표 출력</h2>
<p><strong>python runGan.py 2</strong> 실행
위와 마찬가지로 testpre에서 평가할 이미지 변경가능
평가지표 결과는 TecoGAN/metric_log에 저장됨</p>
<p><strong>결과</strong>
<img src="https://velog.velcdn.com/images/water-beetle/post/5e6edfa9-025f-462b-9ac8-33f60e52f10c/image.png" alt=""></p>
<h1 id="모델-학습-시켜보기">모델 학습 시켜보기</h1>
<h2 id="학습용-데이터셋-다운로드">학습용 데이터셋 다운로드</h2>
<p><strong>python dataPrepare.py –help</strong>로 살펴보기 -&gt; <strong>cannot import name ‘clock’ from ‘time’</strong> 에러
(dataPrepare.py 코드를 보니 from time import clock 코드 안 쓰여서 주석처리 함)
<strong>python dataPrepare.py –start_id 2000 –duration 120 –disk_path datasets</strong>로 데이터셋 다운
전체 데이터를 다운받는데 시간이 너무 오래 걸려서 50/290개만 받음(1시간 소요)</p>
<h2 id="데이터셋-학습">데이터셋 학습</h2>
<p><strong>python runGan.py 2</strong> 실행 (Train the TecoGAN Model)
wget 오류 발생(윈도우 환경) -&gt; 직접 파일 다운로드
사전 훈련된 VGG19, FRVSR model 직접 다운로드 후 TecoGAN/model에 압축 풀기
<a href="http://download.tensorflow.org/models/vgg_19_2016_08_28.tar.gz">http://download.tensorflow.org/models/vgg_19_2016_08_28.tar.gz</a>
<a href="http://ge.in.tum.de/download/2019-TecoGAN/FRVSR_Ours.zip">http://ge.in.tum.de/download/2019-TecoGAN/FRVSR_Ours.zip</a></p>
<p>runGan.py에서 TrainingDataPath 경로를 -disk_path에서 설정한 경로(datasets)로 수정
<img src="https://velog.velcdn.com/images/water-beetle/post/b5e49abf-f86a-4be9-a40e-a100a5c5e70f/image.png" alt="">
<img src="https://velog.velcdn.com/images/water-beetle/post/e1c132b2-e7dc-4d7d-a953-b2febd75b240/image.png" alt=""></p>
<p>데이터도 50/290개만 받았으므로 다음과 같이 str_dir, end_dir, end_dir_val값 수정
(주석 값이 원래 값)
<img src="https://velog.velcdn.com/images/water-beetle/post/25fdac7f-60c6-4952-b7f0-675e990365ea/image.png" alt=""></p>
<p><strong>오류 1</strong> - module &#39;tensorflow.compat.v1&#39; has no attribute &#39;contrib&#39;
<strong>해결 1</strong> – TecoGAN/lib/Teco.py의 tf.contrib.image.dense_image_warp를
모두 tfa.image.dense_image_warp로 바꾸어줌</p>
<p><strong>오류 2</strong> - module &#39;tensorflow.python.ops.summary_op_util&#39; has no attribute &#39;skip_summary&#39;
<strong>해결 2</strong> – TecoGAN/lib/ops.py에서 from tensorflow.python.ops import summary_op_util를
from tensorflow.python.ops import summary_op_util 
from tensorflow.python.distribute.summary_op_util import skip_summary로 바꾸어주고,
아래에 있는 코드 중 summary_op_util.skip_summary를 skip_summary로 바꾸어줌</p>
<p><strong>오류 3</strong> – 노트북 GPU(MX250)으로 모델 학습 시 batch_size를 1로 해도 OOM에러 발생
<strong>해결 3</strong> – runGan.py에서 batch_size가 4(default)로 되어있는데 2로 수정 및
본체 GPU(RTX 3060ti 사용)
<img src="https://velog.velcdn.com/images/water-beetle/post/faee629b-97ba-4422-a9b6-edc5de101fa3/image.png" alt="">
<img src="https://velog.velcdn.com/images/water-beetle/post/85889fb5-70ae-4189-a03d-f2047721a997/image.png" alt=""></p>
<p>학습 종료조건이 되지 않았지만 너무 오래 걸릴 것 같아 8시간만 학습</p>
<h2 id="학습결과-확인">학습결과 확인</h2>
<p><strong>Tensorboard –logdir ‘log 경로’</strong> 실행</p>
<p><img src="https://velog.velcdn.com/images/water-beetle/post/3e75fe7a-bc67-4034-bc7b-d71e05733645/image.png" alt="">
<img src="https://velog.velcdn.com/images/water-beetle/post/341d390f-2aab-499d-b96a-eb386d9c1079/image.png" alt="">
학습을 오래 시키지 않았음에도 불구하고 SR이 잘 된 모습을 확인할 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 16번 : 두 수의 덧셈]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-16%EB%B2%88-%EB%91%90-%EC%88%98%EC%9D%98-%EB%8D%A7%EC%85%88</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-16%EB%B2%88-%EB%91%90-%EC%88%98%EC%9D%98-%EB%8D%A7%EC%85%88</guid>
            <pubDate>Mon, 26 Sep 2022 03:43:25 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/add-two-numbers/">https://leetcode.com/problems/add-two-numbers/</a></p>
<pre><code class="language-python">class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next</code></pre>
<p>역순으로 저장된 연결 리스트의 숫자를 더하라</p>
<pre><code class="language-python">Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.

Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]</code></pre>
<h1 id="풀이">풀이</h1>
<h2 id="내-풀이">내 풀이</h2>
<p>두 연결 리스트의 길이를 맞추기 위해서 값이 0인 연결리스트를 추가 해줘서 길이를 맞추어
두 수를 덧셈 해줌 -&gt; <code>150 ms</code></p>
<pre><code class="language-python">class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -&gt; Optional[ListNode]:

        l1_trav, l2_trav = l1, l2
        l1_prev = None
        next_val = 0
        while l1_trav.next or l2_trav.next:

            if not l1_trav.next:
                l1_trav.next = ListNode(0)
            if not l2_trav.next:
                l2_trav.next = ListNode(0)

            l1_trav.val, next_val = (l1_trav.val + l2_trav.val+ next_val) % 10 , (l1_trav.val + l2_trav.val + next_val) // 10


            l1_trav, l2_trav = l1_trav.next, l2_trav.next

        l1_trav.val, next_val = (l1_trav.val + l2_trav.val+ next_val) % 10 , (l1_trav.val + l2_trav.val + next_val) // 10

        if next_val:
            l1_trav.next = ListNode(next_val)

        return l1</code></pre>
<h2 id="책-풀이">책 풀이</h2>
<h3 id="자료형-변환">자료형 변환</h3>
<p>연결 리스트를 문자열로 이어 붙인다음 숫자로 변환하고, 이를 모두 계산한 후 다시 연결리스트로 바꾼다.
-&gt; 비효율적 풀이 : <code>160 ms</code> </p>
<pre><code class="language-python">class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -&gt; Optional[ListNode]:
        # 연결 리스트 뒤집기
        a = self.toList(self.reverseList(l1))
        b = self.toList(self.reverseList(l2))

        resultStr = int(&#39;&#39;.join(str(e) for e in a)) + int(&#39;&#39;.join(str(e) for e in b))

        return self.toReversedLinkedList(str(resultStr))


    def reverseList(self, head: ListNode) -&gt; ListNode:
        node, prev = head, None

        while node:
            next, node.next = node.next, prev
            prev, node = node, next

        return prev


    def toList(self, node: ListNode) -&gt; List:
        list: List = []
        while node:
            list.append(node.val)
            node = node.next

        return list

    def toReversedLinkedList(self, result: str) -&gt; ListNode:
        prev: ListNode = None
        for r in result:
            node = ListNode(r)
            node.next = prev
            prev = node

        return node</code></pre>
<h3 id="전가산기-구현">전가산기 구현</h3>
<p>내가 한 방법이랑 비슷함
더 나은 부분은</p>
<ol>
<li>몫과 나머지 계산을 divmod()로 계산</li>
<li>l1에 값을 더한게 아니라 새로운 리스트 노드를 만들어서 값을 반환</li>
</ol>
<p>-&gt;<code>129 ms</code></p>
<pre><code class="language-python">    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -&gt; Optional[ListNode]:
        root = head = ListNode(0)

        carry = 0

        while l1 or l2 or carry:
            sum = 0

            if l1:
                sum += l1.val
                l1 = l1.next
            if l2:
                sum += l2.val
                l2 = l2.next


            # 몫과 나머지 계산
            carry, val = divmod(sum+carry, 10)
            head.next = ListNode(val)
            head = head.next

        return root.next</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 15번 : 역순 연결 리스트]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-15%EB%B2%88-%EC%97%AD%EC%88%9C-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-15%EB%B2%88-%EC%97%AD%EC%88%9C-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 22 Sep 2022 11:53:33 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/reverse-linked-list/">https://leetcode.com/problems/reverse-linked-list/</a></p>
<pre><code class="language-python">class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next</code></pre>
<p>연결 리스트를 뒤집어라</p>
<pre><code class="language-python">Input: head = [1,2,3,4,5]
Output: [5,4,3,2,1]</code></pre>
<h1 id="풀이">풀이</h1>
<h2 id="내-풀이">내 풀이</h2>
<p>이전 노드, 현재 노드, 다음 노드 변수를 선언해서 연결 리스트를 뒤집었다.
-&gt; <code>81 ms</code>...</p>
<pre><code class="language-python">class Solution:
    def reverseList(self, head: Optional[ListNode]) -&gt; Optional[ListNode]:

        before_head = None
        trav_head = head
        after_head = head.next

        while not trav_head:
            trav_head.next = before_head
            before_head = trav_head
            trav_head, after_head = after_head, after_head.next


        return before_head</code></pre>
<h2 id="책-풀이">책 풀이</h2>
<h3 id="재귀-구조로-뒤집기">재귀 구조로 뒤집기</h3>
<p>-&gt;<code>81 ms</code></p>
<pre><code class="language-python">class Solution:
    def reverseList(self, head: Optional[ListNode]) -&gt; Optional[ListNode]:
        def reverse(node: ListNode, prev: ListNode = None):
            if not node:
                return prev
            next, node.next = node.next, prev
            return reverse(next, node)

        return reverse(head)</code></pre>
<h3 id="반복-구조로-뒤집기">반복 구조로 뒤집기</h3>
<p>-&gt;<code>80 ms</code></p>
<pre><code class="language-python">class Solution:
    def reverseList(self, head: Optional[ListNode]) -&gt; Optional[ListNode]:
        node, prev = head, None

        while node:
            next, node.next = node.next, prev
            prev, node = node, next

        return prev</code></pre>
<p>내가 햇던 코드랑 비슷한데 훨씬 간결하게 잘 표현했다...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 14번 : 두 정렬 리스트의 병합]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-14%EB%B2%88-%EB%91%90-%EC%A0%95%EB%A0%AC-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EC%9D%98-%EB%B3%91%ED%95%A9</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-14%EB%B2%88-%EB%91%90-%EC%A0%95%EB%A0%AC-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EC%9D%98-%EB%B3%91%ED%95%A9</guid>
            <pubDate>Tue, 20 Sep 2022 04:04:50 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/merge-two-sorted-lists/">https://leetcode.com/problems/merge-two-sorted-lists/</a></p>
<pre><code class="language-python"># Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next</code></pre>
<p>정렬되어 있는 두 연결 리스트를 합쳐라</p>
<pre><code class="language-python">Input: list1 = [1,2,4], list2 = [1,3,4]
Output: [1,1,2,3,4,4]</code></pre>
<pre><code class="language-python">Input: list1 = [], list2 = []
Output: []</code></pre>
<h1 id="풀이">풀이</h1>
<h2 id="내-풀이">내 풀이</h2>
<p>연결리스트를 돌아다니는 두 개의 trav 변수를 이용해 값을 비교하며 새로운 연결 리스트를 만듬
-&gt; <code>78 ms</code></p>
<pre><code class="language-python">class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -&gt; Optional[ListNode]:

        head, trav = None, None
        list1_trav, list2_trav = list1, list2

        if not list1:
            return list2

        if not list2:
            return list1

        if list1_trav.val &gt; list2_trav.val:
            head, trav = list2, list2
            list2_trav= list2_trav.next
        else:
            head, trav = list1, list1
            list1_trav = list1_trav.next

        while list1_trav and list2_trav:
            if list1_trav.val &gt; list2_trav.val:
                trav.next, list2_trav = list2_trav, list2_trav.next
            else:
                trav.next, list1_trav = list1_trav, list1_trav.next  
            trav = trav.next

        while list1_trav:
            trav.next, list1_trav = list1_trav, list1_trav.next
            trav = trav.next
        while list2_trav:
            trav.next, list2_trav = list2_trav, list2_trav.next
            trav = trav.next

        return head</code></pre>
<h2 id="책-풀이">책 풀이</h2>
<p>재귀 함수로 구현
-&gt; <code>38 ms</code></p>
<pre><code class="language-python">class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -&gt; Optional[ListNode]:
        if (not list1) or (list2 and list1.val &gt; list2.val):
            list1, list2 = list2, list1

        if list1:
            list1.next = self.mergeTwoLists(list1.next, list2)

        return list1</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 13번 : 팰린드롬 연결 리스트]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-13%EB%B2%88-%ED%8C%B0%EB%A6%B0%EB%93%9C%EB%A1%AC-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-13%EB%B2%88-%ED%8C%B0%EB%A6%B0%EB%93%9C%EB%A1%AC-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Mon, 19 Sep 2022 12:49:05 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/palindrome-linked-list/">https://leetcode.com/problems/palindrome-linked-list/</a></p>
<pre><code class="language-python"># Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next</code></pre>
<p>연결 리스트가 팰린드롬 구조인지 판별하라</p>
<pre><code>Input: head = [1,2,2,1]
Output: true</code></pre><pre><code>Input: head = [1,2]
Output: false</code></pre><h1 id="풀이">풀이</h1>
<h2 id="내-풀이">내 풀이</h2>
<p>연결 리스트들을 배열에 옮겨닮은 후, 원래 배열과 뒤집은 배열이 같은지 반환
-&gt; <code>O(n)</code>, <code>1868 ms</code></p>
<pre><code class="language-python">class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -&gt; bool:

        a = []

        while(1):
            a.append(head.val)

            if head.next == None:
                break

            head = head.next

        return a[::] == a[::-1]</code></pre>
<h2 id="책-풀이">책 풀이</h2>
<h3 id="리스트-변환">리스트 변환</h3>
<p>-&gt; <code>O(n)</code>, <code>2705 ms</code>
pop(0) 하는 부분에서 값을 꺼내온 다음에 모든 값을 앞으로 시프팅 하기 때문에
시간이 많이 걸렸다 -&gt; Deque를 사용 : 이중 연결 리스트 구조로 
양쪽 방향 모두 추출하는데 O(1) 시간만큼 걸림</p>
<pre><code class="language-python">class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -&gt; bool:
        q: List = []

        if not head:
            return True

        node = head

        while node is not None:
            q.append(node.val)
            node = node.next

        while len(q) &gt; 1:
            if q.pop(0) != q.pop():
                return False

        return True</code></pre>
<h3 id="데크를-이용한-최적화">데크를 이용한 최적화</h3>
<p>-&gt; <code>O(n)</code>, <code>2705 ms -&gt;     1643 ms로 감소</code>
Deque를 사용 : 이중 연결 리스트 구조로 
양쪽 방향 모두 추출하는데 O(1) 시간만큼 걸림</p>
<pre><code class="language-python">class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -&gt; bool:
        q: Deque = collections.deque()

        if not head:
            return True

        node = head
        while node is not None:
            q.append(node.val)
            node = node.next

        while len(q) &gt; 1:
            if q.popleft() != q.pop():
                return False

        return True</code></pre>
<h3 id="런너를-이용한-풀이">런너를 이용한 풀이</h3>
<p>-&gt; <code>O(n)</code>, <code>1643 ms -&gt;     1541 ms로 감소</code>
링크드 리스트에서 2개의 러너를 사용
하나는 2칸씩 이동하는 러너, 하나는 하나씩 이동하는 러너
2칸씩 이동하는 러너가 끝에 도착하면 하나씩 이동하는 러너는 링크드 리스트에서 중간 위치가됨.
이 점을 이용해 중간 위치를 알 수 있으므로 중간 이전과 중간 이후의 값 비교 가능</p>
<pre><code class="language-python">class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -&gt; bool:
        rev = None
        slow = fast = head

        #런너를 이용해 역순 연결 리스트 구성
        while fast and fast.next:
            fast = fast.next.next
            rev, rev.next, slow = slow, rev, slow.next

        if fast:
            slow = slow.next

        # 팰린드롬 여부 확인
        while rev and rev.val == slow.val:
            slow, rev = slow.next, rev.next

        return not rev</code></pre>
<h4 id="파이썬-다중-할당">파이썬 다중 할당</h4>
<p><strong>rev = 1, slow = 2-&gt;3이라 가정</strong></p>
<pre><code class="language-python">rev, rev.next, slow = slow, rev, slow.next</code></pre>
<p>rev=2-&gt;3, rev.next=1, slow=3이 되고, rev.next=1이므로
최종적으로 rev=2-&gt;1, slow=3이 된다.
다중 할당을 하게 되면 이 같은 작업이 동시에 일어나기 떄문에, 이 모든 작업은 중간과정없이
한 번의 트랜잭션으로 끝나게 된다.
<strong>V.S</strong></p>
<pre><code class="language-python">rev, rev.next = slow, rev
slow = slow.next</code></pre>
<p>rev=2-&gt;3, rev.next=1, 따라서  rev=2-&gt;1이 되는데 rev=slow,
동일한 참조가 되었으며 rev=2-&gt;1이 되었기 떄문에 slow=2-&gt;1로 바뀐다.
그래소 slow=1이 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[파이썬 알고리즘 인터뷰] 12번 : 주식을 사고팔기 가장 좋은 시점]]></title>
            <link>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-12%EB%B2%88-%EC%A3%BC%EC%8B%9D%EC%9D%84-%EC%82%AC%EA%B3%A0%ED%8C%94%EA%B8%B0-%EA%B0%80%EC%9E%A5-%EC%A2%8B%EC%9D%80-%EC%8B%9C%EC%A0%90</link>
            <guid>https://velog.io/@water-beetle/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9D%B8%ED%84%B0%EB%B7%B0-12%EB%B2%88-%EC%A3%BC%EC%8B%9D%EC%9D%84-%EC%82%AC%EA%B3%A0%ED%8C%94%EA%B8%B0-%EA%B0%80%EC%9E%A5-%EC%A2%8B%EC%9D%80-%EC%8B%9C%EC%A0%90</guid>
            <pubDate>Mon, 19 Sep 2022 11:37:37 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/">https://leetcode.com/problems/best-time-to-buy-and-sell-stock/</a></p>
<p>한 번의 거래로 낼 수 있는 최대 이익을 산출하라
<strong>입력</strong> : [7, 1, 5, 3, 6, 4]
<strong>출력</strong> : 5
<strong>설명</strong> : 1일 때 사서 6일 때 팔면 5의 이익을 얻는다</p>
<h1 id="풀이">풀이</h1>
<h2 id="bruteforce로-계산">BruteForce로 계산</h2>
<p>모든 경우의 수를 계산해 본다 -&gt; <code>O(N^2)</code>,     <code>timeout</code></p>
<pre><code class="language-python">class Solution:
    def maxProfit(self, prices: List[int]) -&gt; int:
        max_price = 0

        for i, price in enumerate(prices):
            for j in range(i, len(prices)):
                max_price = max(prices[j] - price, max_price)

        return max_price</code></pre>
<h2 id="저점과-현재-값과의-차이-계산">저점과 현재 값과의 차이 계산</h2>
<p>배열을 쭉 지나가면서 최저값을 저장하면서 현재 값과의 차이를 계산해준다
-&gt; <code>O(n)</code></p>
<pre><code class="language-python">class Solution:
    def maxProfit(self, prices: List[int]) -&gt; int:

        min_price = prices[0]
        max_price = 0

        for price in prices:
            min_price = min(min_price, price)
            max_price = max(price - min_price, max_price)

        return max_price
</code></pre>
<p>개선점 : min_price = price[0]을 sys.maxsize로 대체 가능하다</p>
]]></description>
        </item>
    </channel>
</rss>