<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jinyeong-afk.log</title>
        <link>https://velog.io/</link>
        <description>못하는 건 없다. 단지 그만큼 노력을 안 할 뿐이다.</description>
        <lastBuildDate>Sun, 27 Aug 2023 13:52:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jinyeong-afk.log</title>
            <url>https://images.velog.io/images/jinyeong-afk/profile/251fcd8d-7be5-45de-ac55-ebb1c728edff/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jinyeong-afk.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jinyeong-afk" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[백준 장학금 마지막 주차 회고]]></title>
            <link>https://velog.io/@jinyeong-afk/%EB%B0%B1%EC%A4%80-%EC%9E%A5%ED%95%99%EA%B8%88-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jinyeong-afk/%EB%B0%B1%EC%A4%80-%EC%9E%A5%ED%95%99%EA%B8%88-%EB%A7%88%EC%A7%80%EB%A7%89-%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 27 Aug 2023 13:52:57 GMT</pubDate>
            <description><![CDATA[<h2 id="설정한-목표와-목표-달성-결과">설정한 목표와 목표 달성 결과</h2>
<ol>
<li><p>기업 코딩 테스트를 준비하기 위해 백준 알고리즘 문제 한 달에 30문제 풀기 <strong>(성공)</strong>
<img src="https://velog.velcdn.com/images/jinyeong-afk/post/7f3f8cf2-d2c2-42b4-b700-36f205331749/image.png" alt=""></p>
</li>
<li><p>면접에 대한 준비를 하기 위해 백엔드 개발자 면접 질문 한 달에 20개 정리하여 블로그에 기록하기<strong>(성공)</strong>
2-1. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80">[기술 면접] 영속성 컨텍스트란?</a>
2-2. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%A6%89%EC%8B%9C-%EB%A1%9C%EB%94%A9%EA%B3%BC-%EC%A7%80%EC%97%B0-%EB%A1%9C%EB%94%A9%EC%9D%98-%EC%B0%A8">[기술 면접] JPA 즉시 로딩과 지연 로딩의 차이</a>
2-3. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-QueryDSL%EC%9D%B4%EB%9E%80">[기술 면접] QueryDSL이란?</a>
2-4. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-ArrayList%EC%99%80-LinkedList%EC%9D%98-%EC%B0%A8">[기술 면접] ArrayList와 LinkedList의 차이</a>
2-5. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-Java%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD">[기술 면접] Java의 메모리 영역</a>
2-6. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EB%A9%80%ED%8B%B0-%EC%93%B0%EB%A0%88%EB%93%9C%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC">[기술 면접] 멀티 쓰레드에 대하여</a>
2-7. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4">[기술 면접] 프로세스와 스레드의 차이</a>
2-8. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-DAO-DTO-VO-%EC%B0%A8%EC%9D%B4">[기술 면접] DAO, DTO, VO 차이</a>
2-9. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EB%8F%99%EA%B8%B0sync-%EB%B9%84%EB%8F%99%EA%B8%B0async-%EC%B0%A8">[기술 면접] 동기(sync), 비동기(async) 차이</a>
2-10. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-Java%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC">[기술면접] Java에 대하여</a>
2-11. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-Java-11-vs-Java-17-%EC%B0%A8%EC%9D%B4">[기술 면접] Java 11 vs Java 17 차이</a>
2-12. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%9B%B9%EC%86%8C%EC%BC%93-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC">[기술 면접] 웹소켓 개념 및 동작 원리</a>
2-13. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-SpringBootApplication-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0">[기술 면접] @SpringBootApplication 이해하기</a>
2-14. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%84%9C%EB%B8%94%EB%A6%BFServlet%EA%B3%BC-%EC%84%9C%EB%B8%94%EB%A6%BF-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88Servlet-Container%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC">[기술 면접] Servlet, Servlet Container, Dispatcher Servlet에 대하여</a>
2-15. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-Spring-IoC-Inversion-of-Control%EC%99%80-DI-Dependency-Injection%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC">[기술 면접] Spring IoC (Inversion of Control)와 DI (Dependency Injection)에 대하여</a>
2-16. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-MySQL-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0">[기술 면접] MySQL 인덱스 자료구조</a>
2-17. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0%EB%A9%B4%EC%A0%91-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%84%9C%EB%B2%84%EC%99%80-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EB%8F%99%EC%9E%91-%EB%B0%A9%EC%8B%9D">[기술면접] 스프링 서버와 클라이언트 동작 방식</a>
2-18. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-WSWeb-Server%EC%99%80-WASWeb-Application-Server%EC%9D%98-%EC%B0%A8%EC%9D%B4">[기술 면접] WS(Web Server)와 WAS(Web Application Server)의 차이</a>
2-19. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-Spring-Transactional-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%ACfeat.-AOP">[기술 면접] Spring @Transactional 동작 원리(feat. AOP)</a>
2-20. <a href="https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EA%B3%BC-%EA%B2%A9%EB%A6%AC%EC%84%B1">[기술 면접] 트랜잭션과 격리성</a></p>
</li>
</ol>
<ol start="3">
<li>꾸준히 취업 활동을 하고, 부족한 부분을 점검하기 위해 한 달에 15곳의 기업에 입사 지원하기<strong>(성공)</strong>
<img src="https://velog.velcdn.com/images/jinyeong-afk/post/ae65b35a-5b57-4ff0-a99e-e0567f1515d0/image.png" alt=""></li>
</ol>
<ol start="4">
<li><p>꾸준한 성장을 위한 노력의 증거로, 1일 1커밋 하기<strong>(성공)</strong>
<a href="https://github.com/jinyeong-afk">https://github.com/jinyeong-afk</a></p>
</li>
<li><p>꾸준한 성장을 위한 노력의 증거로, 기술 블로그 한 달 동안 10개의 글 작성하기(2번의 면접 준비 글 제외)<strong>(성공)</strong>
5-1. <a href="https://velog.io/@jinyeong-afk/Python-S5-14916%EB%B2%88-%EA%B1%B0%EC%8A%A4%EB%A6%84%EB%8F%88">[Python] S5 14916번: 거스름돈</a>
5-2. <a href="https://velog.io/@jinyeong-afk/Python-S1-1080%EB%B2%88-%ED%96%89%EB%A0%AC">[Python] S1 1080번: 행렬</a>
5-3. <a href="https://velog.io/@jinyeong-afk/Python-S4-2847%EB%B2%88-%EA%B2%8C%EC%9E%84%EC%9D%84-%EB%A7%8C%EB%93%A0-%EB%8F%99%EC%A4%80%EC%9D%B4">[Python] S4 2847번: 게임을 만든 동준이</a>
5-4. <a href="https://velog.io/@jinyeong-afk/Python-S5-1343%EB%B2%88-%ED%8F%B4%EB%A6%AC%EC%98%A4%EB%AF%B8%EB%85%B8">[Python] S5 1343번: 폴리오미노</a>
5-5. <a href="https://velog.io/@jinyeong-afk/Python-S3-1783%EB%B2%88-%EB%B3%91%EB%93%A0-%EB%82%98%EC%9D%B4%ED%8A%B8">[Python] S3 1783번: 병든 나이트</a>
5-6. <a href="https://velog.io/@jinyeong-afk/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-3-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%90%98%EA%B8%B0%EC%9E%90%EB%B0%94-%ED%8E%B8-%EC%9D%84-%EC%9D%BD%EA%B3%A0-%EB%82%98%EC%84%9C">&lt;스프링 부트 3 백엔드 개발자 되기(자바 편)&gt; 을 읽고 나서</a>
5-7. <a href="https://velog.io/@jinyeong-afk/Python-G4-16234-%EC%9D%B8%EA%B5%AC-%EC%9D%B4%EB%8F%99">[Python] G4 16234 인구 이동</a>
5-8. <a href="https://velog.io/@jinyeong-afk/Python-G4-11559-Puyo-Puyo">[Python] G4 11559 Puyo Puyo</a>
5-9. <a href="https://velog.io/@jinyeong-afk/Springboot-Entity%EC%97%90-Serializable-%EA%B5%AC%ED%98%84%EC%9D%84-%ED%95%B4%EC%95%BC-%ED%95%98%EB%82%98">[Springboot] Entity에 Serializable 구현을 해야 하나?</a>
5-10. <a href="https://velog.io/@jinyeong-afk/IT-%EC%A2%80-%EC%95%84%EB%8A%94-%EC%82%AC%EB%9E%8C-%EC%9D%84-%EC%9D%BD%EA%B3%A0-%EB%82%98%EC%84%9C">&lt;IT 좀 아는 사람&gt; 을 읽고 나서</a></p>
</li>
<li><p>개발 서적 2권 읽고 블로그에 작성하기<strong>(성공)</strong>
6-1. <a href="https://velog.io/@jinyeong-afk/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-3-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%90%98%EA%B8%B0%EC%9E%90%EB%B0%94-%ED%8E%B8-%EC%9D%84-%EC%9D%BD%EA%B3%A0-%EB%82%98%EC%84%9C">&lt;스프링 부트 3 백엔드 개발자 되기(자바 편)&gt; 을 읽고 나서</a>
6-2. <a href="https://velog.io/@jinyeong-afk/IT-%EC%A2%80-%EC%95%84%EB%8A%94-%EC%82%AC%EB%9E%8C-%EC%9D%84-%EC%9D%BD%EA%B3%A0-%EB%82%98%EC%84%9C">&lt;IT 좀 아는 사람&gt; 을 읽고 나서</a></p>
</li>
<li><p>서버 개발 개인 프로젝트(뷰 페이지 없이) 1개 완성하기<strong>(성공)</strong>
<a href="https://github.com/jinyeong-afk/personal-backend-project">개인 백엔드 프로젝트 깃허브</a></p>
</li>
</ol>
<h2 id="한-달-간의-회고">한 달 간의 회고</h2>
<p>백준 장학금을 시작하고 한 달이 지났다. 남들 보다 높은 목표를 잡았지만 목표를 설정할 때는 내가 이 목표를 이뤄낼 수 있을 거고 나는 정말 그만큼 노력할 거라는 다짐을 했었다. 하지만 첫째 주가 지나고 둘째 주에 접어들 때는 내가 목표를 너무 크게 잡았다는 걸 깨달았다. 그래서 그때까지만 해도 목표의 30퍼센트도 이루지 못했던 것 같다. 그래도 뚜렷한 목표와 빠듯한 마감 기한이 있었기 때문에 초조해진 나는 목표를 어떻게 이룰지 계획을 다시 잡게 되었고, 백준 장학금의 마감 기한이 다가올수록 나를 더욱 채찍질 하며 목표를 이루기 위해서 노력했다. 그 결과 마지막 날까지 밤잠을 설쳐가며 최선을 다해서 목표를 이룰 수 있었다. 위의 목표 결과를 공유한 것만 봐도 내가 한 달이라는 짧은 시간 동안 얼마나 노력했는지 알 수 있다. 한 달 동안 이렇게 노력한 내 모습이 너무 뿌듯하고, 나에게 이런 노력의 결과를 만들 수 있게 해준 백준 장학금을 주최해준 분들께 너무 감사하다.. 앞으로도 백준 장학금을 진행할 때의 감정을 잊지 않고, 꾸준히 노력해서 내가 목표한 기업에 취업에 성공하게 될 거라고 믿는다. 나 자신 화이팅!</p>
<h2 id="백준-장학금-도전을-시작하고-달라진-점">백준 장학금 도전을 시작하고 달라진 점</h2>
<p>대학교를 졸업하고 나서, 나를 이끌어줄 사람과 교육처가 사라지고, 함께 나아갈 동기들이 사라져서 혼자 취업 준비를 하다 보니 방향성을 잃거나 해이해지게 되어 취업 준비를 하고는 있었지만 흐지부지 하는 경우가 많았다. 하지만 백준 장학금 도전을 시작하고 나서 뚜렷한 목적과 나 자신을 채찍질 할 수 있는 빠듯한 마감 기한을 통해서 한 달이라는 짧은 시간 동안 최선을 다해서 나아가며, 해이해진 정신 상태를 붙잡고, 취업 준비에 전념할 수 있었던 것 같다.</p>
<h2 id="앞으로의-계획">앞으로의 계획</h2>
<p>백준 장학금을 도전하며 한 달 동안 달라진 모습, 그리고 결과를 통해 동기부여를 꾸준히 하여 이 모습 변하지 않고, 올해까지 꾸준히 취업 준비를 해서 빠르게 목표한 기업에 취업하는 것이 목표이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 55. Jump Game]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-55.-Jump-Game</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-55.-Jump-Game</guid>
            <pubDate>Fri, 25 Aug 2023 00:57:22 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>최대 점프 가능 횟수가 주어진 리스트에서 마지막 인덱스까지 이동이 가능한지 확인하는 문제이다. 간단하게 그리디 방식으로 풀었다.
for문으로 리스트를 탐색해서 이동 가능한 곳들을 모두 체크해서 마지막 인덱스까지 이동이 가능한지 확인하는 것이다.</p>
<pre><code class="language-python">class Solution:
    def canJump(self, nums: List[int]) -&gt; bool:
        leng = len(nums)
        check_list = [0] * leng
        check_list[0] = 1
        for i in range(leng):
            for j in range(1,nums[i]+1):
                if check_list[i] == 1 and i+j &lt; leng:
                    check_list[i+j] = 1
                else:
                    break
        return check_list[-1]</code></pre>
<p>처음엔 위와 같이 했지만 시간 복잡도에서 통과하지 못해서 두 번째 for문 즉, 이동 가능한 곳을 체크할 때 for문을 뒤에서부터 탐색하고, 이미 체크한 곳이면 break를 걸어 시간 복잡도를 줄여주니 문제가 해결됐다.</p>
<ol>
<li><p>이동 가능한 곳을 체크할 리스트를 만든다.</p>
</li>
<li><p>for문을 통해 리스트를 탐색한다. 
※ 단, 이동 가능한 리스트만 탐색한다.</p>
</li>
<li><p>최대 이동 가능 위치부터 역순으로 리스트의 이동 횟수 만큼 탐색하며, 이동 가능한 곳을 체크해준다.</p>
</li>
<li><p>마지막 인덱스가 이동 가능하면 True 아니면 False를 return 해준다.</p>
<h2 id="답">답</h2>
<pre><code class="language-python">class Solution:
 def canJump(self, nums: List[int]) -&gt; bool:
     leng = len(nums)
     check_list = [0] * leng ## 1. 이동 가능한 곳을 체크할 리스트를 만든다.
     check_list[0] = 1
     for i in range(leng): ## 2. for문을 통해 리스트를 탐색한다.
         if not check_list[i]:
             continue
         for j in range(min(i + nums[i],leng-1), 0, -1): ## 3. 최대 이동 가능 위치부터 역순으로 리스트의 이동 횟수 만큼 탐색하며, 이동 가능한 곳을 체크해준다.
             if check_list[-1]:
                 return True
             elif check_list[j] == 1:
                 break
             else:
                 check_list[j] = 1

     return check_list[-1] ## 4. 마지막 인덱스가 이동 가능하면 True 아니면 False를 return 해준다.</code></pre>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 122. Best Time to Buy and Sell Stock II]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-122.-Best-Time-to-Buy-and-Sell-Stock-II</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-122.-Best-Time-to-Buy-and-Sell-Stock-II</guid>
            <pubDate>Fri, 25 Aug 2023 00:50:38 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>언제든 주식을 사고 팔 수 있는 상황에서 가장 많은 수익을 냈을 때의 값을 찾는 문제이다. 이 문제는 그리디 방식으로 풀었다.
주식을 살 수 있을 때 최대한 싼 주식으로 사고, 팔 수 있을 때는 무조건 팔면서 수익을 극대화하면 된다.</p>
<ol>
<li><p>산 주식을 리스트의 첫 번째 원소로 지정해준다.</p>
</li>
<li><p>for문으로 리스트의 두 번째 원소부터 탐색한다.</p>
</li>
<li><p>현재 인덱스에서 주식을 팔았을 때 이득이면 팔고, 총 수익에 더해준다.</p>
</li>
<li><p>그리고 다시 현재 주식을 산다.</p>
</li>
<li><p>이득이 아니면 산 주식과 현재 인덱스의 주식 중 싼 주식을 산 주식으로 해준다.</p>
</li>
<li><p>총 수익을 return 해준다.</p>
</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">class Solution:
    def maxProfit(self, prices: List[int]) -&gt; int:
        total = 0
        buy = prices[0] ## 1. 산 주식을 리스트의 첫 번째 원소로 지정해준다.
        for i in range(1, len(prices)): ## 2. for문으로 리스트의 두 번째 원소부터 탐색한다.
            if prices[i]- buy &gt; 0: ## 3. 현재 인덱스에서 주식을 팔았을 때 이득이면 팔고, 총 수익에 더해준다.
                total += prices[i] - buy
                buy = prices[i] ## 4. 그리고 다시 현재 주식을 산다.
            else:
                buy = min(buy, prices[i]) ## 5. 이득이 아니면 산 주식과 현재 인덱스의 주식 중 싼 주식을 산 주식으로 해준다.
        return total ## 6. 총 수익을 return 해준다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 121. Best Time to Buy and Sell Stock]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-121.-Best-Time-to-Buy-and-Sell-Stock</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-121.-Best-Time-to-Buy-and-Sell-Stock</guid>
            <pubDate>Fri, 25 Aug 2023 00:45:21 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>주식의 값들이 주어질 때, 어떤 날에 사거나 팔아서 가장 수익을 많이 낼 수 있는 값을 찾는 문제이다.
나는 dp로 이 문제를 풀었다.</p>
<ol>
<li><p>dp 리스트를 만들어준다.</p>
</li>
<li><p>산 주식을 첫 번째 리스트 원소로 지정해준다.</p>
</li>
<li><p>for문을 두 번째 원소부터 시작하여 탐색한다.</p>
</li>
<li><p>dp 리스트에 현재 주식 값에서 산 주식을 빼준 값을 넣어준다.</p>
</li>
<li><p>현재 주식이 산 주식보다 싸다면 현재 주식을 산 주식으로 바꿔준다.</p>
</li>
<li><p>dp 리스트에서 가장 큰 값을 return 해준다.</p>
</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">class Solution:
    def maxProfit(self, prices: List[int]) -&gt; int:
        dp = [0] * len(prices) ## 1. dp 리스트를 만들어준다.
        buy = prices[0] ## 2. 산 주식을 첫 번째 리스트 원소로 지정해준다.
        for i in range(1, len(prices)): ## 3. for문을 두 번째 원소부터 시작하여 탐색한다.
            dp[i] = prices[i] - buy ## 4. dp 리스트에 현재 주식 값에서 산 주식을 빼준 값을 넣어준다.
            buy = min(buy, prices[i]) ## 5. 현재 주식이 산 주식보다 싸다면 현재 주식을 산 주식으로 바꿔준다.
        return max(dp) ## 6. dp 리스트에서 가장 큰 값을 return 해준다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 189. Rotate Array]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-189.-Rotate-Array</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-189.-Rotate-Array</guid>
            <pubDate>Fri, 25 Aug 2023 00:40:20 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>리스트가 원으로 연결되어 있다고 생각하고, 시계 방향으로 회전시키는 문제이다.</p>
<pre><code class="language-python">from collections import deque
class Solution:
    def rotate(self, nums: List[int], k: int) -&gt; None:
        nums = deque(nums)
        for i in range(k):
            nums.rotate(1)
        nums = list(nums)</code></pre>
<p>파이썬은 위와 같이 rotate 함수를 자체적으로 지원해줘서 이 함수를 가져다 쓰면 손쉽게 구현할 수 있지만 LeetCode는 리스트를 새로 선언하는 것을 다른 리스트로 판단하고, 인정해주지 않는다. 그래서 직접 구현해야 한다.</p>
<ol>
<li><p>for문으로 리스트를 탐색한다.</p>
</li>
<li><p>리스트의 마지막 원소를 제거해준다.</p>
</li>
<li><p>제거해준 리스트의 마지막 원소를 리스트의 첫 번째 위치에 삽입한다.</p>
</li>
<li><p>이 과정을 k번 반복한다.</p>
</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">class Solution:
    def rotate(self, nums: List[int], k: int) -&gt; None:
        for i in range(k): ## 1. for문으로 리스트를 탐색한다.

        ## 2. 리스트의 마지막 원소를 제거해준다.
        ## 3. 제거해준 리스트의 마지막 원소를 리스트의 첫 번째 위치에 삽입한다.
            nums.insert(0,nums.pop()) </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 169. Majority Element]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-169.-Majority-Element</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-169.-Majority-Element</guid>
            <pubDate>Fri, 25 Aug 2023 00:32:48 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>리스트의 길이 / 2 보다 중복 개수가 많은 원소들 중에서 가장 높은 원소를 return 해주는 문제이다.</p>
<ol>
<li><p>int defaultdict를 선언해준다.</p>
</li>
<li><p>for문으로 리스트를 탐색한다.</p>
</li>
<li><p>딕셔너리에 원소의 개수를 1씩 더해 카운트 해준다.</p>
</li>
<li><p>원소의 개수가 리스트의 길이 / 2 보다 큰지 확인한다.</p>
</li>
<li><p>크다면 result 리스트에 저장한다.</p>
</li>
<li><p>result 리스트 중 가장 큰 값을 return 한다.</p>
</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">from collections import defaultdict
class Solution:
    def majorityElement(self, nums: List[int]) -&gt; int:
        nums_cnt = defaultdict(int) ## 1. int defaultdict를 선언해준다.
        leng = len(nums)
        result = []
        for i in range(leng): ## 2. for문으로 리스트를 탐색한다.
            nums_cnt[nums[i]] += 1 ## 3. 딕셔너리에 원소의 개수를 1씩 더해 카운트 해준다.
            if nums_cnt[nums[i]] &gt;= leng/2: ## 4. 원소의 개수가 리스트의 길이 / 2 보다 큰지 확인한다.
                result.append(nums[i]) ## 5. 크다면 result 리스트에 저장한다.
        return max(result) ## 6. result 리스트 중 가장 큰 값을 return 한다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 80. Remove Duplicates from Sorted Array II]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-80.-Remove-Duplicates-from-Sorted-Array-II</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-80.-Remove-Duplicates-from-Sorted-Array-II</guid>
            <pubDate>Fri, 25 Aug 2023 00:26:40 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>리스트 원소의 중복된 값을 2개까지만 허용하고, 나머지는 제거하는 문제이다.</p>
<pre><code class="language-python">class Solution:
    def removeDuplicates(self, nums: List[int]) -&gt; int:
        cnt_arr = [0] * (max(nums) + 1)
        cnt = 0
        for i in range(len(nums)):
            cnt_arr[nums[cnt]] += 1
            if cnt_arr[nums[cnt]] == 3:
                cnt_arr[nums[cnt]] -= 1
                del nums[cnt]
                cnt -=1
            cnt += 1</code></pre>
<p>처음에는 위와 같이 리스트를 만들어 값을 해당 값이 몇 개인지 기록을 했었는데 음수 값도 존재하기 때문에 음수를 표현하기 곤란해서 리스트 대신 딕셔너리를 활용했다.</p>
<ol>
<li><p>int defaultdict를 선언해준다.</p>
</li>
<li><p>for문으로 리스트를 탐색한다.</p>
</li>
<li><p>딕셔너리에 해당 값의 개수를 1씩 더해준다.</p>
</li>
<li><p>해당 값의 개수가 3개가 되는지 확인한다.</p>
</li>
<li><p>해당 값의 개수가 개가 되면 해당 인덱스의 원소를 제거해준다.</p>
</li>
<li><p>이 과정을 반복한다.</p>
</li>
</ol>
<p>※ 주의해야 될 점은 중복 개수가 3개가 되어서 제거했을 때, 기록한 중복 값을 1 빼주고, 제거 된 원소의 빈자리를 뒷부분 원소들이 당겨져서 채워지기 때문에 다시 현재 인덱스를 탐색해야 한다.</p>
<h2 id="답">답</h2>
<pre><code class="language-python">from collections import defaultdict
class Solution:
    def removeDuplicates(self, nums: List[int]) -&gt; int:
        nums_cnt = defaultdict(int) ## 1. int defaultdict를 선언해준다.
        cnt = 0
        for i in range(len(nums)): ## 2. for문으로 리스트를 탐색한다.
            nums_cnt[nums[cnt]] += 1 ## 3. 딕셔너리에 해당 값의 개수를 1씩 더해준다.
            if nums_cnt[nums[cnt]] == 3: ## 4. 해당 값의 개수가 3개가 되는지 확인한다.
                nums_cnt[nums[cnt]] -= 1
                del nums[cnt] ## 5. 해당 값의 개수가 개가 되면 해당 인덱스의 원소를 제거해준다.
                cnt -=1
            cnt += 1</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 26. Remove Duplicates from Sorted Array]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-26.-Remove-Duplicates-from-Sorted-Array</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-26.-Remove-Duplicates-from-Sorted-Array</guid>
            <pubDate>Fri, 25 Aug 2023 00:17:15 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>리스트의 중복 원소를 제거해주는 문제이다.</p>
<pre><code class="language-python">class Solution:
    def removeDuplicates(self, nums: List[int]) -&gt; int:
        nums = set(nums)
        nums = list(nums)</code></pre>
<p>파이썬은 위와 같이 set으로 옮겨 담으면 중복을 제거할 수 있지만 LeetCode는 기존의 저런식으로 nums를 재선언하는 것을 답으로 허용하지 않는 것 같다. 그래서 중복을 일일히 찾아서 제거해줬다.</p>
<ol>
<li><p>for 문으로 리스트를 탐색한다.</p>
</li>
<li><p>인덱스의 원소가 인덱스 이전까지의 원소들이 포함된 리스트 안에 존재하는지 확인한다.</p>
</li>
<li><p>존재한다면 중복된 원소이므로, 제거해준다.</p>
</li>
<li><p>이 과정을 for 문이 끝날 때까지 반복한다.</p>
</li>
</ol>
<p>※ 주의 할 점은 해당 원소를 제거하면 이후의 원소들이 당겨져서 빈자리를 채우기 때문에 제거하고 나서는 인덱스 값을 증가시키면 안되고, 다시 현재의 인덱스 값을 확인해야 한다.</p>
<h2 id="답">답</h2>
<pre><code class="language-python">class Solution:
    def removeDuplicates(self, nums: List[int]) -&gt; int:
        cnt = 1
        for i in range(1, len(nums)): ## 1. for 문으로 리스트를 탐색한다.
            if nums[cnt] in nums[:cnt]: ## 2. 인덱스의 원소가 인덱스 이전까지의 원소들이 포함된 리스트 안에 존재하는지 확인한다.
                del nums[cnt] ## 3. 존재한다면 중복된 원소이므로, 제거해준다.
                cnt -=1
            cnt += 1</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] LeetCode 88. Merge Sorted Array]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-LeetCode-88.-Merge-Sorted-Array</link>
            <guid>https://velog.io/@jinyeong-afk/Python-LeetCode-88.-Merge-Sorted-Array</guid>
            <pubDate>Fri, 25 Aug 2023 00:05:32 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>nums1은 인덱스 m개의 원소, nums2는 인덱스 n까지의 원소를 가진 채 nums2를 nums1에 합치고 정렬하는 문제였다.</p>
<ol>
<li><p>nums1 리스트를 슬라이싱으로 m개까지 자른다.</p>
</li>
<li><p>nums2 리스트를 슬라이싱으로 n개까지 자른다.</p>
</li>
<li><p>num1 리스트에 nums2 리스트를 더하여 합친다.</p>
</li>
<li><p>합쳐진 nums1 리스트를 정렬한다.</p>
</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -&gt; None:
         del nums1[m:] ## 1. nums1 리스트를 슬라이싱으로 m개까지 자른다.
         del nums2[n:] ## 2. nums2 리스트를 슬라이싱으로 n개까지 자른다.
         nums1 += nums2 ## 3. num1 리스트에 nums2 리스트를 더하여 합친다.
         nums1.sort() ## 4. 합쳐진 nums1 리스트를 정렬한다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 장학금 4주차 회고]]></title>
            <link>https://velog.io/@jinyeong-afk/%EB%B0%B1%EC%A4%80-%EC%9E%A5%ED%95%99%EA%B8%88-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jinyeong-afk/%EB%B0%B1%EC%A4%80-%EC%9E%A5%ED%95%99%EA%B8%88-4%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 20 Aug 2023 13:44:35 GMT</pubDate>
            <description><![CDATA[<p>드디어 백준장학금 마지막 주차가 끝났다... 길다면 길고 짧다면 짧은 한 달의 기간이었다.</p>
<h2 id="백준-장학금-4주차-경과">백준 장학금 4주차 경과</h2>
<h3 id="1일-1커밋성공">1일 1커밋(성공)</h3>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/0cdc1687-0350-411c-b33d-8be78d01b86e/image.png" alt="">
1일 1커밋은 7월 19일부터 시작해서 8월 20일까지 꾸준히 프로젝트와 알고리즘 공부했던 것을 정리하면서 성공할 수 있었다. 꾸준하게 매일매일 하는 게 가장 어렵다고 생각했는데 이것은 생각보다 어렵지 않았던 것 같다.</p>
<h3 id="알고리즘성공">알고리즘(성공)</h3>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/231e7310-bc39-4ab1-abf5-4d35a5b6f53f/image.png" alt=""></p>
<p>한 달 동안 알고리즘 30개 풀기도 정확히 30개를 풀며 성공적으로 마무리 할 수 있었다.
처음에는 난이도 높은 문제를 억지로 두세 시간씩 붙잡으면서 풀다가 안되면 풀이를 보면서 배우는 방식으로 진행을 했었는데 목표 했던 게 30개여서 알고리즘만 매일 진행한다면 그렇게 해도 할 수 있었겠지만 다른 목표들도 많았기 때문에 문제 수준을 낮추고, 여러 문제 유형을 경험하고 익히자라는 생각으로 바꾸며, 어찌저찌 30개를 다 풀 수 있었던 것 같다.</p>
<h3 id="입사지원성공">입사지원(성공)</h3>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/7df949d5-1e4e-45b3-8210-2e64542a819b/image.png" alt="">
원티드로만 20곳 지원하고, 홈페이지로 지원했던 것을 합치면 30곳 넘게 지원한 것 같다.</p>
<h3 id="개인-프로젝트성공">개인 프로젝트(성공)</h3>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/ed0a171f-14fc-46be-9a26-653558ca107d/image.png" alt=""></p>
<p>개인 프로젝트는 Git으로 이슈하며, Mockito를 적용한 테스트 코드를 작성하여 프로젝트의 기초적인 부분을 신경 쓰며, Backend 서버 부분만을 완성시키는 것을 목표로 했고, 성공적으로 마무리 할 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/a8becffd-b383-48fc-91ba-fa30b64074ac/image.png" alt=""></p>
<h3 id="면접-준비성공">면접 준비(성공)</h3>
<p>백준 장학금 시작 전의 기술 면접 글 5개를 제외한 20개를 작성하며, 기술 면접에 관한 질문과 그에 대한 내용을 정리하며, 공부를 했다. 처음엔 간단하게 생각했는데 정리를 하다보니 내 스스로 공부를 하고, 그것을 정리하면서 글을 작성하다 보니 오랜 시간이 걸려서 이 부분이 가장 어려웠던 것 같다. 하지만 면접에 대비하는 것이기 때문에 조금 더 간소화 하여 성공적으로 마무리 할 수 있었다.</p>
<h3 id="기술-블로그-글-작성성공">기술 블로그 글 작성(성공)</h3>
<p>백준 장학금 시작 전의 전체 글 수 47 개와 백준 장학금 회고 글 3개를 제외하고, 면접 글 20개와, 면접 글을 제외한 10개의 글을 작성하는 데 성공했다. 면접 글 작성하는 것도 쉽지 않았는데 다른 글도 10개나 작성하는 것이 정말 어렵게 느껴졌다. 내가 프로젝트를 하며 공부했던 것과 알고리즘을 풀면서 이해했던 내용을 정리하며 10개의 글을 작성할 수 있었다.</p>
<h3 id="개발-서적성공">개발 서적(성공)</h3>
<p>IT 좀 아는 사람, 스프링 부트 3 백엔드 개발자 되기(자바 편) 두 권을 읽고 책 카테고리에 글을 2개 작성하며 성공적으로 마무리 할 수 있었다. 어떤 책을 읽을지 모르겠고, 책을 여러 권 사기엔 돈이 아까웠는데 밀리의 서재에도 IT 관련 서적이 있길래 그곳에서 이 책 두 권을 모두 읽을 수 있었는데 시간 날 때마다 간단하게 휴대폰으로 읽기에 괜찮았던 것 같다.</p>
<h2 id="목표-달성-현황">목표 달성 현황</h2>
<ol>
<li>기업 코딩 테스트를 준비하기 위해 백준 알고리즘 문제 한 달에 30문제 풀기<strong>(성공)</strong></li>
<li>면접에 대한 준비를 하기 위해 백엔드 개발자 면접 질문 한 달에 20개 정리하여 블로그에 기록하기<strong>(성공)</strong></li>
<li>꾸준히 취업 활동을 하고, 부족한 부분을 점검하기 위해 한 달에 15곳의 기업에 입사 지원하기<strong>(성공)</strong></li>
<li>꾸준한 성장을 위한 노력의 증거로, 1일 1커밋 하기<strong>(성공)</strong></li>
<li>꾸준한 성장을 위한 노력의 증거로, 기술 블로그 한 달 동안 10개의 글 작성하기(2번의 면접 준비 글 제외)<strong>(성공)</strong></li>
<li>개발 서적 2권 읽고 블로그에 작성하기<strong>(성공)</strong></li>
<li>서버 개발 개인 프로젝트(뷰 페이지 없이) 1개 완성하기<strong>(성공)</strong></li>
</ol>
<p>목표 7개 모두 성공</p>
<h2 id="회고">회고</h2>
<p>목표를 정말 높게 잡았기 때문에 백준 장학금을 시작한 초반에는 내가 이걸 정말로 해낼 수 있을까? 라는 의문을 가지기도 했지만 포기하지 않고, 단순히 장학금을 목표로 하기 보다는 이 기회를 통해 성장한 나를 보기 위해서 끝까지 포기하지 않고, 해내서 결국 성공할 수 있었던 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] S5 14916번: 거스름돈 ]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-S5-14916%EB%B2%88-%EA%B1%B0%EC%8A%A4%EB%A6%84%EB%8F%88</link>
            <guid>https://velog.io/@jinyeong-afk/Python-S5-14916%EB%B2%88-%EA%B1%B0%EC%8A%A4%EB%A6%84%EB%8F%88</guid>
            <pubDate>Sun, 20 Aug 2023 13:15:47 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>최소 동전 개수를 구해야 하기 때문에 5원 짜리의 개수가 더 많도록 거스름돈을 구해주면 된다.</p>
<ol>
<li><p>5로 나누어 떨어지는지 확인한다.</p>
</li>
<li><p>5로 나누어 떨어지지 않는다면 2를 뺀다.</p>
</li>
<li><p>5로 나누어 떨어질 때까지 1,2의 과정을 반복한다.</p>
</li>
<li><p>돈이 0이 된다면 동전의 개수를 출력하고, 음수가 된다면 -1을 출력해준다.</p>
</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">n = int(input())

cnt = 0
i = 0
while True:
    if n % 5 == 0:   
        cnt += n//5        
        break
    else:
        n -= 2   
        cnt += 1

    if n &lt; 0:  
        break
if n&lt;0:            
    print(-1)            
else:
    print(cnt)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] S1 1080번: 행렬]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-S1-1080%EB%B2%88-%ED%96%89%EB%A0%AC</link>
            <guid>https://velog.io/@jinyeong-afk/Python-S1-1080%EB%B2%88-%ED%96%89%EB%A0%AC</guid>
            <pubDate>Sun, 20 Aug 2023 13:09:01 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>3 곱하기 3 칸씩 뒤집을 수 있기 때문에 2중 for문을 통해서 [0][0]부터 순서대로 행렬이 다를 경우 뒤집는 걸 반복하다 보면 왼쪽 위부터 순서대로 다른 것들만 뒤집기 했기 때문에 이미 뒤집어서 같게 바꿔줬던 건 바뀔 일이 없어서 두 행렬이 같아지는 결과를 얻을 수 있다. 하지만 결과가 다를 경우 -1을 출력해주면 된다.
단, for 문으로 탐색할 때는 그 좌표가 가장 왼쪽 위라고 생각하고 3 곱하기 3이 확보될 때만 뒤집는다.</p>
<ol>
<li>2중 for 문으로 왼쪽위부터 순서대로 탐색한다.</li>
<li>두 행렬이 다를 경우 3 곱하기 3 뒤집기를 한다.</li>
<li>이것을 끝까지 반복한다.</li>
<li>두 결과를 비교하여 같으면 count를 출력, 아니면 -1을 출력해준다.</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">n, m = map(int, input().split()) 
listA = []
for _ in range(n): # 리스트A 선언
    listA.append(list(map(int, list(input()))))
listB = []
for _ in range(n): # 리스트B 선언
    listB.append(list(map(int, list(input()))))


def check(i, j): # 뒤집기 함수
    for x in range(i, i+3):
        for y in range(j, j+3):
            if listA[x][y] == 0:
                listA[x][y] = 1
            else:
                listA[x][y] = 0


cnt = 0 # 카운트
if (n &lt; 3 or m &lt; 3) and listA != listB:
    # 예외 1, 리스트가 작을 때
    cnt = -1
else:
    for r in range(n-2):
        for c in range(m-2):
            if listA[r][c] != listB[r][c]:
                cnt += 1
                check(r, c)

if cnt != -1:
    if listA != listB: # A와 B가 같은지 확인
        cnt = -1
print(cnt)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] S4 2847번: 게임을 만든 동준이]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-S4-2847%EB%B2%88-%EA%B2%8C%EC%9E%84%EC%9D%84-%EB%A7%8C%EB%93%A0-%EB%8F%99%EC%A4%80%EC%9D%B4</link>
            <guid>https://velog.io/@jinyeong-afk/Python-S4-2847%EB%B2%88-%EA%B2%8C%EC%9E%84%EC%9D%84-%EB%A7%8C%EB%93%A0-%EB%8F%99%EC%A4%80%EC%9D%B4</guid>
            <pubDate>Sun, 20 Aug 2023 12:45:46 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>이전 레벨의 점수가 다음 레벨의 점수보다 낮아지도록 바꾸면 된다.
하지만 앞에서부터 확인하면서 바꿔주면 경우의 수가 더 많아지기 때문에 뒤에서부터 확인해준다.</p>
<ol>
<li>맨 마지막 점수(높은 레벨의 점수)부터 그 앞의 수(낮은 레벨의 점수)와 비교한다.</li>
<li>낮은 레벨의 점수가 높은 레벨의 점수보다 높거나 같다면 낮은 레벨의 점수를 한 단계 높은 레벨의 점수보다 1 낮게 바꾼다.</li>
<li>이 과정을 뒤에서 앞으로 반복한다.</li>
</ol>
<p>ex) 점수 5 5 5가 주어졌을 경우, 1~3 레벨까지 모두 점수를 5씩 주기 1, 2 레벨에 문제가 있다.
5 5 5 -&gt; 3 4 5 이렇게 바뀌게 되는데 결론적으로 5-(1<em>2) 5-(1</em>1) 5 이기 때문에 답이 3이 된다.</p>
<h2 id="답">답</h2>
<pre><code class="language-python">n = int(input())
score = []
for i in range(n):
    score.append(int(input()))

count = 0
for i in range(n-2, -1, -1):
    if score[i] &gt;= score[i+1]:
        count += score[i] - score[i+1] + 1
        score[i] = score[i+1]-1

print(count)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] S5 1343번: 폴리오미노]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-S5-1343%EB%B2%88-%ED%8F%B4%EB%A6%AC%EC%98%A4%EB%AF%B8%EB%85%B8</link>
            <guid>https://velog.io/@jinyeong-afk/Python-S5-1343%EB%B2%88-%ED%8F%B4%EB%A6%AC%EC%98%A4%EB%AF%B8%EB%85%B8</guid>
            <pubDate>Sun, 20 Aug 2023 12:28:30 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-풀이">문제 풀이</h2>
<p>replace 함수는 왼쪽부터 해당하는 것을 치환해주기 때문에 replace 함수를 사용하면 간단하다.</p>
<ol>
<li>&#39;XXXX&#39;를 먼저 &#39;AAAA&#39;로 치환해준다.</li>
<li>1번을 수행한 결과에서 &#39;XX&#39;를 &#39;BB&#39;로 치환해준다.</li>
<li>이렇게 해서 X가 남아있다면 -1, 아니면 결과를 출력해준다.</li>
</ol>
<h2 id="답">답</h2>
<pre><code class="language-python">board = input()

board = board.replace(&quot;XXXX&quot;, &quot;AAAA&quot;)
board = board.replace(&quot;XX&quot;, &quot;BB&quot;)

if &#39;X&#39; in board:
    print(-1)

else:
    print(board)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] S3 1783번: 병든 나이트]]></title>
            <link>https://velog.io/@jinyeong-afk/Python-S3-1783%EB%B2%88-%EB%B3%91%EB%93%A0-%EB%82%98%EC%9D%B4%ED%8A%B8</link>
            <guid>https://velog.io/@jinyeong-afk/Python-S3-1783%EB%B2%88-%EB%B3%91%EB%93%A0-%EB%82%98%EC%9D%B4%ED%8A%B8</guid>
            <pubDate>Sun, 20 Aug 2023 12:23:48 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>문제
병든 나이트가 N × M 크기 체스판의 가장 왼쪽아래 칸에 위치해 있다. 병든 나이트는 건강한 보통 체스의 나이트와 다르게 4가지로만 움직일 수 있다.</p>
<p>2칸 위로, 1칸 오른쪽
1칸 위로, 2칸 오른쪽
1칸 아래로, 2칸 오른쪽
2칸 아래로, 1칸 오른쪽
병든 나이트는 여행을 시작하려고 하고, 여행을 하면서 방문한 칸의 수를 최대로 하려고 한다. 병든 나이트의 이동 횟수가 4번보다 적지 않다면, 이동 방법을 모두 한 번씩 사용해야 한다. 이동 횟수가 4번보다 적은 경우(방문한 칸이 5개 미만)에는 이동 방법에 대한 제약이 없다.</p>
<p>체스판의 크기가 주어졌을 때, 병든 나이트가 여행에서 방문할 수 있는 칸의 최대 개수를 구해보자.</p>
<h2 id="답">답</h2>
<pre><code class="language-python">n, m = map(int, input().split())
if n == 1:
    print(1)
elif n == 2:
    print(min(4, (m-1)//2+1))
elif m &lt;= 6:
    print(min(4, m))
else:
    print(m-2)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[<스프링 부트 3 백엔드 개발자 되기(자바 편)> 을 읽고 나서]]></title>
            <link>https://velog.io/@jinyeong-afk/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-3-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%90%98%EA%B8%B0%EC%9E%90%EB%B0%94-%ED%8E%B8-%EC%9D%84-%EC%9D%BD%EA%B3%A0-%EB%82%98%EC%84%9C</link>
            <guid>https://velog.io/@jinyeong-afk/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-3-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%90%98%EA%B8%B0%EC%9E%90%EB%B0%94-%ED%8E%B8-%EC%9D%84-%EC%9D%BD%EA%B3%A0-%EB%82%98%EC%84%9C</guid>
            <pubDate>Sun, 20 Aug 2023 11:51:31 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/10c72a11-91f4-41c0-848c-bcc52d5042a2/image.png" alt=""></p>
<h2 id="개요">개요</h2>
<p>스프링을 처음 배울 때 김영한 님의 무료 스프링 강의 기본편을 들으며 개념에 대해서 들었는데 내용이 너무 어렵고 머릿속에 들어오지 않았다.
나는 개념을 먼저 익히고 프로젝트에 적용시키기 보다는 프로젝트에 적용시키면서 그것에 대해 이해를 하고 알아가는 타입이라는 걸 깨닫고 개념 강의는 한 번만 듣고 넘어갔더니 머릿속에 남은 게 많지 않았다. 스프링을 사용해서 구현한 프로젝트가 꽤 많은데도 불구하고 말이다.
그래서 시간이 남을 때 스프링 개념에 대해 다시 배우고자 하여 이 책을 읽게 되었다.</p>
<h2 id="책-소개">책 소개</h2>
<p>★ 자바 백엔드 개발자가 되고 싶다면
★ 자바 언어 입문 그다음에 꼭 보세요실력을 갖춘 개발자로 성장하려면 시작이 중요합니다. 그래서 이 책은 무엇부터 익혀야 하는지 막막한 입문자에게 백엔드 개발의 필수 지식을 학습 로드맵 중심으로 설명합니다. 이어서 스프링 부트 3 개발에 꼭 필요한 4대장인 JPA ORM, OAuth2 인증, AWS 배포, CI/CD를 최신 트렌드에 맞게 그리고 실무에 유용하게 알려줍니다. 모든 장 끝에는 연습문제가 수록되어 있어 배운 내용을 점검할 수 있습니다. 이 책이 여러분의 백엔드 개발자 여정에 든든한 나침반이 되어 줄 겁니다.</p>
<h2 id="리뷰">리뷰</h2>
<p>우선 책 제목처럼 스프링 부트를 사용하는 백엔드 개발자가 되기 위한 내용들이 담겨 있어 기본에 대한 내용이 대부분이었다. 그래서 스프링으로 서버를 구현하면서 보안, 배포까지 다 경험해본 나에게는 아는 내용들이 너무 많았고, 모르는 내용도 깊게 들어가는 듯한 느낌이 아니어서 조금 아쉬웠다. 하지만 스프링을 처음 배우거나 아직 기초적인 것밖에 모르는 초보자에게는 상당히 좋은 책이라고 생각한다. 기본적인 개념과 더불어 실습 코드와 테스트 코드, 그리고 목차 또한 기본 개념부터 실습 구현, 보안, 배포까지 백엔드 개발자로서 기본적으로 경험해봐야 할 거의 모든 것들을 다루기 때문에 이 책을 여러 번 읽고 나면 스프링을 어떻게 활용해야 하고, 본인이 어떤 부분을 더 공부해야 할지 깨닫게 될 것이다.</p>
<h2 id="요약">요약</h2>
<p>초보자들이 읽기에 안에 담긴 내용이 웬만한 강의보다 괜찮다고 생각한다. 비싼 돈 주고 강의를 듣기 싫거나 본인이 강의 보다는 책을 통해서 배우는 걸 좋아한다면 적극 추천한다. 구현, 테스트 코드, 보안, 배포까지 모두 어느 정도 경험해본 사람이라면 굳이 추천하진 않지만 가볍게 읽어볼 수는 있을 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술 면접] 영속성 컨텍스트란?]]></title>
            <link>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80</link>
            <guid>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80</guid>
            <pubDate>Sun, 20 Aug 2023 11:35:54 GMT</pubDate>
            <description><![CDATA[<h2 id="영속성-컨텍스트란">영속성 컨텍스트란?</h2>
<p>영속성 컨텍스트란 엔티티를 영구 저장하는 환경이라는 뜻이다. 애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스 같은 역할을 한다. 엔티티 매니저를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.</p>
<pre><code class="language-javascript">em.persist(member);</code></pre>
<ul>
<li>엔티티 매니저를 사용해 회원 엔티티를 영속성 컨텍스트에 저장한다는 의미</li>
</ul>
<h3 id="영속성-컨텍스트의-특징">영속성 컨텍스트의 특징</h3>
<ul>
<li>엔티티 매니저를 생성할 때 하나 만들어진다.</li>
<li>엔티티 매니저를 통해서 영속성 컨텍스트에 접근하고 관리할 수 있다.</li>
</ul>
<h2 id="엔티티-생명주기">엔티티 생명주기</h2>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/e34b399f-6a96-43ff-8d2e-bdd70936be4d/image.png" alt=""></p>
<h3 id="비영속newtransient-상태-영속성-컨텍스트와-관계가-없는-상태">비영속(new/transient) 상태: 영속성 컨텍스트와 관계가 없는 상태</h3>
<pre><code class="language-javascript">// 객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId(&quot;member1&quot;);
member.setUsername(&quot;회원1&quot;);</code></pre>
<h3 id="영속managed-상태-영속성-컨텍스트에-저장된-상태">영속(managed) 상태: 영속성 컨텍스트에 저장된 상태</h3>
<pre><code class="language-javascript">// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId(&quot;member1&quot;);
member.setUsername(&quot;회원1&quot;);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 지정한 상태(영속)
em.persist(member);</code></pre>
<h3 id="준영속detached-상태-영속성-컨텍스트에-저장되었다가-분리된-상태">준영속(detached) 상태: 영속성 컨텍스트에 저장되었다가 분리된 상태</h3>
<pre><code class="language-javascript">// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);</code></pre>
<ul>
<li>1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다.</li>
<li>식별자 값을 가지고 있다.</li>
</ul>
<h3 id="삭제removed-상태-삭제된-상태">삭제(removed) 상태: 삭제된 상태</h3>
<pre><code class="language-javascript">// 객체를 삭제한 상태(삭제)
em.remove(member);
// 영속성 컨텍스트를 비워도 관리되던 엔티티는 준영속성 상태가 된다.
em.clear();
// 영속성 컨텍스트를 종료해도 관리되던 엔티티는 준영속 상태가 된다.
em.close();</code></pre>
<h2 id="영속성-컨텍스트의-이점">영속성 컨텍스트의 이점</h2>
<h3 id="1-1차-캐시">1. 1차 캐시</h3>
<p>영속성 내부에는 1차 캐시가 존재한다. 영속 상태의 엔티티를 이곳에 저장하기 때문에 만약 엔티티를 조회했을 때 1차 캐시에 엔티티가 존재한다면 DB를 찾아보지 않아도 된다. 말 그대로 캐시로써의 기능과 장점을 가지고 있다.</p>
<h3 id="2-영속-엔티티의-동일성-보장">2. 영속 엔티티의 동일성 보장</h3>
<pre><code class="language-javascript">Member a = em.find(Member.class, &quot;member1&quot;);
Member b = em.find(Member.class, &quot;member1&quot;);

System.out.println(a==b) // true</code></pre>
<p>1차 캐시로 반복 가능한 읽기(Repeatable Read) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공해 줄 수 있다.</p>
<h3 id="3-트랜잭션을-지원하는-쓰기-지연">3. 트랜잭션을 지원하는 쓰기 지연</h3>
<pre><code class="language-javascript">EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
// 엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작

em.persist(memberA);
em.persist(memberB);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

// 커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋</code></pre>
<p>em.persist()로 객체를 영속성 컨텍스트에 저장해도 DB에 바로 Insert 쿼리를 날리지 않는다.
SQL 쿼리들을 모아놓았다가 flush 될 때(영속성 컨텍스트의 변경 내용을 DB에 반영할 때) 모아둔 쿼리를 모두 날린다.
이를 쓰기 지연이라고 한다.</p>
<h3 id="4-변경-감지dirty-checking">4. 변경 감지(Dirty Checking)</h3>
<pre><code class="language-javascript">EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작

// 영속 엔티티 조회
Member memberA = em.find(Member.class, &quot;memberA&quot;);

// 영속 엔티티 데이터 수정
memberA.setUsername(&quot;hi&quot;);
memberA.setAge(10);

//em.update(member) 이런 코드가 있어야 하지 않을까?

transaction.commit(); // [트랜잭션] 커밋</code></pre>
<p>영속성 컨텍스트에서 엔티티를 조회해서 해당 엔티티를 수정한다고 하자.
이때 조회한 엔티티를 다시 업데이트하는 코드가 있어야 할 것 같지만, 그러한 코드가 없어도 영속성 컨텍스트 내의 스냅샷과 엔티티를 비교해 변경된 엔티티가 있으면 Update 쿼리를 자동으로 생성한다.</p>
<p>물론 이 Update 쿼리도 쓰기 지연이 될 수 있다.</p>
<h3 id="5-지연-로딩lazy-loading">5. 지연 로딩(Lazy Loading)</h3>
<p>지연 로딩은 연관 관계 매핑되어 있는 엔티티를 조회 시 우선 프록시 객체를 반환하고, 실제로 필요할 때 쿼리를 날려 가져오는 기능이다.</p>
<p>즉, 필요할 때 데이터를 가져오는 기능이다.</p>
<h2 id="플러시">플러시</h2>
<p>플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다. 영속성 컨텍스트의 엔티티를 지우는 게 아니라 변경 내용을 데이터베이스에 동기화하는 것이다.</p>
<p>플러시의 흐름</p>
<ol>
<li>변경 감지가 동작해서 스냅샷과 비교해서 수정된 엔티티를 찾는다.</li>
<li>수정된 엔티티에 대해서 수정 쿼리를 만들고 SQL 저장소에 등록한다.</li>
<li>쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송한다.</li>
</ol>
<h3 id="플러시-하는-방법">플러시 하는 방법</h3>
<ol>
<li>em.flush()</li>
<li>트랜잭션 커밋시 자동 호출</li>
<li>JPQL 쿼리 실행 시 자동 호출</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술 면접] JPA 즉시 로딩과 지연 로딩의 차이]]></title>
            <link>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%A6%89%EC%8B%9C-%EB%A1%9C%EB%94%A9%EA%B3%BC-%EC%A7%80%EC%97%B0-%EB%A1%9C%EB%94%A9%EC%9D%98-%EC%B0%A8</link>
            <guid>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%A6%89%EC%8B%9C-%EB%A1%9C%EB%94%A9%EA%B3%BC-%EC%A7%80%EC%97%B0-%EB%A1%9C%EB%94%A9%EC%9D%98-%EC%B0%A8</guid>
            <pubDate>Sun, 20 Aug 2023 11:34:14 GMT</pubDate>
            <description><![CDATA[<p>JPA에서는 데이터를 조회할 때 즉시 로딩(EAGER)과 지연 로딩(LAZY) 두 가지 방식이 있다. 이 두 가지 방식을 간단하게 설명하면 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고, 지연 로딩은 필요한 시점에 연관된 데이터를 불러오는 것이라고할 수 있다. </p>
<h2 id="fetch-type이란">Fetch Type이란</h2>
<p>FetchType이란, JPA가 하나의 Entity를 조회할 때, 연관관계에 있는 객체들을 어떻게 가져올 것이냐를 나타내는 설정값이다.</p>
<p>JPA는 ORM 기술로, 사용자가 직접 쿼리를 생성하지 않고, JPA에서 JPQL을 이용하여 쿼리문을 생성하기 때문에 객체와 필드를 보고 쿼리를 생성한다.
따라서, 다른 객체와 연관관계 매핑이 되어있으면 그 객체들까지 조회하게 되는데, 이때 이 객체를 어떻게 불러올 것인가를 설정할 수 있다.</p>
<p>fetch의 디폴트 값을 @xxToOne에서는 EAGER, @xxToMany에서는 LAZY이다.</p>
<h2 id="즉시로딩eager">즉시로딩(Eager)</h2>
<p>즉시로딩이란 데이터를 조회할 때, 연관된 모든 객체의 데이터까지 한 번에 불러오는 것이다.</p>
<ul>
<li>xxToxx(fetch = fetchType.EAGER)</li>
<li>다음과 같이 Member 엔티티와 Team 엔티티가 N:1 매핑으로 관계를 맺고 있다.</li>
</ul>
<pre><code class="language-javascript">@Entity
public class Member {

    @Id @GeneratedValue
    private Long id;
    private String username;

    @ManyToOne(fetch = FetchType.EAGER) //Team을 조회할 때 즉시로딩을 사용하곘다!
    @JoinColumn(name = &quot;team_id&quot;)
    Team team;
}

@Entity
public class Team {

    @Id @GeneratedValue
    private Long id;
    private String teamname;
}</code></pre>
<p>JPQL로 Member 1건 조회</p>
<pre><code class="language-javascript">Member findMember = em.createQuery(&quot;select m from Member m&quot;, Member.class).getSingleResult();</code></pre>
<p>실제 SQL 코드</p>
<pre><code class="language-sql">//멤버를 조회하는 쿼리
select
    member0_.id as id1_0_,
    member0_.team_id as team_id3_0_,
    member0_.username as username2_0_ 
from
    Member member0_

//팀을 조회하는 쿼리
select
    team0_.id as id1_3_0_,
    team0_.name as name2_3_0_ 
from
    Team team0_ 
where
    team0_.id=?</code></pre>
<p>다음과 같이 즉시 로딩(EAGER) 방식을 사용하면 Member 조회하는 시점에 바로 Team까지 불러오는 쿼리를 날려 한꺼번에 데이터를 불러오는 것을 볼 수 있다.</p>
<h2 id="지연로딩lazy">지연로딩(Lazy)</h2>
<p>지연로딩이란, 필요한 시점에 연관된 객체의 데이터를 불러오는 것이다.</p>
<ul>
<li>@xxToxx(fetch = fetchType.LAZY)</li>
<li>위의 예제에서 FetchType만 Lazy로 바꿔서 실행<pre><code class="language-javascript">@ManyToOne(fetch = FetchType.LAZY) //Team을 조회할 때 지연로딩을 사용하곘다!</code></pre>
JPQL로 Member 조회<pre><code class="language-javascript">Member findMember = em.createQuery(&quot;select m from Member m&quot;, Member.class).getSingleResult();
</code></pre>
</li>
</ul>
<pre><code>실제 SQL 코드
```sql
//Team을 조회하는 쿼리가 나가지 않음!
select
    member0_.id as id1_0_,
    member0_.team_id as team_id3_0_,
    member0_.username as username2_0_ 
from
    Member member0_</code></pre><p>지연 로딩을 사용하면 Member를 조회하는 시점이 아닌 실제 Team을 사용하는 시점에 쿼리가 나가도록 할 수 있다는 장점이 있다.</p>
<p>위 예제의 즉시 로딩에서는 member와 연관된 Team이 1개여서 Team을 조회하는 쿼리가 나갔지만, 만약 Member를 조회하는 JPQL을 날렸는데 연관된 Team이 1000개라면? Member를 조회하는 쿼리를 하나 날렸을 뿐인데 Team을 조회하는 SQL 쿼리 1000개가 추가로 나가게 된다.</p>
<p>그렇기 때문에 가급적이면 기본적으로 지연로딩을 사용하는 것이 좋다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술 면접] QueryDSL이란?]]></title>
            <link>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-QueryDSL%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-QueryDSL%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 20 Aug 2023 11:30:52 GMT</pubDate>
            <description><![CDATA[<h2 id="querydsl이란">QueryDSL이란?</h2>
<p>QueryDSL은 하이버네이트 쿼리 언어(HQL: Hibernate Query Language)의 쿼리를 타입에 안전하게 생성 및 관리해주는 프레임워크다.
QueryDSL은 정적 타입을 이용하여 SQL과 같은 쿼리를 생성할 수 있게 해준다.</p>
<p>자바 백엔드 기술은 Spring Boot와 Spring Data JPA를 함께 사용한다. 하지만 복잡한 쿼리, 동적 쿼리를 구현하는 데 있어 한계가 있다. 이러한 문제점을 해결할 수 있는 것이 QueryDSL이다.</p>
<p>QueryDSL이 등장하기 이전에는 Mybatis, JPQL, Criteria 등 문자열 형태로 쿼리문을 작성하여 컴파일 시에 오류를 발견하는 것이 불가능했다.
하지만 QueryDSL은 자바 코드로 SQL문을 작성할 수 있어 컴파일 시에 오류를 발생하여 잘못된 쿼리가 실행되는 것을 방지할 수 있다.</p>
<p>QueryDSL은 JPA 뿐만 아니라 SQL, MongoDB, Lucenece 등다양한 언어에 대해서 서비스를 제공한다.</p>
<h2 id="jpql과-querydsl-비교">JPQL과 QueryDSL 비교</h2>
<h3 id="jpql">JPQL</h3>
<pre><code class="language-javascript">String username = &quot;java&quot;;
String jpql = &quot;select m from Member m where m.username = :username&quot;;

List&lt;Member&gt; result = em.createQuery(query, Member.class).getResultList();</code></pre>
<h3 id="querydsl">QueryDSL</h3>
<pre><code class="language-javascript">String username = &quot;java&quot;;

List&lt;Member&gt; result = queryFactory
        .select(member)
        .from(member)
        .where(usernameEq(username))
        .fetch();</code></pre>
<h2 id="querydsl-장점">QueryDSL 장점</h2>
<ul>
<li>문자가 아닌 코드로 쿼리를 작성할 수 있어 컴파일 시점에 문법 오류를 확인할 수 있다.</li>
<li>인텔리제이와 같은 IDE의 자동 완성 기능의 도움을 받을 수 있다.</li>
<li>복잡한 쿼리나 동적 쿼리 작성이 편리하다.</li>
<li>쿼리 작성 시 제약 조건 등을 메서드 추출을 통해 재사용할 수 있다.</li>
<li>JPQL 문법과 유사한 형태로 작성할 수 있어 쉽게 적응할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[기술 면접] ArrayList와 LinkedList의 차이 ]]></title>
            <link>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-ArrayList%EC%99%80-LinkedList%EC%9D%98-%EC%B0%A8</link>
            <guid>https://velog.io/@jinyeong-afk/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-ArrayList%EC%99%80-LinkedList%EC%9D%98-%EC%B0%A8</guid>
            <pubDate>Sun, 20 Aug 2023 11:27:14 GMT</pubDate>
            <description><![CDATA[<h2 id="arraylist-vs-linkedlist">ArrayList vs LinkedList</h2>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/477612b0-b028-4fbd-8804-6f8d315a002a/image.png" alt="">
위 사진을 보면 알 수 있듯 ArrayList는 index가 있고, LinkedList는 각 원소마다 앞,뒤 원소의 위치를 가지고 있다.</p>
<p>이러한 각각의 특징은 조회, 삽입, 삭제 시에 성능의 차이를 발생시킨다.
<img src="https://velog.velcdn.com/images/jinyeong-afk/post/868f5c0e-2ff6-4bda-86a3-f33336aa4b94/image.png" alt=""></p>
<h2 id="arraylist">ArrayList</h2>
<p>ArrayList는 기본적으로 배열을 사용한다. 하지만 배열과 차이점이 존재한다.
일반 배열은 처음에 메모리를 할당할 때 크기를 지정해주어야 하지만, ArrayList는 크기를 지정하지 않고, 동적으로 값을 삽입하고 삭제할 수 있다.</p>
<h3 id="조회">조회</h3>
<p>ArrayList는 각 데이터의 index를 가지고 있고 무작위 접근이 가능하기 때문에 해당 index의 데이터를 한번에 가져올 수 있다.</p>
<h3 id="데이터-삽입과-삭제">데이터 삽입과 삭제</h3>
<p>데이터의 삽입과 삭제시 ArrayList는 그만큼 위치를 맞춰주어야 한다.
예를 들어 5개의 데이터가 있을 때 맨 앞의 2를 삭제했다면 나머지 뒤의 4개를 앞으로 한 칸씩 이동해야 한다.
삽입과 삭제가 많다면 ArrayList는 비효율적이다.</p>
<h2 id="linkedlist">LinkedList</h2>
<p>LinkedList는 내부적으로 양방향의 연결 리스트로 구성되어 있어 참조하려는 원소에 따라 처음부터 정방향 또는 역순으로 순회 가능 (배열의 단점을 보완하기 위해 LinkedList가 고안되었다.)</p>
<h3 id="조회-1">조회</h3>
<p>LinkedList는 순차적 접근이기 때문에 검색의 속도가 느리다.</p>
<h3 id="데이터-삽입과-삭제-1">데이터 삽입과 삭제</h3>
<p>LinkedList는 데이터를 추가-삭제 시 가리키고 있는 주소값만 수정해주면 도기ㅣ 때문에 ArrayList에 비해 상당히 효율적이다.
예를 들어 두 번째 값을 삭제하면 첫 번째 노드가 세 번째 노드를 가리키게 하기만 하면 된다.</p>
<p><img src="https://velog.velcdn.com/images/jinyeong-afk/post/04340eb4-e6f7-4989-9f34-643f8dd6529a/image.png" alt=""></p>
<p>이처럼 조회 시에는 ArrayList가 우위에 있지만, 삽입 / 삭제 시에는 LinkedList가 뛰어난 성능을 보여준다.</p>
<p>소량의 데이터를 가지고 사용할 때는 사실 큰 차이가 없지만, 정적인 데이터를 활용하면서 조회가 빈번하다면 ArrayList를 사용하는 것이 좋고, 동적으로 추가 / 삭제 요구사항이 빈번하다면 LinkedList를 사용하는 것이 좋다.</p>
<h2 id="arraylist와-linkedlist의-성능-차이-비교">ArrayList와 LinkedList의 성능 차이 비교</h2>
<pre><code class="language-c">package study.dataStructure;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ArrayListLinkedListTest {
    public static void main(String[] args) {
        ArrayList ary = new ArrayList(2000000);
        LinkedList lkd = new LinkedList();

        System.out.println(&quot;======순차적으로 추가하기======&quot;);
        System.out.println(&quot;ArrayList = &quot; + addF(ary));
        System.out.println(&quot;LinkedList = &quot; + addF(lkd));

        System.out.println(&quot;\n======중간에 추가하기======&quot;);
        System.out.println(&quot;ArrayList = &quot; + addM(ary));
        System.out.println(&quot;LinkedList = &quot; + addM(lkd));

        System.out.println(&quot;\n======중간에 삭제하기======&quot;);
        System.out.println(&quot;ArrayList = &quot; + removeM(ary));
        System.out.println(&quot;LinkedList = &quot; + removeM(lkd));

        System.out.println(&quot;\n======순차적으로 삭제하기======&quot;);
        System.out.println(&quot;ArrayList = &quot; + removeF(ary));
        System.out.println(&quot;LinkedList = &quot; + removeF(lkd));

    }

    public static long addF(List list) {
        long start = System.currentTimeMillis();
        for(int i = 0; i &lt; 1000000; i++) {
            list.add(i+&quot;&quot;);
        }
        long end = System.currentTimeMillis();
        return end - start;
    }

    public static long addM(List list) {
        long start = System.currentTimeMillis();
        for(int i = 0; i &lt; 10000; i++) {
            list.add(500,&quot;X&quot;);
        }
        long end = System.currentTimeMillis();
        return end - start;
    }

    public static long removeF(List list) {
        long start = System.currentTimeMillis();
        for(int i = list.size() - 1; i &gt;= 0; i--) {
            list.remove(i);
        }
        long end = System.currentTimeMillis();
        return end - start;
    }

    public static long removeM(List list) {
        long start = System.currentTimeMillis();
        for(int i = 0; i &lt; 10000; i++) {
            list.remove(i);
        }
        long end = System.currentTimeMillis();
        return end - start;
    }
}</code></pre>
<h3 id="실행-결과">실행 결과</h3>
<pre><code class="language-c">======순차적으로 추가하기======
ArrayList = 92
LinkedList = 145

======중간에 추가하기======
ArrayList = 3142
LinkedList = 11

======중간에 삭제하기======
ArrayList = 1746
LinkedList = 116

======순차적으로 삭제하기======
ArrayList = 8
LinkedList = 19

Process finished with exit code 0</code></pre>
<h2 id="결론">결론</h2>
<h3 id="1-순차적으로-추가--삭제하는-경우-arraylist가-linkedlist보다-빠르다">1. 순차적으로 추가 / 삭제하는 경우 ArrayList가 LinkedList보다 빠르다.</h3>
<p>큰 차이는 없지만, 처음 또는 마지막 데이터부터 순차적으로 데이터를 쭉 삭제하면 각 요소들의 재배치가 필요하지 않기 때문에 ArrayList도 빠르다.</p>
<h3 id="2-중간-데이터비-순차적를-추가--삭제하는-경우-linkedlist가-arraylist보다-빠르다">2. 중간 데이터(비 순차적)를 추가 / 삭제하는 경우 LinkedList가 ArrayList보다 빠르다.</h3>
<p>중간 요소를 추가 또는 삭제하는 경우, LinkedList는 각 노드간 연결만 변경해주면 되기 때문에 처리 속도가 빠르다.
반면에 ArrayList는 각 요소들을 재배치하여 추가할 공간을 확보하거나 빈 공간을 채워야 하기 때문에 처리속도가 늦다.</p>
]]></description>
        </item>
    </channel>
</rss>