<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>하람✨</title>
        <link>https://velog.io/</link>
        <description>사회에 이로운 IT 기술에 대해 고민하고 모두가 소외되지 않는 서비스를 운영하는  개발자를 꿈꾸고 있습니다 ✨</description>
        <lastBuildDate>Fri, 01 Nov 2024 12:08:34 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>하람✨</title>
            <url>https://velog.velcdn.com/images/ramrami-12/profile/6c61b509-37ca-4d48-a7f8-49cd1e710a3f/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 하람✨. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ramrami-12" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[프로그래머스] 야근 지수]]></title>
            <link>https://velog.io/@ramrami-12/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%95%BC%EA%B7%BC-%EC%A7%80%EC%88%98</link>
            <guid>https://velog.io/@ramrami-12/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%95%BC%EA%B7%BC-%EC%A7%80%EC%88%98</guid>
            <pubDate>Fri, 01 Nov 2024 12:08:34 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-링크"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12927?language=python3">문제 링크</a></h3>
<h3 id="풀이-과정">풀이 과정</h3>
<p>처음에는 dfs로 풀었는데 테케만 맞고 제출을 눌렀더니 시간 초과가 났다.</p>
<pre><code class="language-python">answer = 999999999

def dfs(n, works):
    global answer 

    if n == 0:
        temp = 0
        for work in works: 
            temp += work ** 2
        answer = min(temp, answer)
        return 

    flag = True
    for work in works:
        if work &gt; 0:
            flag = False

    if n &gt; 0 and flag:
        temp = 0
        for work in works: 
            temp += work ** 2
        answer = min(temp, answer)

    for i in range(len(works)):
        if works[i] == 0:
            continue
        works[i] -= 1
        dfs(n - 1, works)
        works[i] += 1

def solution(n, works):
    global answer

    dfs(n, works)

    return answer</code></pre>
<p>다음에는 n번 정렬 하면서 가장 큰 값을 1씩 줄이는 방식으로 풀었는데 정답은 다 맞고 효율성에서 틀렸다고 나왔다.</p>
<pre><code class="language-python">def solution(n, works):
    answer = 0

    for i in range(n):
        works.sort(reverse=True)
        works[0] -= 1

    for work in works:
        if work &lt; 0:
            continue
        answer += work ** 2

    return answer</code></pre>
<p>마지막으로 우선순위큐 알고리즘으로 풀어서 맞았다!✨</p>
<pre><code class="language-python">import heapq

def solution(n, works):
    if sum(works) &lt;= n:
        return 0

    works = [-w for w in works]
    heapq.heapify(works)

    for i in range(n):
        ele = heapq.heappop(works)
        ele += 1
        heapq.heappush(works, ele)

    return sum([w ** 2 for w in works])</code></pre>
<h3 id="교훈--알게-된-것">교훈 &amp; 알게 된 것</h3>
<ul>
<li>무작정 풀기 보다 시간복잡도 생각하면서 풀기 -&gt; 매번 얻는 교훈이지만 빨리 풀어야 한다는 생각에 냅다 dfs, 완전 탐색을 돌리게 된다..</li>
<li>python에서는 heapq 라이브러리로 우선순위 큐를 쉽게 사용 할 수 있다. 라이브러리는 최소 힙으로 구현 되어 있지만 요소를 -로 변환 시켜서 최대 힙으로도 사용 할 수 있다.
예를 들어 <code>[7, 2, 5, 8, 6]</code> 배열이 있을 때 -를 붙여서 heapq 라이브러리를 사용하면 <code>[-8, -7, -6, -5, -2]</code>가 되고, heapq.pop()을 하면 -8이 나오므로 그때 -를 없애면 최대 힙처럼 사용할 수 있다!</li>
<li><a href="https://docs.python.org/ko/3/library/heapq.html#heapq.heappush">heapq 라이브러리</a> 사용법
<code>import heapq</code><ul>
<li>주요 함수<ul>
<li><code>heapq.heapify(list)</code>: <code>list</code>를 힙으로 만들어준다.</li>
<li><code>heapq.heappush(heap, ele)</code>: 힙을 유지하면서 <code>ele</code> 추가</li>
<li><code>heapq.heappop(heap)</code>: 힙을 유지하면서 가장 작은 요소를 반환</li>
<li><code>heapq.heappushpop(heap, ele)</code>: 힙을 유지하면서 <code>ele</code>를 추가하고 가장 작은 요소를 반환</li>
<li><code>heapq.heapreplace(heap, ele)</code>: 힙을 유지하면서 가장 작은 요소를 반환하고 <code>ele</code> 추가, 만약 비어있는 힙이라면 <code>IndexError</code> 발생</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js] <Image /> 에러(경고) 해결]]></title>
            <link>https://velog.io/@ramrami-12/Next.js-Image-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@ramrami-12/Next.js-Image-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Tue, 29 Oct 2024 01:09:47 GMT</pubDate>
            <description><![CDATA[<p>Next.js로 개발하면서 자주 마주친 에러(경고) 해결에 대해 기록해두려고 한다😅</p>
<h3 id="⚠︎-에러경고-메세지">⚠︎ 에러(경고) 메세지</h3>
<p>Image with src <del>~</del> was detected as the Largest Contentful Paint (LCP). Please add the &quot;priority&quot; property if this image is above the fold.</p>
<h3 id="💡-해결">💡 해결</h3>
<p>priority 속성을 추가하면 된다.</p>
<pre><code>&lt;Image src=&quot;/~~~&quot; alt=&quot;~~~&quot; width=&quot;150&quot; height=&quot;150&quot; /&gt;</code></pre><p>➡</p>
<pre><code>&lt;Image src=&quot;/~~~&quot; alt=&quot;~~~&quot; width=&quot;150&quot; height=&quot;150&quot; priority /&gt;</code></pre><h3 id="⚠︎-에러-메세지">⚠︎ 에러 메세지</h3>
<p>Image with src has either width or height modified, but not the other. If you use CSS to change the size of your image, also include the styles &#39;width: &quot;auto&quot;&#39; or &#39;height: &quot;auto&quot;&#39; to maintain the aspect ratio.</p>
<h3 id="💡-해결-1">💡 해결</h3>
<p>style 속성을 추가해서 사이즈 변동이 있는 부분(width 또는 height)에 auto를 주면 된다.</p>
<pre><code>&lt;Image src=&quot;/~~~&quot; alt=&quot;~~~&quot; width=&quot;150&quot; height=&quot;150&quot; style={{ height: &quot;auto&quot; }} /&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[따끈 따끈한 싸피(SSAFY) 11기 합격 후기🥳]]></title>
            <link>https://velog.io/@ramrami-12/%EB%94%B0%EB%81%88-%EB%94%B0%EB%81%88%ED%95%9C-%EC%8B%B8%ED%94%BCSSAFY-11%EA%B8%B0-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/%EB%94%B0%EB%81%88-%EB%94%B0%EB%81%88%ED%95%9C-%EC%8B%B8%ED%94%BCSSAFY-11%EA%B8%B0-%ED%95%A9%EA%B2%A9-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 29 Jan 2024 03:03:14 GMT</pubDate>
            <description><![CDATA[<p>티스토리에 포스팅 했어요🥰
<a href="https://sh-tg.tistory.com/1">https://sh-tg.tistory.com/1</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023 리눅스 마스터 2급 1차 시험 합격]]></title>
            <link>https://velog.io/@ramrami-12/2023-%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%A7%88%EC%8A%A4%ED%84%B0-2%EA%B8%89-1%EC%B0%A8-%EC%8B%9C%ED%97%98-%ED%95%A9%EA%B2%A9-feat.-%EC%A1%B1%EB%B3%B4</link>
            <guid>https://velog.io/@ramrami-12/2023-%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%A7%88%EC%8A%A4%ED%84%B0-2%EA%B8%89-1%EC%B0%A8-%EC%8B%9C%ED%97%98-%ED%95%A9%EA%B2%A9-feat.-%EC%A1%B1%EB%B3%B4</guid>
            <pubDate>Thu, 09 Nov 2023 15:23:37 GMT</pubDate>
            <description><![CDATA[<p>정보처리기사 말고 다른 자격증을 더 따고 싶어서 알아봤더니
리눅스 마스터, 네트워크 관리사, AWS 자격증 등이 있었다.
네트워크 관리사는 올해 접수할 수 있는 시험 일정이 없었고, AWS는 공부가 좀 필요할 것 같아서(비용도 비싸다.) 
비교적 쉽고 지금 당장 할 수 있는 리눅스 마스터 2급을 따기로 했다.</p>
<hr>
<p>몇 번 구글링 해보니 2급은 1차는 족보, 2차는 기출+족보로 쉽게 합격할 수 있는듯 했다.</p>
<h3 id="시험-안내">시험 안내</h3>
<p>먼저, <a href="https://www.ihd.or.kr/memaccept1.do">시험 접수</a>는 KAIT 자격검정 사이트에서 가능하다.
아쉽게도 올해는 1급과 2급 모두 접수가 마감 되었다.</p>
<p>2급 1차 시험의 경우 온라인 CBT 시험이기 때문에 언제 어디서나 칠 수 있다.
그러나 인터넷이 잘 되어 있어야 하고 60분 동안 시험을 칠 수 있기 때문에 방해받지 않는 곳에서 시험을 치는 것이 좋다.</p>
<h3 id="시험-후기">시험 후기</h3>
<p>홈페이지 메인 화면에서 &#39;온라인 시험 보기&#39;를 클릭하면 아래와 같은 창이 떠서 시험을 시작할 수 있다.
<img src="https://velog.velcdn.com/images/ramrami-12/post/5e6ce8a7-abe0-4d1c-a967-9b391525c176/image.png" alt="">
크롬의 경우 팝업 차단을 꼭 해제 해 주어야 한다.
나만 그런지 모르겠지만 <strong>수험 번호와 이름을 제대로 작성하고 로그인을 했는데 시험 시작이 되지 않아서 당황</strong>스러웠다.
크롬을 모두 껐다가(cmd+q로) 다시 키니까 시험이 잘 시작 되어서 다행이었다.
만약 나처럼 시험이 제대로 시작 되지 않거나 창이 제대로 뜨지 않는 경우, <strong>팝업 차단을 해제 했는지 확인해 보고 크롬(이나 기타 브라우저) 또는 컴퓨터를 재부팅</strong> 해보길 바란다.</p>
<p>시험이 시작되고 나서도 <strong>모든 문제가 1번 문제와 동일하게 나오는 오류</strong>가 있었다.
새로 고침도 할 수 없어서 곤란했는데, 모니터 연결 때문에 인터넷이 잘 안돼서 시험 문제가 제대로 다운 받아지지 않았던 모양이었다.
다양한 이유로 <strong>인터넷 연결이 원활하지 않을 경우</strong>, 문제가 발생할 수 있을 것 같다. <strong>꼭 확인하길!!</strong>
모니터로 족보를 띄워놓고 시험을 치려고 했는데 결국 모니터 연결을 해제하고, 창을 왔다 갔다 하면서 시험을 치게 되었다.</p>
<p>위의 문제 때문에 시험 시간을 10분 정도 낭비했는데도 <strong>문제가 거의 족보에 나와 있고, 인터넷 검색이 허용되어서 쉽게 합격</strong>할 수 있었다.
혹시 몰라서 모니터 또는 별도의 컴퓨터(태블릿)를 사용하는 사람도 있는 것 같은데 한 컴퓨터에서 창을 여러 개 띄워놓고 왔다 갔다 하는 것도 가능하다!</p>
<p>족보의 경우 내가 찾은 것 중 가장 최신이 2021년도 족보였는데 문제를 풀기엔 충분했다.
또한, 족보에 없는 내용은 인터넷에 찾아보면 나온다.
ChatGPT는 정확도가 떨어지므로 찾아보지 말자 (...)</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/50e14d09-9da8-46e1-8587-cc5024a35bd0/image.png" alt=""></p>
<h3 id="결론">결론</h3>
<p>결과는 합격!!
5개는 어디서 틀렸는지 모르겠다. 아마 구글링을 잘 못 하지 않았을까..
<img src="https://velog.velcdn.com/images/ramrami-12/post/22931fd8-8b4a-4d4d-89ac-c17a90531675/image.png" alt=""></p>
<p>2차 시험은 내일(11/10)까지 접수할 수 있고 서울, 부산, 대구, 광주, 대전, 인천, 수원, 제주(8개시)에서 시험을 칠 수 있다.
공부는 족보와 기출이면 충분하다고 하지만 혹시 몰라서 <a href="https://product.kyobobook.co.kr/detail/S000200456451">책을 살 예정</a>이다.
2차 시험도 합격 후기로 돌아오겠습니다!</p>
<p><a href="https://www.ihd.or.kr/introducesubject1.do">리눅스 마스터 시험 정보</a></p>
<p>그럼 안녕 👋</p>
<h3 id="240509-수정">24/05/09 수정</h3>
<p>지금까지 댓글 달아주신 분들께는 모두 메일 드렸습니다!
확인 후 파일이 열리지 않거나 이상이 있다면 연락 주세요 :)
*댓글을 늦게 확인해서 놀랐는데 다행히 시험이 오늘까지네요! 댓글 확인이 늦을 수도 있다는 점 미리 말씀 드립니다 ㅠㅠ</p>
<h3 id="241030-수정">24/10/30 수정</h3>
<p>기존에는 이메일로 족보를 요청하면 보내드렸는데 
저도 현생이 바빠 메일 확인을 잘 못하다 보니 족보를 드리는 시간이 늦어지기도 했고,
구글링으로 쉽게 찾을 수 있는 자료라서 공유를 그만하기로 했습니다😥
인터넷 검색이 허용되므로 1차는 정말 쉽게 합격이 가능하답니다!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js] 오늘의 에러 일지✍🏻]]></title>
            <link>https://velog.io/@ramrami-12/Next.js-%EC%98%A4%EB%8A%98%EC%9D%98-%EC%97%90%EB%9F%AC-%EC%9D%BC%EC%A7%80</link>
            <guid>https://velog.io/@ramrami-12/Next.js-%EC%98%A4%EB%8A%98%EC%9D%98-%EC%97%90%EB%9F%AC-%EC%9D%BC%EC%A7%80</guid>
            <pubDate>Wed, 01 Nov 2023 05:43:44 GMT</pubDate>
            <description><![CDATA[<h3 id="날마다-새로운-에러-세상🌍🎶">날마다 새로운 에러 세상🌍🎶</h3>
<h4 id="1-로컬-파일명과-원격-저장소-파일명이-달라서-발생하는-오류">1. 로컬 파일명과 원격 저장소 파일명이 달라서 발생하는 오류</h4>
<p>Next로 개발한 프로젝트를 Vercel로 배포하려고 하는데 오류가 발생했다.
매우 익숙한 <code>Module not found: Can&#39;t resolve ~</code> 에러가 떴는데 눈을 씻고 찾아봐도 파일명이나 변수명 등등 올바르게 잘 적혀 있었다.
<strong>구글링을 해보니 로컬에서 변경된 파일 이름이 원격저장소(GitHub)에서 변경되지 않아서 에러가 떴을 수도 있다고 한다.</strong>
그래서 GitHub을 확인해보니까 로컬에서는 대문자로 시작하는 파일 이름이 원격에서는 소문자로 시작하는걸 확인할 수 있었다. (ㅠㅠ)</p>
<h4 id="해결-방법">해결 방법</h4>
<ol>
<li>원격 저장소의 프로젝트 clone 하기 (옵션: branch 바꾸기)</li>
<li><code>git config core.ignorecase false</code> 명령어 입력해서 대소문자 무시하지 말라고 명령해주기</li>
<li>원하는대로 파일명 변경</li>
<li>add, commit 후 push~</li>
</ol>
<p>*캐싱 된 내용을 삭제 하기 위해선 아래와 같이 한다.</p>
<pre><code>git rm -r --cached .

git add .

git commit -m &quot;Remove: 캐시 삭제&quot;</code></pre><h4 id="2-error-eperm-operation-not-permitted">2. Error: EPERM: operation not permitted</h4>
<p>수정된 내용을 GitHub에 올리기 전에 실행이 잘 되는지 확인해 보려고 실행 했는데 이런 오류가 떴다.
구글링 해보니 npm 캐시를 삭제하고 (강제로) npm install(강제로) 하면 된다는데 캐시 삭제 명령어도 먹히지 않았다.</p>
<h4 id="해결-방법-1">해결 방법</h4>
<p>프로젝트 편집기(ex.VSCODE)를 껐다가 다시 들어오거나 사용하던 터미널을 껐다가 다시 키면 해결,,
새로 킨 터미널에서는 <code>npm cache clean --force</code>가 잘 먹혔다 ^^;
<code>npm install -g npm@latest --force</code> 해 준 다음, 실행하면 해결!</p>
<h4 id="3-window-is-not-defined--document-is-not-defined">3. window is not defined / document is not defined</h4>
<p>배포하기 위해 빌드 할 때 뜬 에러인데, 처음 &#39;/&#39;로 페이지에 들어갈 때 쿠키에 토큰이 있는지 없는지 검사한 뒤 있으면 로그인 된 상태라고 파악하고 없으면 로그인 화면으로 리다이렉트 하기 위해 구현한 코드에서 에러가 발생했다.</p>
<p>ex) 오류가 났던 코드 예시</p>
<pre><code class="language-typescript">export function getCookie(name:string) {
  let value;

  value = document.cookie.match(&quot;(^|;) ?&quot; + name + &quot;=([^;]*)(;|$)&quot;);

  return value ? value[2] : null;
}</code></pre>
<h4 id="해결-방법-2">해결 방법)</h4>
<p>Next.js는 SSR을 하기 때문에 렌더링 하기 전에 window나 document 객체에 접근할 수 없다. 아래와 같은 방법으로 해결할 수 있다 :)</p>
<ol>
<li><p>useEffect를 사용해서 브라우저가 다 그려진 뒤에 window, document를 접근한다.</p>
</li>
<li><p><code>if (typeof document !== &quot;undefined&quot;)</code> 구문을 통해 window나 document 객체의 타입이 undefined가 아닐 때(렌더링 된 후에)만 접근한다.</p>
</li>
</ol>
<blockquote>
<p>References
<a href="https://papababo.tistory.com/entry/git-%EC%9D%80-%ED%8F%B4%EB%8D%94%ED%8C%8C%EC%9D%BC%EB%AA%85%EC%9D%98-%EB%8C%80%EC%86%8C%EB%AC%B8%EC%9E%90%EB%A5%BC-%EA%B0%9C%EB%AC%B4%EC%8B%9C%ED%95%9C%EB%8B%A4-%EA%B7%B8%EB%9F%BC-%EC%9A%B0%EC%A7%B8">1번 문제</a>
<a href="https://stackoverflow.com/questions/39293636/npm-err-error-eperm-operation-not-permitted-rename">2번 문제</a>
<a href="https://handhand.tistory.com/272">3번 문제</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[코딩테스트용 자바(Java)]]></title>
            <link>https://velog.io/@ramrami-12/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%9A%A9-%EC%9E%90%EB%B0%94Java</link>
            <guid>https://velog.io/@ramrami-12/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%9A%A9-%EC%9E%90%EB%B0%94Java</guid>
            <pubDate>Fri, 15 Sep 2023 16:09:49 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>원래 코테는 python으로 준비하다가 프론트엔드로 (거의) 진로를 정하게 되면서 javascript로 하려고 했는데..! 띠용 갑자기 내일 당장 자바로 코테를 치게 되었다.
이 포스팅이 나에게 또 이 글을 보는 사람들에게 도움이 되기를..</p>
</blockquote>
<h1 id="📌-0">📌 0.</h1>
<h2 id="라이브러리">라이브러리</h2>
<pre><code class="language-java">import java.util.*;        // collection, map, list, queue 등
import java.io.*;        //file, console, buffer 등</code></pre>
<h2 id="length--length--size">length / length() / size()</h2>
<pre><code class="language-java">// 배열
int[] arr = new arr[3];
System.out.println(arr.length);        //3

// String
String str = &quot;Java&quot;;
System.out.println(str.length());    //4

// Collections 객체들
ArrayList&lt;String&gt; list = new ArrayList&lt;&gt;();
System.out.println(list.size());</code></pre>
<h1 id="📌-string-관련-메서드">📌 String 관련 메서드</h1>
<pre><code class="language-java">// 선언
String str = &quot;apple&quot;;

// 길이 반환
str.length();    //5

// 빈 배열 체크
str.isEmpty();

// 문자 찾기
str.charAt(0);    // &#39;a&#39;
str.indexOf(&quot;a&quot;);    //0
str.lastIndexOf(&quot;p&quot;);    //2
// 반복문을 사용해서 요소에 접근할 수 있다.
for(int i=0; i &lt; str.length; i++) str.charAt(i);

// 문자 자르기
str.substring(1, 3);    //&#39;pp&#39;
str.substring(3);    //&#39;app&#39;

// 문자 치환
str.replace(&#39;p&#39;, &#39;b&#39;);    //&#39;abble&#39;
str.replaceAll(&#39;.&#39;, &#39;*&#39;);    // &#39;*****&#39; //정규식에 맞게 문자 치환
str.replaceFirst(&#39;p&#39;, &#39;b&#39;);        //&#39;abple&#39;

// 문자열 동일 여부 판단
// String &lt;변수명&gt; = &quot;&quot;; 로 선언했을 때, 클래스로써 주소값이 부여된다. 그러므로 값이 같더라도 주소값이 다를 수 있기 때문에 값이 같은지 확인할 때는 .equals를 사용한다.
str.equals(&quot;apple&quot;);

// 문자 비교
// 문자와 비교 대상이 같으면 0
// 비교 대상이 문자에 포함되면 두 문자 길이 차이 반환
// 첫 인덱스부터 비교하되 다른 값을 만나면 아스키코드 값 차이 반환
// int형도 비교 가능
str.compareTo(&quot;applf&quot;);        //0
str.compareTo(&quot;ap&quot;);    // 3 

// 문자 포함 여부
str.contains(&quot;ap&quot;);

// 문자열 분리
str.spilt(&quot;&quot;);    // 구분자는 있을수도 없을수도 있음. 구분자가 없을시 한글자씩 분리하여 String[]로 반환

str.trim();        // 문자 앞뒤 공백 제거

Integer.parseInt(&quot;100&quot;);    //100
Integer.toString(100);        //&#39;100&#39;

// 대소문자 변경
str = str.toUpperCase();    //str: APPLE
str = str.toLowerCase();    // str: apple

// 한번 선언한 String 객체 값은 변경 불가, substring으로 변경할 수 있음
String newStr = str.substring(3) + &quot;lication&quot;;        //application</code></pre>
<p>참고
<a href="https://learn.microsoft.com/ko-kr/dotnet/api/system.string.compareto?view=net-7.0">String.CompareTo 메서드</a></p>
<h1 id="📌-list-관련-메서드">📌 List 관련 메서드</h1>
<pre><code class="language-java">// 선언
List&lt;string&gt; list = new ArrayList&lt;&gt;();
List&lt;string&gt; list2 = new ArrayList&lt;&gt;();

list.add(&quot;one&quot;);    //list: &quot;one&quot;
list.add(0, &quot;zero&quot;);    //list: &quot;zero&quot;, &quot;one&quot;

// 추가되는 리스트가 뒤에 추가됨
list.addAll(list2);

list.indexOf(&quot;zero&quot;);    //0

// 특정 요소의 마지막 인덱스 반환
list.lastIndexOf(&quot;zero&quot;);

// 괄호 안에 인덱스가 들어가면 특정 인덱스의 값 삭제, 값이 들어가면 첫번째 값 삭제
list.remove(0);
list.remove(&quot;one&quot;);

// 리스트 초기화
list.clear();

// 리스트 비어있는지 확인
list.isEmpty();

// 리스트 길이
list.size();

// 리스트 특정 요소 포함 여부
list.contains(&quot;one&quot;);

// 다른 리스트의 요소 전부의 포함 여부
list.containsAll(list2);    // 모두 포함되어 있으면 true

// 람다식 사용하여 리스트에서 요소 제거
// 예시는 리스트에서 짝수인 수 모두 제거
list.removeIf(x -&gt; x % 2 == 0);    </code></pre>
<h1 id="📌-array-관련-메서드">📌 Array 관련 메서드</h1>
<pre><code class="language-java">// 선언
int arr = [0, 1, 2, 3, 4, 5];
String[] strArr = [&quot;zero&quot;, &quot;one&quot;, &quot;two&quot;];

// 오름차순 정렬
Arrays.sort(arr);
// 내림차순 정렬
Arrays.sort(arr, Collections.reverseOrder());
// 일부 구간 정렬
Arrays.sort(arr, 0, 4);        //0-3번째 인덱스 정렬

// 오름차순 정렬 후 값 찾기
Arrays.binarySearch(arr, 2);

// 배열 자르기
int temp[] = Arrays.copyOfRange(arr, 0, 3);</code></pre>
<h2 id="array와-list는-다르다">Array와 List는 다르다.</h2>
<ul>
<li>Array, List 모두 선형 자료구조이고, 인덱스를 가지고 있어 값을 참조할 수 있다.</li>
<li>그러나 Array는 크기가 고정되어 있으며 메모리 상에 데이터가 연속적으로 존재한다. 검색에는 O(1)의 시간 복잡도를 갖기만 삽입 및 삭제에는 O(N)의 시간 복잡도를 가진다. </li>
<li>List는 메모리를 유동적으로 할당한다. (메모리에 빈 공간을 허용하지 않는다.) 그러므로 검색, 삽입, 삭제 모두 O(N)의 시간 복잡도를 가진다. ➡️ add, remove 등 자체 메서드를 가지고 있다.</li>
<li>두 가지의 특징을 골고루 가지고 있는 ArrayList도 있다
<del>비슷한 선형 자료구조로 LinkedList도 있긴 함 =&gt; 큐에서 사용</del></li>
</ul>
<pre><code class="language-java">// 문자열 array를 list로 변환
String[] temp = {&quot;one&quot;, &quot;two&quot;, &quot;three&quot;};
List&lt;String&gt; list = new ArrayList&lt;&gt;(Arrays.asList(temp));

// list를 문자열 array로 변환
List&lt;String&gt; list = new ArrayList&lt;&gt;();
String[] temp = list.toArray(new String[list.size()]);

// Integer 등 다른 타입도 그대로 사용 가능

// 하지만 이런 식으로 선언하면 변경할 수 없다.
List&lt;String&gt; list = Array.asList(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;);</code></pre>
<h1 id="📌-arraylist-관련-메서드">📌 ArrayList 관련 메서드</h1>
<ul>
<li><code>import java.util.ArrayList</code></li>
<li>삽입, 삭제, 참조(순회)에 편리하다!<pre><code class="language-java">// 선언
ArrayList&lt;String&gt; list = new ArrayList&lt;&gt;();
</code></pre>
</li>
</ul>
<p>// 삽입
list.add(&quot;b&quot;);        //{&quot;b&quot;}
list.add(0, &quot;a&quot;);        //{&quot;a&quot;, &quot;b&quot;}</p>
<p>// 수정
list.set(1, &quot;c&quot;);        //{&quot;a&quot;, &quot;c&quot;}</p>
<p>// 삭제
list.remove(1);        //{&quot;a&quot;}</p>
<p>list.contains(&quot;b&quot;);        //false
list.indexOf(&quot;a&quot;);        //0</p>
<p>// iterator 사용
Iterator it = list.iterator();</p>
<p>while(it.hasNext()) { ... }</p>
<p>while(it.hasPrevious()) { ... }</p>
<p>// 중복 없이 값 넣기
if(list.indexOf(value) &lt; 0} {
    list.add(value)        //중복이 있을 경우 값을 넣지 않음
}</p>
<p>// 값 하나씩 가져오기
for(int i=0; i&lt;list.size; i++) {
    list.get(i).intValue();
}</p>
<pre><code>
# 📌 HashMap 관련 메서드
```java
// 선언
HashMap&lt;String, Integer&gt; hashMap = new HashMap&lt;&gt;();

// key-value 넣기
hashMap.put(&quot;zero&quot;, 0);

// 해당 키 값 삭제
hashMap.remove(&quot;zero&quot;);

// 초기화
hashMap.clear();

// key로 값 가져오기
hashMap.get(0);

// key값 존재 유무
if(!hashMap.containsKey(&quot;one&quot;)) hashMap.put(&quot;one&quot;, 1);

// value 존재 유무
hashMap.containsValue();

// 키가 없으면 값 세팅, 있으면 기존 값 가져오기
hashMap.put(&quot;two&quot;, hashMap.getOrDefault(&quot;two&quot;, 2));

// 순회
for(String key : hashMap.keySet()) {
    hashMap.get(key);
}

for(Entry&lt;String, Integer&gt; temp : hashMap.entrySet()) {
    System.out.println(temp.getKey() + &quot; &quot; + temp.getValue());
}</code></pre><h1 id="📌-stack-관련-메서드">📌 Stack 관련 메서드</h1>
<pre><code class="language-java">// 선언
Stack&lt;Integer&gt; stack = new Stack&lt;&gt;();

// 추가
stack.push(1);

// 요소 제거
stack.pop();

// 초기화
stack.clear();

// 크기
stack.size();

// 비어있는지 확인
stack.empty();

// 요소 존재하는지 확인
stack.contains(1);

// 스택 최상단 요소 확인 *pop() 아님
stack.peek();</code></pre>
<h1 id="📌-queue-관련-메서드">📌 Queue 관련 메서드</h1>
<pre><code class="language-java">// 선언
Queue&lt;Integer&gt; q = new LinkedList&lt;&gt;();    //LinkedList 사용

// 삽입
q.add(1);        //문제시 예외 발생
q.offer(2);        //문제시 false

// 삭제
q.remove();        //문제시 예외 발생
q.pool();        //문제시 null 리턴

// 초기화 
q.clear();

q.element();     //문제시 예외 발생
q.peek();        //문제시 null 리턴</code></pre>
<h1 id="📌-math-라이브러리">📌 Math 라이브러리</h1>
<pre><code class="language-java">// 두 값을 비교
Math.max(10, 2);    //10
Math.min(10, 2);    //2

// 절대값
Math.abs();

// 올림 내림 반올림
Math.ceil(-2.1);    //-1
Math.floor(-4.8);    //-4
Math.round(-5.5);    // -4

double a = 1.23456;
String b = String.format(&quot;%.1f&quot;, a);    //1.23

Math.pow(2, 2);        //4
Math.sqrt(4);        //2</code></pre>
<hr>
<h1 id="💡dfs-bfs">💡DFS, BFS</h1>
<ul>
<li><p>메서드는 아니지만 자주 나오는 알고리즘이므로 써 봄</p>
<h2 id="1-dfs-재귀-또는-스택으로-구현">1. DFS: 재귀 또는 스택으로 구현</h2>
<h3 id="보통-재귀하면-간단함">보통 재귀하면 간단함</h3>
<pre><code class="language-java">public static void dfs(int i) {
  visited[i] = true;
  System.out.println(i + &quot; &quot;);

  for (int j=1; j&lt;n+1; j++) {
      if(map[i][j] == 1 &amp;&amp; visited[j] == false) {
          dfs(j);
         }
  }
}</code></pre>
</li>
</ul>
<h2 id="2-bfs-큐로-구현">2. BFS: 큐로 구현</h2>
<pre><code class="language-java">public static void bfs(int i) {
    Queue&lt;Integer&gt; q = new LinkedList&lt;&gt;();
    q.offer(i);
    visited[i] = true;

    while(!q.isEmpty()) {
        int temp = q.poll();
        System.out.println(temp + &quot; &quot;);
        for (int j=1; j&lt;n+1; j++) {
            if(map[temp][j] == 1 &amp;&amp; visited[j] == false) {
                q.offer(j);
                visited[j] = true;
            }
         }
     }
}</code></pre>
<blockquote>
<p>참고 링크
<a href="https://velog.io/@ryusuz/JAVA-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%9A%A9-%EC%A3%BC%EC%9A%94-%ED%95%A8%EC%88%98-%EB%AA%A8%EC%9D%8C#8-math-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC">[JAVA] 코딩테스트용 주요 함수 모음</a>
<a href="https://earthteacher.tistory.com/169#">[Java] 자주 사용하는 코딩테스트 문법 정리</a>
<a href="https://bbangson.tistory.com/42">[Java] DFS, BFS 정리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[🙋🏻‍♀️ 프론트엔드 면접 질문 정리]]></title>
            <link>https://velog.io/@ramrami-12/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@ramrami-12/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 24 Jul 2023 08:04:27 GMT</pubDate>
            <description><![CDATA[<h4 id="프론트엔드-직무로-지원했던-회사에-서류통과-후-면접에서-실제로-받았던-질문들과-면접을-대비하기-위한-예상-질문들에-대한-답을-정리한-포스팅-입니다-계속-업데이트-예정">프론트엔드 직무로 지원했던 회사에 서류통과 후, 면접에서 실제로 받았던 질문들과 면접을 대비하기 위한 예상 질문들에 대한 답을 정리한 포스팅 입니다! (계속 업데이트 예정)</h4>
<p>2번 이상 들었거나 중요하다고 생각되는 질문은 추가 설명 및 또는 ⭐️ 표시!</p>
<h3 id="✍-실제-면접에서-들었던-질문">✍ 실제 면접에서 들었던 질문</h3>
<p>*<em>✔️ 브라우저 렌더링 과정⭐️ *</em>
: 브라우저 렌더링은 html, css, javascript와 같은 웹페이지 자원을 브라우저가 렌더링하는 과정입니다. 먼저 HTML 문서를 파싱하여 DOM tree를 생성하고, CSS 문서를 파싱하여 CSSOM(CSS Object Model)을 생성합니다. 그런 다음, 생성한 DOM과 CSSOM을 조합하여 렌더 트리를 구축합니다. 마지막으로 뷰포트를 기반으로 렌더 트리의 각 노드의 위치와 크기를 결정한 뒤 화면에 그립니다(페인팅하는 과정을 거치게 됩니다).</p>
<p><strong>✔️ 비동기, 비동기 함수란 무엇인가요?⭐️</strong>
: 비동기 함수는 함수의 실행 결과가 즉시 반환되지 않고, 특정 조건이 충족될 때까지 기다리는 함수입니다. 자바스크립트에서는 크게 콜백 함수, Promise, async await 3가지 비동기 방식이 존재합니다. </p>
<ul>
<li>자바스크립트에서 함수는 object이므로 다른 함수를 함수의 파라미터로 받아서 내부에서 호출할 수 있는데 그것을 Callback 함수라고 합니다. Callback함수는 함수 내의 다른 태스크를 끝낸 후에 실행되므로 비동기적인 동작을 가능하게 합니다.<pre><code class="language-javascript">const message = function() {
console.log(&quot;This message is shown after 3 seconds&quot;);
}
setTimeout(message, 3000);</code></pre>
</li>
<li>Promise는 비동기 작업이 완료된 후 결과 값을 반환합니다. resolve와 reject를 인자로 받으며 비동기 처리가 성공하면 resolve가 호출되고 실패하면 reject가 호출됩니다. Promise는 <code>new Promise()</code>로 생성할 수 있으며, 종료 될 때 Pending, Fulfilled, Rejected 세 가지 상태를 갖습니다.</li>
<li>async 함수 안에 있는 await 뒤의 구문을 비동기 처리하는 것이 async await 방식입니다.</li>
</ul>
<p><em><em>✔️ ContextAPI와 Redux의 차이 *</em>
_</em> 제가 ContextAPI를 사용했던 이력이 있기 때문에 둘의 차이에 대해 질문을 받았습니다._
<a href="https://alwaysharam.tistory.com/14">ContextAPI로 다크모드 만들기</a>
: 먼저 ContextAPI란, React에서는 props를 사용하여 부모에서 자식에게로 데이터를 직접 전달하기 때문에 깊은 하위 컴포넌트까지 상태를 전달해주거나 하위 컴포넌트에서 상위 컴포넌트로 상태를 끌어올리는데 어려움이 있습니다. 그래서 Context를 선언하여 전역적으로 데이터를 공유할 수 있게 한 것이 ContextAPI입니다. 그러나 Context를 사용하면 상위 컴포넌트가 리렌더링 될 때 같은 context를 공유받은 모든 하위 컴포넌트가 다같이 리렌더링 되어 렌더링 이슈가 발생할 수 있다는 단점이 있습니다. 또한, 상태관리 툴인 Redux와 다르게 ContextAPI는 상태를 공유만 할 뿐 상태를 관리해주지는 않습니다.</p>
<p>*<em>✔️ Redux에 대한 질문(Redux란?, 장점)⭐️ *</em>
: Redux란 javascript의 상태관리 라이브러리입니다. Redux를 사용할 때, 앱의 모든 상태는 store라는 하나의 저장소에 보관됩니다. store의 상태는 직접 가져오거나 변경할 수 없고 action을 통해 할 수 있는데 dispatch() 메소드를 사용하여 action을 reducer로 전달하고, reducer를 통해 store에 접근하여 상태를 변경할 수 있습니다.</p>
<p>*<em>✔️ API란? *</em>
: API는 Application Programming Interface의 줄임말 입니다. 즉, 여러 프로그램들, 데이터베이스 혹은 기능들의 상호 통신 방법을 규정하고 도와주는 매개체 입니다. 웹에서는 주로 RESTfulAPI라고 하는 HTTP 프로토콜을 기반으로 하는 웹 서비스 아키텍처를 통해 클라이언트-서버 간의 통신을 합니다.
➡️ 이렇게 대답할 시, RESTful API에 대한 질문이 들어올 수 있을 것 같습니다!</p>
<p>*<em>✔️ CDN이란? *</em>
: CDN(Content Delivery Network, 콘텐츠 전송 네트워크)이란 지리적으로 분산된 여러 개의 서버입니다. CDN을 사용하여 HTML 페이지를 포함한 Javascript,CSS, 이미지, 동영상 등 웹 콘텐츠를 사용자와 가까운 곳에서 캐싱하여 전송 속도를 높일 수 있습니다.</p>
<p>*<em>✔️ caching이란? *</em>
: 원래 데이터를 복사한 복사본이나 오래 걸리는 작업의 결과를 cache에 임시로 저장해서 빠르게 데이터를 가져올 수 있는 접근 방식이다.</p>
<p>*<em>✔️ CI/CD란? + 사용해본적 있는지 *</em>
: CI/CD 도구를 직접 사용해본 적은 없습니다. 그러나 CI/CD의 개념에 대해서는 알고 있는대로 말씀드리겠습니다. CI/CD는 애플리케이션 개발부터 배포까지의 모든 단계를 자동화하여 사용자에게 빠르고 효율적으로 빈번하게 배포할 수 있는 방법입니다. CI(Continuous Integration)는 지속적인 통합이라는 뜻으로 코드 변경이 있을 때 빌드 및 테스트 되면서 정기적으로 공유 레파지토리에 merge 되는 것 입니다. CD는 Continuous Delivery 혹은 Deploy라는 의미를 가지며 CI에서 build, test 단계를 거친 후에 자동으로 배포하는 것입니다. 대표적인 CI/CD 도구로는 Jenkins와 Gitlab 등이 있습니다.</p>
<p>*<em>✔️ javascript에서 map과 forEach문의 차이⭐️ *</em>
: map과 forEach 모두 for문처럼 배열의 요소에 접근할 수 있습니다. 콜백 함수를 인자로 받아 배열의 각 요소에 대해 콜백함수를 실행합니다. 그러나 map은 콜백함수를 실행한 후 새로운 요소를 return 합니다.</p>
<p>*<em>✔️ React에서 map을 사용할 때 key를 지정해줘야하는 이유 *</em>
: React에서 요소를 업데이트 할 때 엘리먼트에 지정된 고유의 key가 있으면 안정적으로 변경이 가능합니다. key가 어떤 항목을 변경, 추가, 삭제할지 식별할 수 있도록 하는 역할을 한다.</p>
<p>*<em>✔️ 레이아웃을 구성하는 html 태그 *</em>
: header, nav, section, article, footer, aside 태그가 있습니다.</p>
<p>*<em>✔️ class란 무엇인가? *</em></p>
<p><strong>✔️ React에서 class형 컴포넌트와 function 컴포넌트의 차이 (+ 나는 무엇을 사용했는지, 그 이유는 무엇인지)</strong></p>
<p>*<em>✔️ 배열과 object의 차이 *</em></p>
<p>*<em>✔️ React에서 object의 상태를 어떻게 바꾸는지 (다른 변수들과 차이) *</em>
<em>&#39;<a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">구조 분해 할당</a>&#39;이라는 단어가 기억나지 않아서 &#39;쩜쩜쩜(...) 문법&#39;이라고 답변한적 있다..^^;</em></p>
<p>*<em>✔️ 프론트엔드 라이브러리 / 프레임워크에 대한 설명(차이점), 각각 예를 들면 어떤게 있는지 *</em></p>
<p>*<em>✔️ React의 특징 (React를 사용하는 이유) *</em></p>
<p><strong>✔️ React Hooks란? (+ 각각 Hooks에 대한 질문, 사용해본적 있는지) ⭐️</strong></p>
<p><strong>✔️ 호이스팅이란?⭐️</strong></p>
<p>*<em>✔️ var과 let의 차이 (최근 var가 아닌 let을 사용하고 있는데 그 이유) *</em></p>
<p><strong>✔️ typescript를 사용하는 이유</strong></p>
<p>*<em>✔️ 화살표 함수의 장점 *</em></p>
<p>*<em>✔️ 웹 표준, 웹 접근성이란? *</em></p>
<p>*<em>✔️ 반응형 UI, 적응형 UI란? *</em></p>
<p>*<em>✔️ scope에 대해서 설명해보세요 *</em></p>
<p>*<em>✔️ API 소통 시 request query와 body의 차이 (둘 중 무엇을 사용했나요?) *</em></p>
<hr>
<h3 id="✍🏻-인터넷에-돌아다니는-프론트엔드-면접-질문">✍🏻 인터넷에 돌아다니는 프론트엔드 면접 질문</h3>
<p>아직 들어본 적 없는 질문이라도 프론트엔드 개발 직무를 지원했을 때, 준비해야할 내용들을 정리합니다! (맨 아래 출처 표기)</p>
<p>*<em>✔️ RestFull API란? *</em>
: HTTP 프로토콜을 기반으로 하는 웹 서비스 아키텍처 입니다. 자원, 메소드, 메세지 등을 정의하여 클라이언트-서버 간의 통신을 가능하게 합니다. RESTful API는 GET, POST, PUT, DELETE 등의 표준 HTTP 메소드를 사용하여 서버와 통신합니다.</p>
<p>*<em>✔️ HTTP 메소드에 대한 설명 *</em>
: 주로 사용되는 HTTP 메소드는 GET, POST, PUT, DELETE가 있습니다. GET은 서버에서 리소스를 요청하는 메소드 입니다. 요청한 데이터를 가져와서 응답합니다. POST는 서버에 리소스를 전송하는 메소드 입니다. 데이터를 전송하여 서버에서 처리하고, 처리 결과를 응답합니다. PUT은 서버에서 리소스를 대체하거나 없으면 신규 생성하는 메소드 입니다. DELETE는 서버에서 리소스를 삭제하는 메소드 입니다. PUT과 DELETE 모두 POST와 같이 데이터를 서버에서 처리하고 처리 결과를 응답합니다.</p>
<p>*<em>✔️ JS에서 &#39;==&#39;와 &#39;===&#39;의 차이는? *</em></p>
<p>*<em>✔️ 클로저란? *</em></p>
<p>*<em>✔️ 이벤트 버블링이란? *</em></p>
<p>*<em>✔️ 함수 선언식과 표현식 *</em></p>
<hr>
<h3 id="✍🏻-이력경험-포트폴리오와-관련된-질문">✍🏻 이력(경험, 포트폴리오)와 관련된 질문</h3>
<p><strong>✔️ styled component가 아닌 tailwindCSS를 사용한 이유</strong></p>
<p><strong>✔️ typescript를 사용해본 적 있나요?⭐️</strong></p>
<ul>
<li>거의 모든 면접에서 typescript에 대한 질문을 받았던 것 같아요! 최근 typescript에 대한 관심과 TS를 사용하는 인재를 원한다는 것을 알 수 있었습니다.</li>
</ul>
<p>*<em>✔️ git branch 정책을 어떻게 했었는지 *</em></p>
<hr>
<p>(프론트엔드 직무로) 첫 면접 때, 무슨 자신감이었는지 아무런 준비 없이 임했다. 
포트폴리오에 대해서도 모두 내가 했던 활동이니까 문제없이 답할 수 있을 것 같았다.</p>
<p>그런데 기본적인 기술 질문은 물론 이 라이브러리를 왜 썼고 왜 이런 코드를 짰는지에 대한 질문도 당당하게 대답하기 힘들었다. 이후 면접 대비를 위해서도 그렇지만 기본기를 잘 쌓아가기 위해 공부하고 있다. </p>
<p>면접 때 받은 질문들도 면접 이후에 기억나는대로 정리하고 답변을 생각했었는데 (소를 잃었어도 외양간을 고쳐놔야 또 소를 잃지 않을 수 있다..^^;)
<strong>오늘은 그 내용을 한군데 모아보기 위해 포스팅을 작성하게 됐다.
나를 포함해 각자 꿈을 이루기 위해 취업을 준비하는 모든 취준생들을 응원하며 포스팅 끝!✨</strong></p>
<blockquote>
<h3 id="references">References</h3>
</blockquote>
<ul>
<li><a href="https://zero-base.co.kr/event/media_insight_contents_FE_frontend_tech_Interview">프론트엔드 면접 질문(zerobase)</a></li>
<li>[비동기 함수] (<a href="https://www.howdy-mj.me/javascript/async">https://www.howdy-mj.me/javascript/async</a>)</li>
<li><a href="https://www.freecodecamp.org/korean/news/https-www-freecodecamp-org-news-javascript-callback-functions-what-are-callbacks-in-js-and-how-to-use-them/">콜백(Callback) 함수</a></li>
<li><a href="https://hong-jh.tistory.com/entry/Context-API%EB%8A%94-%EC%99%9C-%EC%93%B0%EA%B3%A0-%EA%B7%B8%EB%A0%87%EB%8B%A4%EB%A9%B4-Redux%EB%8A%94-%ED%95%84%EC%9A%94%EC%97%86%EC%9D%84%EA%B9%8C">ContextAPI란? 장단점, Redux는 왜 쓸까?</a></li>
<li><a href="https://ko.redux.js.org/introduction/getting-started/">Redux Introduction</a></li>
<li><a href="https://www.hanl.tech/blog/api%EB%9E%80-api%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EC%A2%85%EB%A5%98-%EC%9E%A5%EB%8B%A8%EC%A0%90/">API 정의</a></li>
<li><a href="https://www.akamai.com/ko/glossary/what-is-a-cdn">CDN이란</a></li>
<li><a href="https://www.hanl.tech/blog/ci-cd-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%EC%93%B0%EC%9D%B4%EB%8A%94-%EB%8F%84%EA%B5%AC-5%EA%B0%80%EC%A7%80/">CI/CD란? +많이 쓰이는 도구</a></li>
</ul>
<p>🌱 해당 포스트는 각 개념 혹은 이론에 대한 면접 질문에 대해 간략하게 대답을 정리한 포스트 입니다. 세부적이고 깊은 공부가 필요할 수 있습니다.
✍🏻 추가할 질문 혹은 잘못된 내용이 있다면 댓글로 알려주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 정보처리기사 필기 시험 후기 (접수, 공부 방법, 꿀팁, 벼락치기 합격✨)]]></title>
            <link>https://velog.io/@ramrami-12/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%ED%95%84%EA%B8%B0-%EC%8B%9C%ED%97%98-%ED%9B%84%EA%B8%B0-%EC%A0%91%EC%88%98-%EA%B3%B5%EB%B6%80-%EB%B0%A9%EB%B2%95-%EA%BF%80%ED%8C%81-%EB%B2%BC%EB%9D%BD%EC%B9%98%EA%B8%B0-%ED%95%A9%EA%B2%A9</link>
            <guid>https://velog.io/@ramrami-12/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%ED%95%84%EA%B8%B0-%EC%8B%9C%ED%97%98-%ED%9B%84%EA%B8%B0-%EC%A0%91%EC%88%98-%EA%B3%B5%EB%B6%80-%EB%B0%A9%EB%B2%95-%EA%BF%80%ED%8C%81-%EB%B2%BC%EB%9D%BD%EC%B9%98%EA%B8%B0-%ED%95%A9%EA%B2%A9</guid>
            <pubDate>Mon, 22 May 2023 14:39:44 GMT</pubDate>
            <description><![CDATA[<p>오늘 친 따끈 따끈한 정보처리기사 필기 시험 후기를 써보려고 한다 ✍🏻</p>
<h2 id="1-원서-접수-방법">1. 원서 접수 방법</h2>
<p>먼저 모든 기능사, 기사, 산업기사 시험이 그렇듯 <a href="https://www.q-net.or.kr/man001.do?gSite=Q">큐넷</a>에서 접수를 받는다!</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/cce03bd6-4187-4df1-914d-0938edf56c7f/image.png" alt=""></p>
<p>나는 이번에 정기기사 2회 시험을 쳤고, 3회차 접수는 6월 19일(오전 10시)부터 6월 22일(오후 6시)까지 있다.</p>
<ul>
<li>1회, 2회의 경우 빈자리 추가 접수기간이 있는데 3회는 없음 주의</li>
</ul>
<p>처음에 접수할 땐 자리가 많이 없어서 당황할 수 있는데 계속 새로고침 하면서 보다보면 빈자리가 생기기도 한다..! 
⭐️ <strong>빈자리 추가 접수 때도 마찬가지, 자리 없다고 절망하지 말고 접수할 수 있는 기간동안 계속 새로고침 해보기!!!</strong></p>
<ul>
<li><strong>날짜 변경 기간에 빈 자리가 있으면 환불 없이 날짜를 변경</strong>할 수 있다.
나는 그 사실을 몰랐기 때문에.. 뒤늦게 50% 환불 후 빈자리 추가 접수 때 다시 접수해서 날짜를 변경했다 ㅠㅠ💸</li>
</ul>
<h2 id="2-공부-방법">2. 공부 방법</h2>
<ol>
<li>아무 정보처리기사 책이나 사서 (나는 수제비를 썼지만 무슨 책을 쓰는 것 보다 공부를 어떻게 하느냐, 얼마나 하느냐가 더 중요하다고 생각한다) 3회독 이상을 한다.</li>
<li>시험 3일~1주일 전부터 기출을 풀기 시작해서 최소 3년 기출에서 최대한 많이 푼다.</li>
<li>틀린 문제는 오답 노트를 작성하고 다시 책을 보면서 모르는 개념을 오답 노트와 함께 필기해둔다.</li>
<li>시험 시작 전까지 정리해둔 노트(틀린 개념, 모르는 개념, 외울 것들)를 반복해서 익힌다.</li>
</ol>
<p>내가 이렇게 공부했다면 이 포스팅 제목에 &quot;벼락치기 합격&quot;이라고 쓰지 않았을 것이다..
원래 계획은 수제비 책 앞부분에 있는 1달 공부법(위와 같은 정공법)이었으나 
이리저리 미루고 설렁설렁 하다보니 진정한 공부는 시험 2일 전부터 시작하게 되었다. 
(그 전에 책의 목차와 어떤 내용들이 있는지 정도는 파악할 정도의 1회독을 해두긴 했다.)</p>
<p>아래는 내가 2일간 했던 <strong>벼락치기 공부법</strong>이다!
(단, 당연한 말이겠지만 CS에 대한 지식이 하나도 없는 상태에서 이런 벼락치기는 힘들다 ㅠㅠ)</p>
<p>먼저 <a href="https://www.comcbt.com/xe/iz">CBT 기출 사이트</a>에서 기출을 푼다. 조금 냅다 푸는 느낌이 없잖아 있지만 <strong>일단</strong> 풀어본다. (모의고사로 풀어도 된다)</p>
<p><a href="https://www.comcbt.com/">문제 풀이 사이트</a>를 이용하면 편하게 문제를 풀 수 있다!</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/c67b7fa4-13ee-4aad-b7e1-51b310b6526a/image.png" alt="">
한 문제씩 풀기의 문제풀기에 들어가서 기사 - 정보처리기사를 선택한다. 
해설을 보면서 풀어도 되고 시험 모드(문제를 모두 풀고 체점 후 결과를 알려준다)로 풀어도 되지만 시험 모드를 추천한다!</p>
<p>시험을 한두번 풀고나면 과목당 점수가 나오면서 어떤 과목을 더 공부해야할지 알 수 있다.
틀린 문제들은 모아서 해설과 같이 보여주는데 첫 한 두번 시험에서는 틀린게 많을 확률이 크므로 눈으로만 읽으며 학습한다.</p>
<p>두번째 풀고 나서부터 &#39;조금만 더하면 합격하겠는데?!&#39;하는 생각이 들었다. (두번째 쳐본 결과 평균이 59점이 나와서 불합격이 떴다 ㅠ)</p>
<p>다음부터는 <strong>틀린 문제에서 모르는 개념, 암기해야될 개념들을 해설과 <a href="https://m.blog.naver.com/wook2124/222102990691">요약본</a>, 또는 책에서 찾아서 따로 적어두고 암기한다. 특히 요약본에 별 2개 이상인 것들은 꼭! 기록해서 외워둔다.</strong></p>
<p><strong>시간이 날 때마다 기록해둔 것들을 암기하고 두음쌤 영상</strong>을 계속 봤다.
<a href="https://www.youtube.com/watch?v=4TaS6tpb9uA&amp;list=PLraQPczZnB1p6uiLmXQsBivP5QSilYr_5">두음쌤 영상</a> </p>
<p>아래의 영상들도 밥 먹으면서 혹은 자투리 시간 등등에 꾸준히 봤다</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=6U4ZFrpmL2c">3, 4과목 데이터베이스 구축, 프로그래밍 언어 활용</a></li>
<li><a href="https://www.youtube.com/watch?v=f_onc2EzgN8">1,2,5과목 소프트웨어 설계, 소프트웨어 개발, 정보시스템 구축 관리 + 꿀팁</a></li>
</ul>
<p>유튜브에 &#39;정보처리기사 벼락치기&#39;라고 검색하면 나오는 영상들이다.</p>
<p>그리고 <a href="https://www.youtube.com/watch?v=3gP2qMkjHcY">벼락치기 공부법 영상</a>도 봤다. 요약본을 여기서 참고했는데 공부법도 참고하실 분들은 보시길!</p>
<p>시험 2일전부터 당일까지 이렇게 공부를 했고, 무사히 필기를 합격할 수 있었다.
시험 당일 꿀팁은 아래에 작성하겠다!</p>
<h2 id="3-시험-당일-꿀팁-주의-사항🍯⚠️">3. 시험 당일 꿀팁, 주의 사항🍯⚠️</h2>
<p>📌 <a href="http://www.q-net.or.kr/cbt/index.html">연습 사이트</a>에서 시험 환경 확인해보기
링크를 들어가면 실제 시험처럼 환경을 체험해볼 수 있다. 5분 정도 걸리니까 미리 확인해보고 가면 좋다.</p>
<p>📌 정말 기본적인 것인데 시험장 가는 길을 미리 파악 해둬야한다..!
나는 걸어서 2-30분 정도 걸리는 곳이었는데 그냥 택시를 탔다.
시험 시작 1-20분 전에는 미리 가서 마음의 준비와 화장실 준비(?)를 하는 것이 좋기 때문에 계획을 짜놓는 것이 좋다.</p>
<p>📌 ⭐️⭐️⭐️ 신분증 꼭 챙겨가기 ⭐️⭐️⭐️
진짜 너무 중요,,
정처기는 아니지만 TOPCIT 칠때 신분증 없어서, 안가져와서 못치는 사람들 많이 봤다..</p>
<p>📌 필기구 챙기기
정처기는 딱히 뭘 적을 필요가 없을 수 있지만🤔 그래도 혹시 모르니, 또 은근 계산 문제나 머릿속으로 생각하기 힘든 문제들이 있다 연습 종이를 시험 때 나눠주니까 필기구를 챙겨가서 헷갈리지 않게 적어가며 풀자!</p>
<ul>
<li>수험표 뽑아가기, 수험 번호 적어가기 =&gt; 인터넷에서 보고 수험표도 뽑아가고 수험번호도 따로 포스트잇에 적어갔는데 딱히 필요는 없었다. OMR이 아닌 전산 시스템으로 바뀌고 나서는 필요 없는듯?! 혹시 모르니까 수험번호는 미리 알아보고 가자!</li>
<li>물 챙기기 =&gt; 안챙겨가도 상관은 없지만 은근 목이 말라서 도움이 되었다. 화장실 가고 싶을까봐 조금씩만 마심🤣</li>
</ul>
<p>시험장에 가면 감독관님께서 그리고 방송으로 상세하게 주의사항을 알려주시기 때문에 잘 찾아만 간다면 크게 걱정할 필요는 없다.
그리고 결과는 답안을 제출하면 바로 나와서 합격인지 불합격인지 알 수 있다!! (공식적인 합격 발표 날짜는 따로 있지만)</p>
<p>⭐️⭐️⭐️ 그리고 필기 시험에 합격했다면 서류 제출 기간 안에 꼭 <strong>서류 제출</strong>하시길!!</p>
<p>이제 실기가 또 남아있지만 어쨌든 필기를 무사히 합격했기에 공부 방법을 공유한다
모두들 열공해서 합격하시길 바라겠습니다 🙏🔥</p>
<p><em>문제시 댓글 please,,</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2022 KAKAO TECH INTERNSHIP]
두 큐 합 같게 만들기]]></title>
            <link>https://velog.io/@ramrami-12/2022-KAKAO-TECH-INTERNSHIP%EB%91%90-%ED%81%90-%ED%95%A9-%EA%B0%99%EA%B2%8C-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/2022-KAKAO-TECH-INTERNSHIP%EB%91%90-%ED%81%90-%ED%95%A9-%EA%B0%99%EA%B2%8C-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Thu, 13 Apr 2023 22:30:32 GMT</pubDate>
            <description><![CDATA[<h3 id="2022-kakao-tech-internship">[2022 KAKAO TECH INTERNSHIP]</h3>
<h3 id="프로그래머스-두-큐-합-같게-만들기-문제-풀이">프로그래머스 두 큐 합 같게 만들기 문제 풀이</h3>
<h3 id="📌-문제-설명">📌 문제 설명</h3>
<p>길이가 같은 두 개의 큐가 주어집니다. 하나의 큐를 골라 원소를 추출(pop)하고, 추출된 원소를 다른 큐에 집어넣는(insert) 작업을 통해 각 큐의 원소 합이 같도록 만들려고 합니다. 이때 필요한 작업의 최소 횟수를 구하고자 합니다. 한 번의 pop과 한 번의 insert를 합쳐서 작업을 1회 수행한 것으로 간주합니다.</p>
<p>큐는 먼저 집어넣은 원소가 먼저 나오는 구조입니다. 이 문제에서는 큐를 배열로 표현하며, 원소가 배열 앞쪽에 있을수록 먼저 집어넣은 원소임을 의미합니다. 즉, pop을 하면 배열의 첫 번째 원소가 추출되며, insert를 하면 배열의 끝에 원소가 추가됩니다. 예를 들어 큐 [1, 2, 3, 4]가 주어졌을 때, pop을 하면 맨 앞에 있는 원소 1이 추출되어 [2, 3, 4]가 되며, 이어서 5를 insert하면 [2, 3, 4, 5]가 됩니다.</p>
<p>다음은 두 큐를 나타내는 예시입니다.</p>
<pre><code>queue1 = [3, 2, 7, 2]
queue2 = [4, 6, 5, 1]
</code></pre><p>두 큐에 담긴 모든 원소의 합은 30입니다. 따라서, 각 큐의 합을 15로 만들어야 합니다. 예를 들어, 다음과 같이 2가지 방법이 있습니다.</p>
<p>queue2의 4, 6, 5를 순서대로 추출하여 queue1에 추가한 뒤, queue1의 3, 2, 7, 2를 순서대로 추출하여 queue2에 추가합니다. 그 결과 queue1은 [4, 6, 5], queue2는 [1, 3, 2, 7, 2]가 되며, 각 큐의 원소 합은 15로 같습니다. 이 방법은 작업을 7번 수행합니다.
queue1에서 3을 추출하여 queue2에 추가합니다. 그리고 queue2에서 4를 추출하여 queue1에 추가합니다. 그 결과 queue1은 [2, 7, 2, 4], queue2는 [6, 5, 1, 3]가 되며, 각 큐의 원소 합은 15로 같습니다. 이 방법은 작업을 2번만 수행하며, 이보다 적은 횟수로 목표를 달성할 수 없습니다.
따라서 각 큐의 원소 합을 같게 만들기 위해 필요한 작업의 최소 횟수는 2입니다.</p>
<p>길이가 같은 두 개의 큐를 나타내는 정수 배열 queue1, queue2가 매개변수로 주어집니다. 각 큐의 원소 합을 같게 만들기 위해 필요한 작업의 최소 횟수를 return 하도록 solution 함수를 완성해주세요. 단, 어떤 방법으로도 각 큐의 원소 합을 같게 만들 수 없는 경우, -1을 return 해주세요.</p>
<h3 id="📌-제한사항">📌 제한사항</h3>
<p>1 ≤ queue1의 길이 = queue2의 길이 ≤ 300,000
1 ≤ queue1의 원소, queue2의 원소 ≤ 109
주의: 언어에 따라 합 계산 과정 중 산술 오버플로우 발생 가능성이 있으므로 long type 고려가 필요합니다.</p>
<h3 id="📌-입출력-예">📌 입출력 예</h3>
<pre><code>    queue1        |        queue2        |    result    
[3, 2, 7, 2]    |    [4, 6, 5, 1]    |    2            
[1, 2, 1, 2]    |    [1, 10, 1, 2]    |    7        
[1, 1]    [1, 5]    |    -1                |            </code></pre><p><strong>입출력 예 설명</strong>
입출력 예 #1
문제 예시와 같습니다.</p>
<p>입출력 예 #2
두 큐에 담긴 모든 원소의 합은 20입니다. 따라서, 각 큐의 합을 10으로 만들어야 합니다. queue2에서 1, 10을 순서대로 추출하여 queue1에 추가하고, queue1에서 1, 2, 1, 2와 1(queue2으로부터 받은 원소)을 순서대로 추출하여 queue2에 추가합니다. 그 결과 queue1은 [10], queue2는 [1, 2, 1, 2, 1, 2, 1]가 되며, 각 큐의 원소 합은 10으로 같습니다. 이때 작업 횟수는 7회이며, 이보다 적은 횟수로 목표를 달성하는 방법은 없습니다. 따라서 7를 return 합니다.</p>
<p>입출력 예 #3
어떤 방법을 쓰더라도 각 큐의 원소 합을 같게 만들 수 없습니다. 따라서 -1을 return 합니다.</p>
<hr>
<h3 id="💡-간단한-풀이-설명">💡 간단한 풀이 설명</h3>
<p>먼저 queue의 선입선출 기능을 구현하기 위해 collections 라이브러리의 deque를 import해서 사용했다.
pop(0)을 해도 되지만, 그렇게 했을 때 맨 앞의 요소가 빠지고 뒤의 요소들이 앞으로 당겨지면서 연산을 더 하게 된다고 해서 pop(0) 사용을 지양하고 있다.</p>
<p>처음엔 dfs 완탐 문제로 인식하고 풀고 있었는데 잘 안풀려서 구글링 해봤다. (솔직하게,,)
두 개의 큐 중 합이 더 많은 곳에서 더 적은 곳으로 요소를 옮겨 같게 만든다는 메인 아이디어를 참고하여 코드를 작성했다.</p>
<p>‼️ 주의 할 점 
반복문을 queue1 길이x4만큼 도는 이유는 queue1와 queue2의 내용을 완전히 바꾸려면 queue1 길이x4만큼의 회수가 필요하기 때문이다. (더 좋은 횟수가 있을수도 있다)</p>
<h3 id="💡-정답-코드">💡 정답 코드</h3>
<pre><code>from collections import deque

def solution(queue1, queue2):
    answer = 0

    queue1 = deque(queue1)
    queue2 = deque(queue2)

    sum1 = sum(queue1)
    sum2 = sum(queue2)

    for _ in range(len(queue1) * 4):
        if sum1 &gt; sum2:
            sum1 -= queue1[0]
            sum2 += queue1[0]
            queue2.append(queue1.popleft())
        elif sum1 &lt; sum2:
            sum1 += queue2[0]
            sum2 -= queue2[0]
            queue1.append(queue2.popleft())
        else:
            return answer

        answer += 1

    return -1</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[React 반짝이는 별 효과 만들기✨]]></title>
            <link>https://velog.io/@ramrami-12/React-%EB%B0%98%EC%A7%9D%EC%9D%B4%EB%8A%94-%EB%B3%84-%ED%9A%A8%EA%B3%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/React-%EB%B0%98%EC%A7%9D%EC%9D%B4%EB%8A%94-%EB%B3%84-%ED%9A%A8%EA%B3%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Thu, 16 Feb 2023 14:56:59 GMT</pubDate>
            <description><![CDATA[<p>포트폴리오 사이트에 들어갈 별 효과를 만들어보았다.</p>
<p>먼저 별 객체를 만들어준다.</p>
<pre><code>class star {
  constructor(x, y, size, time) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.time = time;
  }
}</code></pre><p>x, y는 좌표, size는 별 크기, time은 반짝이는 효과가 실행되는 시간이다.
4가지를 모두 랜덤으로 생성해서 넣어줄 것이다.</p>
<p>javascript 코드를 작성하기 전에 html과 css만 사용해서 크기가 8x8인 별을 하나만 만들어보면 이렇게 만들 수 있다.</p>
<pre><code>&lt;div class=&quot;star&quot;&gt;&lt;/div&gt;</code></pre><pre><code>.star {
  position: relative;
  width: 8px;
  height: 8px;
  left: 1137px;
  top: 485px;
  background-color: #ffffff;
  filter: blur(5px);
  animation: blink 1s steps(5) infinite;
}</code></pre><p>결과:</p>
<div class="star" style="width: 8px; height: 8px; background-color: #ffffff; filter: blur(5px); animation: blink 1s steps(5) infinite;"></div>

<hr>
<p>똑같이 javascript 코드를 작성해주면 되는데, 사이즈와 별의 위치, 반짝이는 시간을 랜덤으로 뽑아준다.</p>
<pre><code>class star {
  constructor(x, y, size, time) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.time = time;
  }

  set() {
    this.x = Math.random() * window.innerWidth;
    this.y = Math.random() * window.innerHeight;
    this.size = Math.random() * 12;
    this.time = Math.random() * 8;

    const background = document.getElementById(&quot;main&quot;);
    const starDiv = document.createElement(&quot;div&quot;);
    starDiv.className = &quot;star&quot;;

    starDiv.style.position = &quot;absolute&quot;;
    starDiv.style.left = this.x + &quot;px&quot;;
    starDiv.style.top = this.y + &quot;px&quot;;
    starDiv.style.width = this.size + &quot;px&quot;;
    starDiv.style.height = this.size + &quot;px&quot;;
    starDiv.style.backgroundColor = &quot;white&quot;;
    starDiv.style.filter = &quot;blur(5px)&quot;;
    starDiv.style.animation = `blink ${this.time}s steps(5) infinite`;

    background.appendChild(starDiv);
  }
}</code></pre><p>마지막으로 React의 useEffect라는 Hooks를 사용해서 사이트가 렌더링 될 때 별 객체 15개를 만들어서 띄워준다.</p>
<ul>
<li>useEffect는 원래 상태가 변경될 때마다 실행되지만 마지막에 빈 배열을 넣어주면 렌더링 될 때 한번만 실행된다.<pre><code>useEffect(() =&gt; {
  for (let i = 0; i &lt; 15; i++) {
    const newStar = new star();
    newStar.set();
  }
}, []);</code></pre></li>
</ul>
<h3 id="결과물">결과물</h3>
<p>새로고침 할 때마다 (사이트가 렌더링 될 때마다) 15개의 별이 다른 좌표, 다른 사이즈로 만들어진다.
반짝이는 속도도 각각 다르기 때문에 더 반짝 반짝한 느낌이 든다
아주 간단하게 반짝이는 화면 구현 끝_!
<img src="https://velog.velcdn.com/images/ramrami-12/post/a0eb3fb3-c424-472d-9c9d-27fc4e4905ad/image.gif" alt=""></p>
<p>➕ div로 만들었기 때문에 별의 모양이 자세히 보면 네모에 가깝다..! 별을 원 모양으로 만들고 싶다면 border-radius를 50%로 지정해주면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SWEA] 홈 방범 서비스]]></title>
            <link>https://velog.io/@ramrami-12/SWEA-%ED%99%88-%EB%B0%A9%EB%B2%94-%EC%84%9C%EB%B9%84%EC%8A%A4</link>
            <guid>https://velog.io/@ramrami-12/SWEA-%ED%99%88-%EB%B0%A9%EB%B2%94-%EC%84%9C%EB%B9%84%EC%8A%A4</guid>
            <pubDate>Thu, 16 Feb 2023 13:32:39 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p><a href="https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5V61LqAf8DFAWu&amp;">링크</a></p>
<h3 id="문제-풀이">문제 풀이</h3>
<p>😫 처음 시도한 실패한 방법
처음에는 NxN 맵을 모두 돌면서 각 좌표에서 범위가 K일 때 포함되는 집의 수를 세면서 max값을 업데이트 하는 방법을 썼다.
이 방법일 때 알아낸 것은 N일 때 K의 범위는 1부터 N+1이라는 것.
아래 그림을 예로 들면 K가 4일 때 N이 3인 맵을 모두 덮는다
<img src="https://velog.velcdn.com/images/ramrami-12/post/9a95d1bd-35f1-4a2f-9ec3-6fc18ccd59d0/image.png" alt="">
그럼 여기까지만 해도 벌써 for문을 3번 돌게 된다
dfs로 한 중심 좌표에서 K 범위만큼 탐색하는 것을 구현하다가 시간이 너무 오래 걸려서 풀이 방법을 바꾸었다.</p>
<p>💡 성공한 방법
허무하게도 정말 쉬운 방법으로 성공했다.
각 집 사이의 거리를 구해서 K 범위 안에 있으면 count 하는 방식으로 구현했다.</p>
<p>‼️ 문제를 풀면서 주의할 점은 !손해를 보지 않는 서비스 영역을 찾아야 한다! (= 이득이 없어도 된다)</p>
<h3 id="코드">코드</h3>
<pre><code>import sys

sys.stdin = open(&quot;sample_input.txt&quot;, &quot;r&quot;)


def get_distance(x, y, home):
    return abs(home[0] - x) + abs(home[1] - y)


def make_diamond(r, x, y):
    global home_count, home_list

    for home in home_list:
        if get_distance(x, y, home) &lt; r:
            home_count += 1


T = int(input())
for test_case in range(T):
    max_home_count = 0
    city_info = list()
    home_list = list()
    N, M = map(int, input().split())
    K = N+2

    for _ in range(N):
        city_info.append(list(map(int, input().split())))

    for i in range(N):
        for j in range(N):
            if city_info[i][j] == 1:
                home_list.append((i, j))

    for i in range(N):
        for j in range(N):
            for k in range(1, K):
                operation_cost = k * k + (k - 1) * (k - 1)
                home_count = 0
                make_diamond(k, i, j)

                # home_count * M - operation_cost : 회사의 이익
                profit = home_count * M - operation_cost
                if -1 &lt; profit:
                    max_home_count = max(max_home_count, home_count)
                    # max_profit = home_count * M - operation_cost

    print(&quot;#{} {}&quot;.format(test_case+1, max_home_count))</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[SWEA] 줄기세포배양 (풀이 중)]]></title>
            <link>https://velog.io/@ramrami-12/SWEA-%EC%A4%84%EA%B8%B0%EC%84%B8%ED%8F%AC%EB%B0%B0%EC%96%91-%ED%92%80%EC%9D%B4-%EC%A4%91</link>
            <guid>https://velog.io/@ramrami-12/SWEA-%EC%A4%84%EA%B8%B0%EC%84%B8%ED%8F%AC%EB%B0%B0%EC%96%91-%ED%92%80%EC%9D%B4-%EC%A4%91</guid>
            <pubDate>Thu, 16 Feb 2023 12:46:23 GMT</pubDate>
            <description><![CDATA[<p>SW Expert Academy의 모의 SW 역량 테스트 문제들을 풀고 있다.</p>
<h3 id="문제">문제</h3>
<p>줄기세포 배양 시뮬레이션 프로그램을 만들려고 한다.
줄기세포들을 배양 용기에 도포한 후 일정 시간 동안 배양을 시킨 후 줄기 세포의 개수가 몇 개가 되는지 계산하는 시뮬레이션 프로그램을 만들어야 한다. </p>
<p>하나의 줄기 세포는 가로, 세로 크기가 1인 정사각형 형태로 존재하며 배양 용기는 격자 그리드로 구성되어 있으며 하나의 그리드 셀은 줄기 세포의 크기와 동일한 가로, 세로 크기가 1인 정사각형이다.</p>
<p>각 줄기 세포는 생명력이라는 수치를 가지고 있다.
초기 상태에서 줄기 세포들은 비활성 상태이며 생명력 수치가 X인 줄기 세포의 경우 X시간 동안 비활성 상태이고 X시간이 지나는 순간 활성 상태가 된다.
줄기 세포가 활성 상태가 되면 X시간 동안 살아있을 수 있으며 X시간이 지나면 세포는 죽게 된다.
세포가 죽더라도 소멸되는 것은 아니고 죽은 상태로 해당 그리드 셀을 차지하게 된다.</p>
<p>활성화된 줄기 세포는 첫 1시간 동안 상, 하, 좌, 우 네 방향으로 동시에 번식을 한다.
번식된 줄기 세포는 비활성 상태이다.</p>
<p>하나의 그리드 셀에는 하나의 줄기 세포만 존재할 수 있기 때문에 번식하는 방향에 이미 줄기 세포가 존재하는 경우 해당 방향으로 추가적으로 번식하지 않는다.</p>
<p>두 개 이상의 줄기 세포가 하나의 그리드 셀에 동시 번식하려고 하는 경우 생명력 수치가 높은 줄기 세포가 해당 그리드 셀을 혼자서 차지하게 된다.</p>
<p>줄기 세포의 크기에 비해 배양 용기의 크기가 매우 크기 때문에 시뮬레이션에서 배양 용기의 크기는 무한하다고 가정한다. </p>
<p>아래 [그림1]과 [그림2]는 줄기 세포가 번식하는 예를 나타낸다.
<img src="https://velog.velcdn.com/images/ramrami-12/post/4c5e205e-0634-4c0f-8e88-6cc86f07b3b2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/603a43d9-95e7-4253-bbd6-84c33f1b01e3/image.png" alt=""></p>
<p>줄기 세포의 초기 상태 정보와 배양 시간 K시간이 주어질 때, K시간 후 살아있는 줄기 세포(비활성 상태 + 활성 상태)의 총 개수를 구하는 프로그램을 작성하라.</p>
<h3 id="제약-사항">제약 사항</h3>
<p>초기 상태에서 줄기 세포가 분포된 영역의 넓이는 세로 크기 N, 가로 크기 M이며 N, M은 각각 1 이상 50 이하의 정수이다. (1≤N≤50, 1≤M≤50)
배양 시간은 K시간으로 주어지며 K는 1 이상 300 이하의 정수이다. (1≤K≤300)
배양 용기의 크기는 무한하다. 따라서 줄기 세포가 배양 용기 가장자리에 닿아서 번식할 수 없는 경우는 없다.
줄기 세포의 생명력 X는 1 이상 10 이하의 정수이다. (1≤X≤10)</p>
<h3 id="입력">입력</h3>
<p>입력의 가장 첫 줄에는 총 테스트 케이스의 개수 T가 주어진다.
그 다음 줄부터는 각 테스트 케이스가 주어지며
각 테스트 케이스의 첫째 줄에는 초기 상태에서줄기 세포가 분포된 세로 크기 N, 가로 크기 M, 배양 시간 K가 순서대로 주어진다.
다음 N 줄에는 각 줄마다 M개의 그리드 상태 정보가 주어진다.
1~10까지의 숫자는 해당 그리드 셀에 위치한 줄기 세포의 생명력을 의미하며,
0인 경우 줄기 세포가 존재하지 않는 그리드이다.</p>
<h3 id="문제-풀이">문제 풀이</h3>
<p>재귀를 사용한 구현으로 풀었다.
댓글에서 배양 용기의 최대 사이즈는 max(N, M) + Kx2라는 말을 보고 최대 사이즈를 똑같이 설정했다. (N또는 M에서 양 옆으로 K만큼 빠져나간다고 하면 최대는 max(N, M) + Kx2가 될 수 밖에 없다.)</p>
<p>그런데 문제를 아직 시간초과로 완전히 풀지 못했다 (5개의 테스트 케이스는 통과한다.)
시간 초과를 해결하기 위해 용기 사이즈를 이리저리 조절해보다가 용기 사이즈를 380으로 설정해도 된다는 사실을 알게 되었다.</p>
<p>각 시간당 일어날 일들을 문제에서 잘 파악한 뒤에 그대로 구현하면 된다.
조금 더 자세하게 설명하자면 배양 용기 사이즈만큼의 2차원 행렬 2개와 각 좌표당 에너지(생명력)을 저장하는 dictionary를 하나 사용한다.
첫번째 2차원 행렬은 시간(생명력)을 저장하고 두번째 행렬은 상태(비활성화, 활성화, 죽음)를 저장한다 </p>
<p>행렬의 모든 좌표를 돌면서 각 좌표에 세포가 있다면 비활성 상태인지 활성 상태인지 파악하고 비활성 상태인데 시간이 0이라면 활성상태로 바꾸는 등 각 상황에 맞는 작업들을 수행한다.</p>
<p>시간초과가 발생하는 원인으로 생각되는건 아마 세포가 번식할 때 번식할 세포의 좌표를 리스트에 모아놨다가 시간을 +1 하기 전에 한번에 번식하는데 여기서 발생하는 것이 아닐까 싶다..</p>
<p>혹시 지나가던 누구든 무엇이 문제인지 알 것 같다면 알려주길 바란다...
<img src="https://velog.velcdn.com/images/ramrami-12/post/081c6751-3100-49bc-849a-de5c79907f27/image.png" alt=""></p>
<p>‼️ 각 시간별로 일어나는 일들을 꼼꼼하게 잘 생각해서 구현 해야한다.
내가 실수 했던 부분을 몇가지 기록해 두자면 세포는 활성 상태가 된 1시간 이후에 번식한다. 
번식하고 나서도 바로 죽는 것이 아니라 세포의 시간이 점점 줄어들다가 0이 되면 죽는다. 
번식할 때 동시에 번식하는 세포 중 생명력이 더 큰 세포와 번식할 자리(?)가 겹치면 생명력이 더 큰 세포의 생명력으로 번식해야한다. 
이 우선순위 처리 하는 것도 깜빡해서 헤맸다.</p>
<p>💡 상태를 표현하는 숫자들을 INACTIVE, ACTIVE, DIE와 같은 상수로 선언하여 코드가 더 예뻐졌다</p>
<h3 id="코드">코드</h3>
<pre><code>import sys

sys.stdin = open(&quot;sample_input.txt&quot;, &quot;r&quot;)


DIRECTION_X = [-1, 1, 0, 0]
DIRECTION_Y = [0, 0, -1, 1]

INACTIVE = 2
ACTIVE = 1
DIE = 0

NOT_EXIST = -1
MAX_RANGE = 380


def breeding(arr):
    visited = list()
    # 우선 순위
    for x, y in arr:
        for idx in range(4):
            new_x = x + DIRECTION_X[idx]
            new_y = y + DIRECTION_Y[idx]
            if curr_status_map[new_x][new_y] == NOT_EXIST:
                curr_status_map[new_x][new_y] = INACTIVE
                curr_time_map[new_x][new_y] = energy_dict[(x, y)] - 1
                energy_dict[(new_x, new_y)] = energy_dict[(x, y)]
                visited.append([new_x, new_y])
            elif [new_x, new_y] in visited:
                if energy_dict[(new_x, new_y)] &lt; energy_dict[(x, y)]:
                    curr_time_map[new_x][new_y] = energy_dict[(x, y)] - 1
                    energy_dict[(new_x, new_y)] = energy_dict[(x, y)]


def multiply_cells(time):
    if time == K+1:
        return

    breeding_list = list()

    for n in range(MAX_RANGE):
        for m in range(MAX_RANGE):
            if curr_time_map[i][j] == NOT_EXIST:
                # 비활성 상태
                if curr_status_map[n][m] == INACTIVE:
                    if curr_time_map[n][m] == 0:
                        curr_status_map[n][m] = ACTIVE
                        curr_time_map[n][m] = energy_dict[(n, m)]
                    else:
                        curr_time_map[n][m] -= 1

                # 활성 상태
                elif curr_status_map[n][m] == ACTIVE:
                    if curr_time_map[n][m] == energy_dict[(n, m)]:
                        breeding_list.append((n, m))

                    curr_time_map[n][m] -= 1
                    if curr_time_map[n][m] == 0:
                        curr_status_map[n][m] = DIE

    breeding(breeding_list)
    multiply_cells(time+1)


T = int(input())
for test_case in range(T):
    count = 0
    grid_map = list()
    N, M, K = map(int, input().split())  # 세로 크기 N, 가로 크기 M, 배양 시간 K

    # max_range = max(N, M) + K * 2
    curr_time_map = [[NOT_EXIST for _ in range(MAX_RANGE)] for _ in range(MAX_RANGE)]
    curr_status_map = [[NOT_EXIST for _ in range(MAX_RANGE)] for _ in range(MAX_RANGE)]
    energy_dict = dict()

    for _ in range(N):
        grid_map.append(list(map(int, input().split())))

    for i in range(N):
        for j in range(M):
            if grid_map[i][j] &gt; 0:
                curr_status_map[MAX_RANGE//2+i][MAX_RANGE//2+j] = INACTIVE
                curr_time_map[MAX_RANGE//2+i][MAX_RANGE//2+j] = grid_map[i][j]
                energy_dict[(MAX_RANGE//2+i, MAX_RANGE//2+j)] = grid_map[i][j]

    multiply_cells(0)

    for i in range(MAX_RANGE):
        for j in range(MAX_RANGE):
            if curr_status_map[i][j] != DIE and curr_time_map[i][j] != NOT_EXIST:
                count += 1

    print(&quot;#{} {}&quot;.format(test_case+1, count))
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] python 으로 순열 구현하기 ]]></title>
            <link>https://velog.io/@ramrami-12/Python-python-%EC%9C%BC%EB%A1%9C-%EC%88%9C%EC%97%B4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/Python-python-%EC%9C%BC%EB%A1%9C-%EC%88%9C%EC%97%B4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 02 Feb 2023 06:08:09 GMT</pubDate>
            <description><![CDATA[<p>알고리즘 문제를 풀다가 순열을 구현 할 일이 생겼다.
<a href="https://docs.python.org/3/library/itertools.html">itertools 라이브러리</a>를 사용하면 손쉽게 구현할 수는 있지만 
라이브러리를 사용하지 못할 때를 대비하여 순수하게 python 코드로 구현한 순열 코드를 기록해 두려고 한다.</p>
<pre><code>def combinations(arr, n):
    combination = list()

    if n == 0:
        return [[]]

    for idx in range(0, len(arr)):
        ele = arr[idx]
        rest_arr = arr[idx+1:]
        for c in combinations(rest_arr, n-1):
            combination.append([ele] + c)

    return combination</code></pre><p>재귀를 사용하였다.</p>
<p>출처: <a href="https://cotak.tistory.com/70">https://cotak.tistory.com/70</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[mac에서 nvm 설치하기 ]]></title>
            <link>https://velog.io/@ramrami-12/mac%EC%97%90%EC%84%9C-nvm-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/mac%EC%97%90%EC%84%9C-nvm-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 27 Oct 2022 03:41:51 GMT</pubDate>
            <description><![CDATA[<ol>
<li><p>brew로 nvm 설치</p>
<pre><code>brew install nvm</code></pre><p>macos에 <a href="https://brew.sh/index_ko">brew 설치</a>하기 </p>
</li>
<li><p>환경 변수 설정하기</p>
</li>
</ol>
<pre><code>mkdir ~/.nvm </code></pre><pre><code>vi ~/.zshrc</code></pre><p>파일을 열어서 가장 밑에 아래의 문구를 추가 해줍니다.</p>
<pre><code>export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh</code></pre><pre><code>source ~/.bash_profile # 설정 완료</code></pre><ol start="3">
<li>설치 확인<pre><code>nvm --version</code></pre>을 실행했을 때
<img src="https://velog.velcdn.com/images/ramrami-12/post/dfe0f1ea-6d1d-47dd-a0b8-8a0238be11b8/image.png" alt=""></li>
</ol>
<p>이렇게 버전이 나오면 성공!!</p>
<ol start="4">
<li>nodejs 설치 (nvm install &quot;version&quot;)<pre><code>nvm install v14</code></pre>설치 확인<pre><code>node --version
또는 node -v</code></pre><img src="https://velog.velcdn.com/images/ramrami-12/post/056560d5-ad17-44bf-b3c7-13973e484d44/image.png" alt="">
이렇게 버전이 나오면 끄읕_</li>
</ol>
<hr>
<p>맥북의 경우 터미널을 bash와 zsh로 전환할 수 있는데 
저같은 경우에는 bash에서는 환경변수 설정이 안돼서 zsh에서 설치 했습니다! 
그리고 잘 설정(또는 설치) 했는데 적용이 안되는 경우에는 터미널을 한번 껐다 켜주세요</p>
<p><a href="https://velog.io/@me2designer/M1-%EB%A7%A5%EB%B6%81-NVM-%EC%84%A4%EC%B9%98-%EC%95%88%EB%82%B4">출처</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SWEA] 벌꿀채취]]></title>
            <link>https://velog.io/@ramrami-12/%EB%AA%A8%EC%9D%98-SW-%EC%97%AD%EB%9F%89%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B2%8C%EA%BF%80%EC%B1%84%EC%B7%A8</link>
            <guid>https://velog.io/@ramrami-12/%EB%AA%A8%EC%9D%98-SW-%EC%97%AD%EB%9F%89%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B2%8C%EA%BF%80%EC%B1%84%EC%B7%A8</guid>
            <pubDate>Wed, 12 Oct 2022 07:38:43 GMT</pubDate>
            <description><![CDATA[<p>📌 <a href="https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5V4A46AdIDFAWu">문제 링크</a></p>
<p>문제 자체는 빨리 풀었는데 테케를 몇 개씩 계속 틀려서 고민했던 문제이다.
별도의 알고리즘은 사용되지 않았고,
combinations 라이브러리를 사용하였다.</p>
<p>풀이 방법)
<img src="https://velog.velcdn.com/images/ramrami-12/post/9f1e41e7-5399-4fb6-8ac7-6af334c73620/image.png" alt=""></p>
<p>NxN 벌통이 있을 때, 두 일꾼이 서로 겹치지 않게 꿀을 채집해야한다.
위의 그림에서 가장 오른쪽 경우를 어떻게 처리해야할지 고민했었는데
댓글을 보니 저런 경우는 고려하지 않아도 된다는 말이 있어서 
N개의 행에서 2개의 행을 선택할 수 있는 모든 경우의 수를 combinations으로 구하였다.</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/9ddc6841-966b-4e54-8379-319b9d32624c/image.png" alt="">
그런 다음 선택된 행에서 연속된 M개의 숫자를 선택할 수 있는 모든 경우를 이중 for문으로 구하고,
그렇게 뽑은 값들 중에 수익을 구했을 때 최댓값이 나오는 값을 찾는 방식으로 구현했다</p>
<p>변수 이름이나 코드가 다 정리되지 않았지만 제출한(해서 정답이 된) 코드는 다음과 같다.</p>
<pre><code>import sys
from itertools import combinations

sys.stdin = open(&quot;bee.txt&quot;, &quot;r&quot;)

def choice_beehive(a_worker, b_worker):
    global N, M, max_income

    # 2개의 열에서 각자 연달아 M개 벌통을 선택할 수 있는 모든 경우
    for i in range(0, N-M+1):
        for j in range(0, N-M+1):
            income = collection_honey(a_worker[i:i+M]) + collection_honey(b_worker[j:j+M])
            if income &gt; max_income:
                max_income = income

def collection_honey(beehive):
    global C, test_case

    collection = []
    max = 0

    for k in range(1, len(beehive)+1):
        candi = list(combinations(beehive, k))
        for c in candi:
            if sum(c) &lt;= C:
                collection.append(c)

    for s in collection:
        income = 0
        for p in s:
            income += pow(p, 2)
        if income &gt; max: 
            max = income

    return max


T = int(input())
for test_case in range(1, T + 1):
    max_income = 0
    beehive = []

    N, M, C = map(int, input().split()) # 벌통 크기, 선택 벌통 개수, 채취 최대 양
    colomn = [ele for ele in range(N)]

    # NxN 벌통 만들기
    for _ in range(N):
        beehive.append(list(map(int, input().split())))

    # N 열 중 2개 선택
    for a, b in combinations(colomn, 2):
        choice_beehive(beehive[a], beehive[b])

    print(f&quot;#{test_case} {max_income}&quot;)</code></pre><p>이중 for문을 굉장히 많이 돌게 되어서 아쉬운 마음이 있다..🥲</p>
<p>헤맸던 부분)
<img src="https://velog.velcdn.com/images/ramrami-12/post/db27dc01-da92-4c68-b6c1-1c8f192b6805/image.png" alt="">
처음에 구현했던 코드는 이런 경우 7+2+9가 C 값인 10보다 크므로 9를 제외한 7과 2만 선택하는 방식이었다.
하지만 위의 상황처럼 수익이 최대가 되려고 했을 때, 벌꿀을 한칸만 채취하거나 두 칸만 채취하거나 하는 경우도 모두 고려해야한다는 것을 알았다.</p>
<pre><code>for k in range(1, len(beehive)+1):
        candi = list(combinations(beehive, k))
        for c in candi:
            if sum(c) &lt;= C:
                collection.append(c)</code></pre><p>그래서 선택한 행에서 선택할 수 있는 모든 경우를 collection이라는 list에 append 하고 
collection 안을 돌면서 가장 큰 수익을 내는 짝을 찾는 방식으로 구현하였다.</p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter] 맥북으로 플러터 프로젝트 apk 배포하기 ]]></title>
            <link>https://velog.io/@ramrami-12/Flutter-%EB%A7%A5%EB%B6%81%EC%9C%BC%EB%A1%9C-%ED%94%8C%EB%9F%AC%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-apk-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/Flutter-%EB%A7%A5%EB%B6%81%EC%9C%BC%EB%A1%9C-%ED%94%8C%EB%9F%AC%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-apk-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 03 Oct 2022 10:46:33 GMT</pubDate>
            <description><![CDATA[<p>약 1년전 했던 플러터 프로젝트를 apk로 배포 하려고 한다.</p>
<p>하지만 이전에 나는 계속해서 맥북 환경에서 플러터 개발을 했고, ios 시뮬레이터로만 동작했기 때문에 안드로이드 관련 설정은 하나도 되어 있지 않은 상태였다.</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/9a20fa42-0c9d-4c42-9fab-c8dd1cf7277e/image.png" alt="">
flutter doctor 명령어 결과로도  android 환경 설정이 덜 되어 있음을 알 수 있다
(cmdline-tools component is missing)</p>
<p>그래서 일단 오랜만에 안드로이드 스튜디오를 켜서 안드로이드 설정을 마저 해주었다.</p>
<p>Preferences -&gt; Appearance &amp; Behavior -&gt; System Settings-&gt; Android SDK 에서 다음과 같이 Android SDK Command-line Tools를 선택후 apply 하면 설치 된다.</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/8ecd0b33-8df2-4461-823d-8b397af5b2a8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/8b94e9b2-4cd6-42df-b929-833d1510d08a/image.png" alt=""></p>
<p>설치 중,,</p>
<p>설치가 끝나면 </p>
<pre><code>flutter doctor --android-licenses</code></pre><p>를 한번 실행 시켜주고 flutter doctor를 다시 해본다
<img src="https://velog.velcdn.com/images/ramrami-12/post/bbac22f5-d67c-4414-bb0f-281194d6bbec/image.png" alt="">
깔-꼼</p>
<h1 id="📌-apk-배포하기">📌 APK 배포하기</h1>
<blockquote>
<h3 id="💡-index">💡 Index</h3>
<h4 id="1-display-이름-설정">1. display 이름 설정</h4>
<h4 id="2-앱-아이콘-등록"><em><del>2. 앱 아이콘 등록</del></em></h4>
<h4 id="3-앱에-디지털-서명하기">3. 앱에 디지털 서명하기</h4>
<ul>
<li>Key store 만들기</li>
<li>앱으로부터 keystore 참조하기</li>
<li>Gradle에서 서명 구성하기<h4 id="4-빌드-구성">4. 빌드 구성</h4>
<h4 id="5-apk-빌드하기">5. APK 빌드하기</h4>
</li>
</ul>
</blockquote>
<h3 id="1-display-이름-설정-1">1. display 이름 설정</h3>
<p>AndroidManifest.xml에 다음과 같이 설정해주면 된다.</p>
<pre><code>~~~
&lt;application
        android:label=&quot;marshmallow&quot;
        android:icon=&quot;@mipmap/launcher_icon&quot;&gt;
        ~~~</code></pre><p>android:label=&quot;marshmallow&quot; 이부분이 display name!</p>
<h3 id="2-앱-아이콘-등록-1"><del><em>2. 앱 아이콘 등록</em></del></h3>
<p>이 프로젝트의 경우 실 기기를 통해 테스트 한다고 앱 아이콘을 미리 등록해 뒀었다. 그래서 생략,,
<img src="https://velog.velcdn.com/images/ramrami-12/post/230d0f60-a00d-465a-a5e3-166694b7ef92/image.png" alt=""></p>
<p><a href="https://pub.dev/packages/flutter_launcher_icons">flutter_launcher_icons 패키지</a>를 사용하였다.</p>
<h3 id="3-앱에-디지털-서명하기-1">3. 앱에 디지털 서명하기</h3>
<ul>
<li><p>Key store 만들기
여기서 key store란, private key를 암호화 한 텍스트/파일 이라고 한다.</p>
<pre><code>keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key</code></pre><p>명령어를 친 후에 이런 저런 질문에 대답하면 keystore를 저장한 경로를 알려준다.</p>
</li>
<li><p>앱으로부터 keystore 참조하기
여기서부터는 공식 문서에 나와 있는 방식이 아닌, 두번째 참고링크에서 알려준대로 해봤다.</p>
</li>
</ul>
<p>먼저 Android 폴더 안에 keystore 폴더를 만들어서 key.jks를 옮겨준다.
또 keystore.password 라는 파일을 만든다
그 다음 keystore.password에 설정한 비밀번호를 넣어주고
.gitignore 파일에 /keystore 폴더를 추가해준다
<img src="https://velog.velcdn.com/images/ramrami-12/post/b2b4ec8f-3fff-4980-b7b7-bad6c4b2666a/image.png" alt="">
keyproperites는 자동으로 추가 되어 있음을 볼 수 있다.</p>
<ul>
<li>Gradle에서 서명 구성하기
이 단계 역시 공식 문서가 아닌 참고 링크에서 알려준대로 했다.</li>
</ul>
<p>android -&gt; app -&gt; build.gradle 파일에서 buildTypes 부분을 아래와 같이 수정한다.
<img src="https://velog.velcdn.com/images/ramrami-12/post/7b2a0b84-31ba-4f60-b3dc-df921320610d/image.png" alt=""></p>
<pre><code>signingConfigs {
    release {
        storeFile file(&#39;../keystore/key.jks&#39;)
        storePassword file(&#39;../keystore/keystore.password&#39;).text.trim()
        keyPassword file(&#39;../keystore/keystore.password&#39;).text.trim()
        keyAlias &#39;key&#39;
    }
}

buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}
</code></pre><h3 id="4-빌드-구성-검토하기">4. 빌드 구성 검토하기</h3>
<p>문서에 나와 있는대로 AndroidManifest.xml와 build.gradle을 검토해준다</p>
<pre><code>- 앱 매니페스트 검토하기
올바른 앱 설정을 위하여 &lt;app dir&gt;/android/app/src/main에 있는 기본 앱 매니페스트 파일인 AndroidManifest.xml을 검토하고 올바른 값들을 포함하는지 확인하세요. 특히:
application: 앱의 최종 이름을 반영하기 위해 application에 있는 android:label을 수정하세요.
uses-permission: 앱 내에서 인터넷 접근이 필요하지 않다면 android.permission.INTERNET permission을 제거하세요. 기본 템플릿에서는 Flutter 도구와 실행 중인 앱의 커뮤니케이션을 위해 해당 권한을 포함합니다.

- 빌드 구성 검토하기
올바른 빌드 구성을 위하여 &lt;app dir&gt;/android/app에 있는 기본 Gradle build file 파일인 build.gradle을 검토하고 올바른 값들을 포함하는지 확인하세요. 특히:
defaultConfig:
applicationId: 고유한 최종 (Application Id)appid를 지정하세요.
versionCode &amp; versionName: 내부 앱 버전 번호를 지정하고, 문자열 형태로 명시하세요. pubspec.yaml 파일에 version 속성을 설정하여 내부 앱 버전 번호를 문자열 형태로 지정할 수 있습니다. 버전 정보 지침에 대해서는 버전 문서를 참조하세요.
minSdkVersion &amp; targetSdkVersion: 최소 API 레벨과 개발 대상 버전으로 지정한 지정 API 레벨을 명시하세요. 자세한 내용은 버전 문서의 API 레벨 영역을 참조하세요.

출처: 공식 문서</code></pre><h3 id="5-apk-빌드하기-1">5. APK 빌드하기</h3>
<p>프로젝트의 루트 경로로 가서</p>
<pre><code>flutter build apk --split-per-abi</code></pre><p>를 실행하면 끝 ✨
공식 문서에 따르면 앱 번들을 추천한다고는 하지만 나는 apk 실행 파일이 필요하므로 apk 빌드를 해줬다.</p>
<hr>
<p>여기서부터 수많은 에러들의 향연이 펼쳐집니다 ㅠㅠ</p>
<p>Error 1)</p>
<pre><code>Flutter Fix: [!] Your project requires a newer version of the Kotlin Gradle plugin. </code></pre><p>이런 에러가 떴었는데 android 폴더안의 build.gradle에서 kotlin version을 다음과 같이 바꿔주면 된다
<a href="https://kotlinlang.org/docs/gradle.html#targeting-multiple-platforms">latest 버전 확인</a></p>
<pre><code>ext.kotlin_version = &#39;1.7.10&#39;</code></pre><p>Error 2)
Could not resolve all artifacts for configuration <del>~
에러 해결 방법 : <a href="https://young-cow.tistory.com/3">https://young-cow.tistory.com/3</a>
주의! android 폴더 안에서 ./gradlew</del> 사용하기</p>
<p><a href="https://velog.io/@g0709-19/Gradle-Could-not-find-method-compile-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95">https://velog.io/@g0709-19/Gradle-Could-not-find-method-compile-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95</a>
이 에러도 났었따,,</p>
<p>Error 3)
또 하나더 ..</p>
<pre><code>The Android Gradle plugin supports only Kotlin Gradle plugin version 1.5.20 and higher.
The following dependencies do not satisfy the required version:
project &#39;!!!&#39; -&gt; org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32</code></pre><p>와 같은 kotile gradle version 에러가 뜬다면 에러 메세지에서 몇 이상으로 하라는 버전으로 kotiln version을 바꿔주고</p>
<pre><code>buildscript {
    ext.kotlin_version = &quot;여기!!&quot;
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath &#39;com.android.tools.build:gradle:7.3.0&#39;
        classpath &quot;org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version&quot;
    }
}</code></pre><p>!!! 에 들어가는 패키지를 다시 install 해서 업데이트 해주면 된다
---&gt; 이렇게 했더니 또 버전이 너무 최신이어서 그런지 이 패키지에서 에러가 났다. kotiln과 gradle 버전이 release 된 날짜와 비슷한 시기의 버전으로 맞춰주었다.</p>
<p>이 외에도 여러 에러들이 있었는데 고치느라 정신이 없어서 다 기록해두지는 못했다..ㅠㅠ
하지만 에러들이 발생한 이유는 대부분 버전 문제였는데
gradle 버전, kotlin 버전, 플러터 버전, java 버전, 각 패키지들 버전을 적절히 맞춰줬더니 해결이 되었다
구글링 해보니 java는 11을 사용하라는 말이 많아서 11로 업데이트 시켜줬다.</p>
<p>gradle 버전은 아래 표 <a href="https://developer.android.com/studio/releases/gradle-plugin?hl=ko">참고</a></p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/3180a567-3f76-467c-a630-e16ac3cb6a37/image.png" alt=""></p>
<p>어쨌든 무사히 apk가 만들어지면</p>
<p><app dir>/build/app/outputs/apk/release/app-armeabi-v7a-release.apk
<app dir>/build/app/outputs/apk/release/app-arm64-v8a-release.apk</p>
<p>이 경로로 두개의 apk 파일이 생긴다!</p>
<p>진짜 끝..✨</p>
<p> _ ps. 안드로이드 apk 배포가 생각보다 너무 오래 걸려서(오류들 때문에..) ios의 ipa로 배포를 해볼까도 했는데 개발자 계정이 있어야 해서 포기 했다.. 하지만 참고 할 사람은 <a href="https://ios-development.tistory.com/252">여기 링크</a>를 보세용
  _</p>
<hr>
<p>참고 링크</p>
<ul>
<li><p><a href="https://flutter-ko.dev/docs/deployment/android">https://flutter-ko.dev/docs/deployment/android</a></p>
</li>
<li><p><a href="https://eunjin3786.tistory.com/295">https://eunjin3786.tistory.com/295</a></p>
</li>
<li><p><a href="https://here4you.tistory.com/198">https://here4you.tistory.com/198</a> (apk 빌드부터 참고)</p>
</li>
<li><p>gradle 에러 참고: <a href="https://stackoverflow.com/questions/68013717/could-not-find-com-android-tools-buildgradle6-7-1">https://stackoverflow.com/questions/68013717/could-not-find-com-android-tools-buildgradle6-7-1</a></p>
</li>
<li><p><a href="https://docs.gradle.org/6.7.1/release-notes.html">https://docs.gradle.org/6.7.1/release-notes.html</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter] XCode 13.3 업데이트 이후 발생하는 오류 해결하기]]></title>
            <link>https://velog.io/@ramrami-12/Flutter-XCode-13.3-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EC%9D%B4%ED%9B%84-%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/Flutter-XCode-13.3-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EC%9D%B4%ED%9B%84-%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 27 Sep 2022 02:15:27 GMT</pubDate>
            <description><![CDATA[<p>예전에 만들었던 flutter 프로젝트를 리팩토링 해서 교내 대회에 내려고 했는데
약 1년 만에 빌드해 보니 다음과 같은 에러가 발생했다</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/f63cbe3a-424f-46bc-8497-a2c3a21659d9/image.png" alt=""></p>
<p>구글링 해보니 <strong>Xcode가 업데이트 되면서 발생한 문제</strong> 같았다
먼저  .zshrc 파일에 export를 추가하는 방법을 시도해봤다.</p>
<pre><code>xcrun -sdk macosx --show-sdk-path </code></pre><pre><code>export SDKROOT=/Applications/~~~(위 명령어를 쳐서 나온 path를 입력하면 된다)</code></pre><pre><code>source ~/.zshrc</code></pre><pre><code>xcrun -sdk macosx --show-sdk-version</code></pre><p>그래도 해결이 되지 않았다 ..</p>
<p>다음 해결 방법으로 xcode command line tools를 다시 설치하는 방법이 있었다. 
(나는 삭제하고 다시 설치 했다)</p>
<p>uninstall(삭제) 하는 법</p>
<pre><code>sudo rm -rf /Library/Developer/CommandLineTools</code></pre><p>다시 설치</p>
<pre><code>xcode-select --install
sudo xcode-select -s /Library/Developer/CommandLineTools</code></pre><p>그런데 갑자기 잘 되던 ios 시뮬레이터가 연결이 되지 않게 됐다,,
크롬으로만 빌드가 됨 ㅠㅠ
그래서 ios 파일의 podfile.lock 파일을 지우는 등 (<a href="https://bebesoft.tistory.com/36">참고</a>) 의존성을 최신화 했더니</p>
<p>LoadError - dlopen(/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.5/lib/ffi_c.bundle, 0x0009): tried: &#39;/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.5/lib/ffi_c.bundle&#39; (mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e))) - /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.5/lib/ffi_c.bundle</p>
<p>이런 에러가 떴고 M1 맥북 문제 인 것 같아서</p>
<pre><code>sudo gem install ffi </code></pre><p>를 입력해줬다. (<a href="https://effectivecode.tistory.com/1583">참고</a>)</p>
<pre><code>sudo arch -x86_64 gem install ffi</code></pre><pre><code>arch -x86_64 pod install</code></pre><p>--&gt; M1인 경우 위와 같은 명령어로 pod install 실행하기!! **</p>
<p>그래도 안되서 구글링 해본 결과 command line tools를 다시 선택해서 세팅이 유실 된 것 같았다
preferences =&gt; locations 에서 다시 넣어주니까 이제 ios 시뮬레이터는 다시 나온다,,</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/1fe59246-e8f1-4134-8eef-4a5214005ab0/image.png" alt=""></p>
<p>왕,, 됐다 ㅠㅠㅠ</p>
<p><img src="https://velog.velcdn.com/images/ramrami-12/post/418d98e7-0a01-46cb-998f-72d5d90479b9/image.png" alt=""></p>
<p>결과적으로 문제는 xcode 업데이트 + M1 문제 였고 나오는 에러마다 하나씩 해결했더니 해결이 되었다 !!!</p>
<p>오늘의 기록 끝_</p>
<hr>
<p>참고 링크</p>
<ul>
<li><a href="https://stackoverflow.com/questions/71320584/flutter-build-ios-got-error-requested-but-did-not-find-extension-point-with-ide">https://stackoverflow.com/questions/71320584/flutter-build-ios-got-error-requested-but-did-not-find-extension-point-with-ide</a></li>
<li><a href="https://mac.install.guide/commandlinetools/6.html">https://mac.install.guide/commandlinetools/6.html</a></li>
<li><a href="https://mac.install.guide/commandlinetools/7.html">https://mac.install.guide/commandlinetools/7.html</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023 KAKAO BLIND RECRUITMENT 1차 코딩테스트 짧은 후기]]></title>
            <link>https://velog.io/@ramrami-12/2023-KAKAO-BLIND-RECRUITMENT-1%EC%B0%A8-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A7%A7%EC%9D%80-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/2023-KAKAO-BLIND-RECRUITMENT-1%EC%B0%A8-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A7%A7%EC%9D%80-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 26 Sep 2022 03:21:47 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ramrami-12/post/3f08db69-e83a-4f6f-b91d-0707df69d7e1/image.png" alt=""></p>
<p>본격적으로 취업을 준비하게 되면서 경험 삼아 카카오 코딩 테스트를 응시하게 되었다.</p>
<p>결과적으로 가장 쉬운 첫번째 문제 문자열 밖에 풀지 못했다
이모티콘 문제를 풀어보려고 했으나 실패하고,,
나는 알고리즘 쪼렙(?)임을 강렬하게 느끼고 열심히 공부해야겠다는 생각과 함께 첫 코딩 테스트를 마쳤다</p>
<p>다음 후기 포스팅을 할 때는 더 발전한 실력이 되어 있기를 🔥</p>
<ul>
<li>코테 이후 읽었던 후기 포스팅
<a href="https://kth990303.tistory.com/379">https://kth990303.tistory.com/379</a>
<a href="https://seyun0501.tistory.com/50">https://seyun0501.tistory.com/50</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2022 KAKAO BLIND RECRUITMENT] 신고 결과 받기]]></title>
            <link>https://velog.io/@ramrami-12/2022-KAKAO-BLIND-RECRUITMENT-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@ramrami-12/2022-KAKAO-BLIND-RECRUITMENT-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Wed, 21 Sep 2022 05:45:31 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>문제 링크
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/92334">https://school.programmers.co.kr/learn/courses/30/lessons/92334</a></p>
</li>
<li><p>코드 (python)</p>
<pre><code>def solution(id_list, report, k):
  answer = []
  report_dict = {}
  for id in id_list:
      report_dict[id] = []
      answer.append(0)
  for r in report:
      report_person = r.split(&quot; &quot;)[0]
      reported_person = r.split(&quot; &quot;)[1]
      if report_person in report_dict[reported_person]:
          pass
      else:
          report_dict[reported_person].append(
              report_person)

  for key, value in report_dict.items():
      if len(value) &gt;= k:
          for val in value:
              answer[id_list.index(val)] += 1

  return answer</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[나의 React 메모]]></title>
            <link>https://velog.io/@ramrami-12/%EB%82%98%EC%9D%98-React-%EC%95%8C%EC%93%B8%EC%8B%A0%EC%9E%A1-%EA%B0%9C%EC%9D%B8-%ED%8F%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@ramrami-12/%EB%82%98%EC%9D%98-React-%EC%95%8C%EC%93%B8%EC%8B%A0%EC%9E%A1-%EA%B0%9C%EC%9D%B8-%ED%8F%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 07 Jul 2022 08:56:21 GMT</pubDate>
            <description><![CDATA[<pre><code>&quot;rules&quot;: {
   &quot;no-unused-vars&quot;: &quot;off&quot;
 }
출처: https://jainn.tistory.com/324 [Dogfootruler Kim:티스토리]</code></pre><hr>
<p><code>npm cache verify</code></p>
<hr>
<p>Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of DomWrapper which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here
<a href="https://wazacs.tistory.com/36">https://wazacs.tistory.com/36</a></p>
<hr>
<p>Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
react.development.js:1618 Uncaught TypeError: Cannot read properties of null (reading &#39;useContext&#39;)</p>
<p>맨 윗줄에 function <del>()를 선언하고 코드 맨 아래에 export default ~</del>()이런 식으로 했더니 난 에러
다시 맨 윗줄에 export default function ~~()로 고침</p>
<hr>
<p>font site:
<a href="https://noonnu.cc/index">https://noonnu.cc/index</a> </p>
]]></description>
        </item>
    </channel>
</rss>