<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>frog_dev.log</title>
        <link>https://velog.io/</link>
        <description>신입 개발자</description>
        <lastBuildDate>Sun, 03 Nov 2024 12:07:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>frog_dev.log</title>
            <url>https://velog.velcdn.com/images/frog_dev/profile/03bf00c7-7bfe-4d25-b10a-2f5fb312c7af/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. frog_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/frog_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Vue3] V-Model 사용시 Refs와 Definemodel의 차이점 ]]></title>
            <link>https://velog.io/@frog_dev/Vue3-V-Model-%EC%82%AC%EC%9A%A9%EC%8B%9C-Refs%EC%99%80-Definemodel%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
            <guid>https://velog.io/@frog_dev/Vue3-V-Model-%EC%82%AC%EC%9A%A9%EC%8B%9C-Refs%EC%99%80-Definemodel%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</guid>
            <pubDate>Sun, 03 Nov 2024 12:07:32 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Vue 3에서는 다양한 반응형 상태 관리 방식이 제공되며, 그중에서도 v-model, ref, 그리고 defineModel은 데이터를 다루는 데 중요한 역할을 합니다. 이 글에서는 각 개념의 역할과 차이점을 설명하고, 각각을 언제 사용하는 것이 적절한지에 대해 다룹니다.</p>
</blockquote>
<h1 id="1-v-model이란">1. V-Model이란?</h1>
<p>v-model은 Vue에서 양방향 바인딩을 쉽게 구현하기 위해 사용되는 디렉티브입니다. v-model을 사용하면 HTML 입력 요소와 Vue의 데이터가 자동으로 동기화됩니다. 예를 들어, 사용자가 입력한 텍스트가 Vue의 데이터 속성에 자동으로 반영되고, 반대로 Vue의 데이터 속성이 변경되면 입력 필드에도 즉시 반영됩니다.</p>
<pre><code class="language-javascript">&lt;template&gt;
  &lt;input v-model=&quot;username&quot; placeholder=&quot;사용자 이름을 입력하세요&quot; /&gt;
&lt;/template&gt;

&lt;script&gt;
import { ref } from &#39;vue&#39;;

export default {
  setup() {
    const username = ref(&#39;&#39;);
    return { username };
  },
};
&lt;/script&gt;</code></pre>
<p>위 예시에서 v-model을 사용하여 username이란 변수와 &quot;input&quot; 요소의 값을 양방향으로 바인딩합니다. 사용자가 &quot;input&quot; 에 값을 입력하면 username 변수에 즉시 반영됩니다.</p>
<hr>
<p>[ <em>Vue3 공식 문서에서 제시된 V-model 사용방법</em> ]</p>
<p><img src="https://velog.velcdn.com/images/frog_dev/post/7b20a37c-5d8d-4041-beea-58315c302a8b/image.png" alt=""></p>
<hr>
<h3 id="refs와-definemodel의-차이점은-무엇인가">Refs와 DefineModel의 차이점은 무엇인가?</h3>
<p>다음은 이 글을 작성하게 된 이유입니다.   공식 문서에서는 Definemodel을 사용하여 model을 형성하고, 이를 바탕으로 html입력요소와 바인딩을 진행하고 있습니다. 하지만, 어떤 경우에 Refs를 사용하고, 어떤 경우에 defineModel()을 통해 model을 정의해야 하는지에 대해 정리하고 싶었습니다. </p>
<h3 id="ref란">ref란?</h3>
<p>ref는 Vue의 Composition API에서 반응형 상태를 만들기 위해 사용하는 함수입니다. ref로 생성한 변수는 단일 값에 대해 반응형 속성을 가지며, Vue가 그 값을 추적하여 값이 변경될 때마다 컴포넌트를 다시 렌더링합니다. 주로 단일 컴포넌트 내부에서의 상태 관리에 사용됩니다.</p>
<p>ref를 사용하여 입력 필드에 반응형 상태를 설정할 수 있습니다.</p>
<h3 id="definemodel이란">defineModel이란?</h3>
<p>defineModel은 Vue 3에서 자식 컴포넌트가 부모 컴포넌트로부터 전달받는 데이터를 양방향 바인딩할 수 있도록 하는 함수입니다. 주로 부모와 자식 컴포넌트 간의 데이터 바인딩을 위해 사용되며, 부모가 전달한 데이터를 자식이 수정할 수 있게 합니다.</p>
<p>예를 들어, 부모 컴포넌트에서 v-model을 통해 username을 자식 컴포넌트에 전달하고, 자식 컴포넌트는 defineModel을 통해 이 값을 받을 수 있습니다.</p>
<h3 id="ref와-definemodel의-차이점">ref와 defineModel의 차이점</h3>
<ul>
<li><p>ref: 주로 단일 컴포넌트 내의 상태 관리에 사용됩니다. 입력 필드의 값을 반응형으로 관리하거나 컴포넌트 내부의 데이터를 바인딩할 때 사용됩니다.</p>
</li>
<li><p>defineModel: 주로 부모-자식 컴포넌트 간의 데이터 바인딩을 위해 사용됩니다. 자식 컴포넌트에서 부모의 데이터를 직접 수정해야 할 때 사용하며, v-model을 통해 양방향 바인딩을 제공합니다.</p>
</li>
</ul>
<p><strong>언제 무엇을 사용해야 할까?</strong></p>
<blockquote>
<p>단일 컴포넌트 내부에서의 상태 관리가 필요하면 ref를 사용합니다. 예를 들어, 로그인 폼에서 사용자 ID와 비밀번호를 반응형으로 관리하는 경우 ref를 사용하는 것이 적합합니다. 부모-자식 컴포넌트 간의 양방향 바인딩이 필요하다면 defineModel을 사용합니다. 자식 컴포넌트가 부모로부터 받은 데이터를 수정할 필요가 있을 때 유용합니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[로그인 기능은 어떻게 구현하나요?(이론)]]></title>
            <link>https://velog.io/@frog_dev/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B8%B0%EB%8A%A5%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EA%B5%AC%ED%98%84%ED%95%98%EB%82%98%EC%9A%94%EC%9D%B4%EB%A1%A0</link>
            <guid>https://velog.io/@frog_dev/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B8%B0%EB%8A%A5%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EA%B5%AC%ED%98%84%ED%95%98%EB%82%98%EC%9A%94%EC%9D%B4%EB%A1%A0</guid>
            <pubDate>Thu, 17 Oct 2024 01:07:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>✅ <strong>들어가며</strong>
웹 서비스에서 인증은 필수적인 기능입니다. 특히 사용자의 로그인 과정은 단순한 인증을 넘어 보안, 확장성, 유지관리성과 밀접하게 연관되어 있습니다. 이번 글에서는 로그인 기능 구현의 기본 흐름부터 세션과 JWT의 차이, 저장 방식, 토큰 재발급, 혼합 사용 사례까지 정리해보았습니다.</p>
</blockquote>
<h3 id="1-로그인-기능의-구현-흐름">1. 로그인 기능의 구현 흐름</h3>
<p>로그인 기능은 다음과 같은 순서로 구현됩니다:</p>
<ol>
<li>사용자 입력 검증</li>
</ol>
<ul>
<li>이메일, 비밀번호 등 입력값의 유효성 검사</li>
<li>포맷 오류 시 적절한 에러 메시지 반환</li>
</ul>
<ol start="2">
<li>인증 처리</li>
</ol>
<ul>
<li>DB에서 사용자 정보 조회 및 비밀번호 일치 확인</li>
<li>일치 시 인증 성공, 불일치 시 실패</li>
</ul>
<ol start="3">
<li>세션 or 토큰 발급</li>
</ol>
<ul>
<li>인증 성공 시 서버는 세션을 생성하거나 JWT를 발급</li>
</ul>
<ol start="4">
<li>클라이언트 저장</li>
</ol>
<ul>
<li>세션 ID 또는 JWT를 클라이언트에 저장 (쿠키, 로컬스토리지 등 활용)</li>
</ul>
<ol start="5">
<li>인증 유지</li>
</ol>
<ul>
<li>이후 요청 시 저장된 세션 ID나 JWT로 인증 유지</li>
</ul>
<h3 id="2-세션-vs-jwt">2. 세션 vs JWT</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>세션(Session)</th>
<th>JWT (JSON Web Token)</th>
</tr>
</thead>
<tbody><tr>
<td>저장 위치</td>
<td>서버 (세션 데이터), 클라이언트는 세션 ID만 보관</td>
<td>클라이언트가 토큰 전체를 보관</td>
</tr>
<tr>
<td>확장성</td>
<td>서버 상태 유지 필요 → 서버 부하, 분산 처리 어려움</td>
<td>서버 스테이트리스 → 확장성에 유리</td>
</tr>
<tr>
<td>보안성</td>
<td>서버에서 직접 관리 → 상대적으로 안전</td>
<td>클라이언트에 저장되므로 탈취 위험 있음</td>
</tr>
<tr>
<td>사용 예시</td>
<td>로그인 후 세션 ID를 쿠키로 보냄</td>
<td>로그인 후 JWT 토큰을 쿠키 또는 로컬스토리지에 저장</td>
</tr>
</tbody></table>
<h3 id="3-jwt의-구조">3. JWT의 구조</h3>
<p>JWT는 Header.Payload.Signature 형식으로 구성됩니다.</p>
<ul>
<li>Header: 토큰 타입과 서명 알고리즘 (예: {&quot;alg&quot;: &quot;HS256&quot;, &quot;typ&quot;: &quot;JWT&quot;})</li>
<li>Payload: 사용자 정보 및 클레임 포함 (예: sub, iat, exp 등)</li>
<li>Signature: Header + Payload에 비밀 키로 서명하여 생성</li>
</ul>
<p>⚠️ 주의:</p>
<ul>
<li>alg: none 사용 금지</li>
<li>비밀 키는 예측 불가한 값으로 설정</li>
</ul>
<h3 id="4-토큰-저장-위치-쿠키-vs-스토리지">4. 토큰 저장 위치: 쿠키 vs 스토리지</h3>
<p>저장 방식    장점    단점
쿠키    - 자동으로 요청에 포함됨</p>
<ul>
<li>HttpOnly, Secure 설정 가능    - CSRF 공격에 취약</li>
<li>용량 제한 있음
로컬/세션 스토리지    - CSRF에 안전</li>
<li>용량이 비교적 큼    - XSS에 취약</li>
<li>HttpOnly 설정 불가 → JS 접근 가능</li>
</ul>
<p>✔ 보안이 중요한 인증 정보는 일반적으로 HttpOnly 쿠키 사용을 권장합니다.</p>
<h3 id="5-토큰-재발급-시점은">5. 토큰 재발급 시점은?</h3>
<ul>
<li><p>Access Token 만료 직전: 백그라운드에서 갱신</p>
</li>
<li><p>Refresh Token 보유 시: refresh로 새로운 access 토큰 발급</p>
</li>
<li><p>이상 활동 탐지 시: 기기 변경, 위치 변경 등에서 재인증 요구</p>
</li>
</ul>
<h3 id="6-jwt와-세션을-함께-사용하는-방법은">6. JWT와 세션을 함께 사용하는 방법은?</h3>
<p>하이브리드 접근 방식으로 다음과 같이 사용합니다:</p>
<ul>
<li>JWT로 인증 처리: 클라이언트는 JWT를 보관, 요청 시 인증용으로 전송</li>
<li>세션으로 상태 관리: 서버는 세션에 사용자 상태, 권한, 설정 등을 저장</li>
</ul>
<p>📌 이 방식은 인증은 무상태(stateless)로, 상태 관리는 서버에서 이루어져 보안성과 확장성의 균형을 맞춥니다.</p>
<p>✍️ 마치며
로그인 기능은 단순한 기술 구현을 넘어 보안, 사용자 경험, 서비스 구조 전반에 영향을 주는 핵심 기능입니다. 세션과 JWT 각각의 특징을 이해하고, 서비스의 규모와 특성에 따라 적절히 선택하거나 조합하는 것이 중요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[세션과 쿠키란 무엇인가]]></title>
            <link>https://velog.io/@frog_dev/%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@frog_dev/%EC%84%B8%EC%85%98%EA%B3%BC-%EC%BF%A0%ED%82%A4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Wed, 16 Oct 2024 07:41:19 GMT</pubDate>
            <description><![CDATA[<h1 id="세션이란">세션이란?</h1>
<hr>
<p>세션은 사용자와 서버 간의 일시적인 연결을 유지하며, 주로 인증 상태를 관리하는데 사용됩니다. 프론트엔드에서는 세션 토큰을 이용하여 사용자를 인증하고, 서버와의 상호작용 시 세션이 유지되도록 설정합니다.
ex) JSON Web Token(JWT) 같이 토큰 기반 인증도 세션 관리의 일종으로 이해할 수 있으며, 로컬 스토리지 또는 세션 스토리지에 토큰을 저장해 인증 상태를 관리하는 방법을 익히는 것이 중요합니다. </p>
<hr>
<h4 id="_로컬-스토리지-vs-세션-스토리지-_">_<strong>로컬 스토리지 vs 세션 스토리지</strong> _</h4>
<p><strong>로컬 스토리지의 주요 차이점</strong> </p>
<ol>
<li>브라우저를 닫거나, 컴퓨터를 재부팅해도 데이터가 삭제되지 않는다.</li>
<li>사용자가 명시적으로 데이터를 삭제하거나 브라우저 캐시를 지우지 않는 한, 데이터를 계속 유지한다. </li>
<li>장기적으로 필요한 데이터, 예를 들어 사용자 설정, 사용자 선호도 등을 저장할때 이용된다. </li>
</ol>
<p><strong>세션 스토리지의 차이점</strong></p>
<ol>
<li>브라우저 탭 또는 창의 세션이 종료되면 데이터가 삭제됩니다. 해당 탭이나 창을 닫으면 데이터가 사라진다.</li>
<li>특정 세션에서만 필요한 데이터를 저장하는데 적합합니다. 예를 들면, 잠깐 동안만 필요한 폼 데이터나 임시 상태 데이터를 저장할때 사용됩니다. </li>
</ol>
<p>로컬 스토리지와 세션 스토리지는 대부분의 브라우저에서 5MB 정도의 데이터를 저장할 수 있는데, 로컬 스토리지와 세션 스토리지 모두 사용 가능한 공간은 브라우저나 장치에 따라 다를 수 있습니다. HTTP요청과 함께 서버로 전송되지 않으므로, 상대적으로 넉넉한 용량을 사용할 수 있습니다. (쿠키보다 넉넉한 용량)</p>
<h4 id="그렇다면-로컬-스토리지와-세션-스토리지는-어디에-어떤-형태로-저장되는가">그렇다면 로컬 스토리지와 세션 스토리지는 어디에 어떤 형태로 저장되는가?</h4>
<ol>
<li>로컬스토리지(Local Storage)</li>
</ol>
<ul>
<li>브라우저의 프로필 폴더 내에 위치한 특정 파일에 저장되는 형태, 브라우저마다 다르지만 일반적으로 Chrome에서는 Local Storage 폴더에 SQLite 데이터베이스 형식으로 저장됩니다.
개발자도구 &gt; application &gt; localstroage에서 확인 가능
<img src="https://velog.velcdn.com/images/frog_dev/post/7a710d48-f62f-4bd4-a9da-34d6930a5939/image.png" alt=""></li>
<li>각 도메인마다 별도로 저장되며, 데이터는 문자열 형식으로 저장됩니다. 즉 저장하려는 데이터가 숫자, 객체, 배열이라도 문자열로 변환하여 저장해야 합니다. 불러올 때는 JSON.parse로 다시 객체로 변환하는 것이 일반적입니다.</li>
</ul>
<ol start="2">
<li>세션 스토리지(Session Storage)</li>
</ol>
<ul>
<li>브라우저 메모리에 임시로 저장됩니다. 로컬 스토리지와 달리 브라우저 세션 동안만 유지되기 때문에 하드디스크에 별도로 저장되지 않습니다. </li>
<li>로컬 스토리지와 마찬가지로 문자열 형식으로 데이터를 저장합니다.</li>
</ul>
<pre><code>// 저장
const user = { name: &#39;David&#39;, age: 30 };
localStorage.setItem(&#39;user&#39;, JSON.stringify(user));
// 불러오기 
const savedUser = JSON.parse(localStorage.getItem(&#39;user&#39;));</code></pre><hr>
<h1 id="쿠키cookie란">쿠키(Cookie)란?</h1>
<p>쿠키는 사용자의 브라우저에 작은 데이터를 저장하고, 주로 세션 유지와 사용자 식별 추적에 활용됩니다. 프론트엔드에서는 쿠키에 접근해 필요한 데이터를 읽거나 쓸 수 있으며, document.cookie를 통해 다룰 수 있습니다. 쿠키 설정 시 보안 옵션을 이해하는 것이 중요합니다. 예를 들어, HttpOnly, Secure, SameSite 속성을 설정해 보안을 강화할 수 있습니다. </p>
<p><em>쿠키설정이란?</em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python: input(), sys.stdin.readline()의 차이 ]]></title>
            <link>https://velog.io/@frog_dev/python-input-sys.stdin.readline%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@frog_dev/python-input-sys.stdin.readline%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Mon, 16 Sep 2024 13:16:41 GMT</pubDate>
            <description><![CDATA[<h3 id="input">input()</h3>
<p>기능: 표준 입력에서 한 줄의 문자열을 읽어옵니다.
사용법: input() 함수는 사용자가 입력한 한 줄의 문자열을 반환합니다.
<strong>자동 개행 제거</strong>: input() 함수는 입력된 문자열의 끝에 있는 개행 문자(\n)를 자동으로 제거합니다.
편리성: 간단한 입력을 받을 때 사용하기 편리합니다.
속도: sys.stdin.readline()에 비해 상대적으로 느립니다. 특히 많은 양의 입력을 받을 때 차이가 커집니다.</p>
<pre><code class="language-python"># input()을 사용하여 입력받기
n = int(input())  # 정수 입력
data = input().split()  # 공백으로 구분된 문자열 입력</code></pre>
<h3 id="sysstdinreadline">sys.stdin.readline()</h3>
<p>기능: 표준 입력에서 한 줄의 문자열을 읽어옵니다.
사용법: sys.stdin.readline() 함수는 입력된 한 줄의 문자열을 그대로 반환합니다.
<strong>개행 문자 포함</strong>: sys.stdin.readline() 함수는 입력된 문자열의 끝에 있는 개행 문자(\n)를 포함하여 반환합니다. 따라서 필요에 따라 개행 문자를 제거해야 합니다.
속도: input()에 비해 빠릅니다. 특히 많은 양의 입력을 받을 때 유리합니다.
사용 예: 많은 양의 데이터를 빠르게 입력받아야 할 때 사용합니다.</p>
<pre><code class="language-python">import sys
# sys.stdin.readline()을 사용하여 입력받기
n = int(sys.stdin.readline().strip())  # 정수 입력
data = sys.stdin.readline().strip().split()  # 공백으로 구분된 문자열 입력</code></pre>
<p>알고리즘을 풀다보면, 가끔 입력값을 제대로 받지 않아서 시간초과가 발생하곤 한다.</p>
<h2 id="시간초과는-입력받는-방식에-따라-다른데-왜-속도의-차이가-발생하는-걸까">시간초과는 입력받는 방식에 따라 다른데, 왜 속도의 차이가 발생하는 걸까?</h2>
<h3 id="1-버퍼링-방식">1. 버퍼링 방식</h3>
<p><strong>input():</strong>
input() 함수는 표준 입력에서 한 줄을 읽어올 때 내부적으로 많은 작업을 수행합니다. </p>
<ul>
<li>입력을 받을 때마다 표준 입력 스트림을 버퍼링하고, 개행 문자를 제거하는 등의 추가 작업을 수행합니다.</li>
<li>이러한 추가 작업들은 입력을 받을 때마다 반복되므로, 많은 양의 데이터를 처리할 때 시간이 더 많이 소요됩니다.</li>
</ul>
<p><strong>sys.stdin.readline():</strong></p>
<ul>
<li>sys.stdin.readline() 함수는 표준 입력에서 한 줄을 읽어올 때, 단순히 입력 스트림에서 데이터를 읽어옵니다.</li>
<li>개행 문자를 포함한 전체 문자열을 반환하므로, 추가적인 처리가 필요하지 않습니다.
따라서, 입력을 받을 때마다 반복되는 작업이 적고, 더 빠르게 동작합니다.<h3 id="2-함수-호출-오버헤드">2. 함수 호출 오버헤드</h3>
</li>
<li><em>input():*</em>
input() 함수는 Python의 내장 함수로, 호출 시 추가적인 오버헤드가 발생합니다. 특히, 많은 양의 데이터를 처리할 때 이러한 오버헤드가 누적되어 성능에 영향을 미칠 수 있습니다.</li>
</ul>
<p><strong>sys.stdin.readline():</strong>
sys.stdin.readline() 함수는 표준 입력 스트림에서 직접 데이터를 읽어오므로, 함수 호출 오버헤드가 상대적으로 적습니다. 따라서, 많은 양의 데이터를 처리할 때 더 효율적입니다.</p>
<h3 id="3-개행-문자-처리">3. 개행 문자 처리</h3>
<p><strong>input():</strong>
input() 함수는 입력된 문자열의 끝에 있는 개행 문자(\n)를 자동으로 제거합니다. 이 과정에서 추가적인 문자열 처리가 필요하며, 이는 성능에 영향을 미칠 수 있습니다.</p>
<p><strong>sys.stdin.readline():</strong>
sys.stdin.readline() 함수는 개행 문자를 포함한 전체 문자열을 반환하므로, 추가적인 처리가 필요하지 않습니다. 필요에 따라 개행 문자를 제거할 수 있지만, 이는 사용자가 명시적으로 처리할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ 백준_19637_파이썬]]></title>
            <link>https://velog.io/@frog_dev/%EB%B0%B1%EC%A4%8019637%ED%8C%8C%EC%9D%B4%EC%8D%AC</link>
            <guid>https://velog.io/@frog_dev/%EB%B0%B1%EC%A4%8019637%ED%8C%8C%EC%9D%B4%EC%8D%AC</guid>
            <pubDate>Mon, 16 Sep 2024 11:21:12 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-핵심">문제 핵심</h3>
<p><strong>주어진 것</strong></p>
<ol>
<li>각 전투력 별 칭호</li>
<li>N과 M의 범위</li>
<li>전투력 별 칭호가 주어지는 순서(비내림차순)
<em>내림차순이 아님</em></li>
<li>N과 M의 범위</li>
</ol>
<p><strong>알고리즘</strong>
전투력에 따른, 칭호 </p>
<p><strong>출력</strong>
칭호만 출력</p>
<h3 id="구현">구현</h3>
<ol>
<li>전투력 별 칭호를 저장한다. (같은 전투력이면 먼저 입력된 칭호를 출력한다.)</li>
<li>전투력이 입력되면 칭호를 print한다. </li>
</ol>
<p>생각보다 간단한 구현 문제라고 생각했지만, 세 번의 시간초과를 겪었다. </p>
<ul>
<li>N과 M의 범위를 확인해야 했다.
입력받은 전투력 별로 칭호를 확인하자 갯수가 최대 N * M = 10^5 * 10^5 = 10^10이 걸렸다. </li>
<li>중복으로 입력된다면 먼저 입력된 칭호를 반환해야 한다. </li>
</ul>
<ol>
<li>set으로 중복 입력값을 걸러서 저장(칭호와 전투력 저장단계에서)</li>
<li>print할때 가장 첫번째를 반환(출력시 저장된 값 중 첫번째 꺼 출력) </li>
</ol>
<p>-&gt; set의 크기를 늘리는 것(출력시 set조회) vs <strong>set의 크기를 애초에 줄이는 것(저장시 set 조회)</strong></p>
<p>시간 복잡도 상에서는 둘이 동일하지만, 후자의 방식이 리스트를 더욱 간결하게 만들어 유지하므로 후자의 방식을 선택하였습니다. </p>
<h3 id="놓칠-수-있는-부분">놓칠 수 있는 부분</h3>
<ol>
<li>전투력이 같은 칭호가 있다면, 먼저 입력된 칭호 반환 </li>
<li>brute force로 구현하면 시간 초과가 나온다. (N과 M의 범위를 확인)</li>
<li>sys.stdin.readline으로 읽지 않고 input()으로 읽게되면 시간초과가 나온다. </li>
</ol>
<pre><code class="language-python">import sys
input = sys.stdin.readline

# N: number of titles, M: number of characters
N, M = map(int, input().split())

title_power = []
seen_powers = set()
for _ in range(N):
    title, power = input().split()
    power = int(power)
    if power not in seen_powers:
        title_power.append((power, title))
        seen_powers.add(power)

# Sort the list by power values
title_power.sort()

def binary_search(power):
    left, right = 0, len(title_power) - 1
    while left &lt;= right:
        mid = (left + right) // 2
        if title_power[mid][0] &gt;= power:
            right = mid - 1
        else:
            left = mid + 1
    return title_power[left][1] if left &lt; len(title_power) else &#39;No suitable title&#39;

for _ in range(M):
    power = int(input())
    print(binary_search(power))</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준_1343_파이썬]]></title>
            <link>https://velog.io/@frog_dev/%EB%B0%B1%EC%A4%801343%ED%8C%8C%EC%9D%B4%EC%8D%AC</link>
            <guid>https://velog.io/@frog_dev/%EB%B0%B1%EC%A4%801343%ED%8C%8C%EC%9D%B4%EC%8D%AC</guid>
            <pubDate>Mon, 16 Sep 2024 02:50:27 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-핵심">문제 핵심</h3>
<p><strong>주어진 것</strong>
두개의 폴리오미노 AAAA, BB </p>
<p><strong>알고리즘</strong>
&#39;X&#39;와 &#39;.&#39;으로 주어진 보드 판을 덮는다. </p>
<p><strong>출력</strong>
폴리오미노로 덮은 보드판을 출력한다. </p>
<h3 id="구현">구현</h3>
<ol>
<li>&#39;X&#39;와  &#39;.&#39;가 주어진다. </li>
<li>주어진 폴리오미노 2개로 덮을 수 있는 것은 연속된 X<em>4 혹은 X</em>2 뿐이다. (2의 배수)</li>
<li>덮을 수 없다면 -1 을 리턴한다. </li>
</ol>
<p><em>X를 마주하면 stack에 넣고, .을 마주하면 stack에 있는 board를 폴리오미노로 덮는다. stack에 들어있는 board의 갯수가 2의 배수가 아니라면 폴리오미노로 덮을 수 없는 입력이니 -1을 출력, 덮을 수 있다면 덮어서 answer에 저장</em></p>
<h3 id="놓칠-수-있는-부분">놓칠 수 있는 부분</h3>
<p>for 문으로 board를 돌리면, 마지막 케이스에 대한 처리를 따로 해줘야하는 경우가 생길 수도 있다. </p>
<pre><code class="language-python">def process_stack(stack, answer):
    if len(stack) % 2 != 0:
        print(-1)
        exit()
    answer.append(&#39;AAAA&#39; * (len(stack) // 4))
    if len(stack) % 4 != 0:
        answer.append(&#39;BB&#39;)

board = list(input())
answer = []
stack = []

for letter in board:
    if letter == &#39;X&#39;:
        stack.append(letter)
    else:
        if stack:
            process_stack(stack, answer)
            stack = []
        answer.append(&#39;.&#39;)

if stack:
    process_stack(stack, answer)

print(&#39;&#39;.join(answer))</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400]]></title>
            <link>https://velog.io/@frog_dev/error-RPC-failed-HTTP-400-curl-22-The-requested-URL-returned-error-400</link>
            <guid>https://velog.io/@frog_dev/error-RPC-failed-HTTP-400-curl-22-The-requested-URL-returned-error-400</guid>
            <pubDate>Mon, 19 Aug 2024 01:15:38 GMT</pubDate>
            <description><![CDATA[<h1 id="error-message">error message</h1>
<p>error: RPC failed; HTTP 400 curl 22 The requested URL returned error: 400</p>
<h1 id="solution">Solution</h1>
<p>git config --global http.postBuffer 524288000</p>
<h1 id="why">Why?</h1>
<p>Large pushes can sometimes cause issues due to buffer limits. Try increasing the Git HTTP post buffer. The commnad increases the buffer to 500MB, which might resolve the issue if it’s related to the size of the data being pushed.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[간단한 터미널 사용법 정리 ]]></title>
            <link>https://velog.io/@frog_dev/%EA%B0%84%EB%8B%A8%ED%95%9C-%ED%84%B0%EB%AF%B8%EB%84%90-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@frog_dev/%EA%B0%84%EB%8B%A8%ED%95%9C-%ED%84%B0%EB%AF%B8%EB%84%90-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 23 Jan 2024 02:12:41 GMT</pubDate>
            <description><![CDATA[<h3 id="간단한-터미널-명령어-정리">간단한 터미널 명령어 정리</h3>
<pre><code>ls: listSegments 현재 위치에 있는 파일 목록 조회
ls -al: 파일 목록을 상세하게 모두 출력 
cd: changeDirectory 디렉토리 이동 
pwd: 현재 경로 화인 
mkdir: 신규 디렉토리 생성 
rmdir: 디렉토리 삭제
rm: 파일이나 디렉토리 삭제
rm -r: 하위 디렉토리 삭제
rm -f: 강제로 삭제 
mv: 파일 이름 변경 및 이동 
mv /folderA/fileA.txt / folderB/fileB.txt: folderA의 fileA.txt파일을 fodlerB로 옮기고 파일명을 fileB.txt로 변경
touch: 용량 0의 파일 생성 
clear: 파일을 clear함 
</code></pre><h3 id="쉘이란">쉘이란?</h3>
<p>많이 쓰이는 Shell은 두가지가 있다. </p>
<p>Bash, Zsh(맥 사용자라면 카탈리나 버전 이후)로 사용된다. </p>
<p>두 쉘 상에 큰 차이는 아직 인지하지 못하는 수준이지만, Zsh가 Bash의 변형된 버전이라는 것은 조금더 사용자 친화적이라는 글을 읽었다. 맥북 사용자라면 oh my zsh를 까는 경우가 많을텐데, 이때 사용하는 Zsh가 Zshell이다.</p>
<h3 id="두-쉘은-독립적인가">두 쉘은 독립적인가?</h3>
<p>기존 bash에서 사용하던 brew나 yarn이 zsh에서는 없는 커맨드라는 오류 메세지를 보여줬다.</p>
<pre><code>zsh commnad not found</code></pre><p>쉘은 결국 운영체제에서 사용자가 입력하는 명령을 읽고 해석하여 대신 실행해주는 프로그램인데, 별도의 독립적인 환경이 아닐 것이라고 판단하고 환경변수 셋팅이 잘못되어있다고 판단했다.</p>
<h3 id="brew-path-설정하기">Brew PATH 설정하기</h3>
<p>brew를 설치하게 되면 해당 문구가 나오는 것을 볼 수 있다. 대게는 따로 설정해 줄 필요가 없지만, brew라고 입력했을때 아무런 반응이 없다면 해당 코드를 터미널에 입력해주는 것이 좋다.</p>
<blockquote>
<p>Run these two commands in your terminal to add Homebrew to your PATH</p>
</blockquote>
<pre><code>(echo; echo &#39;eval &quot;$(/opt/homebrew/bin/brew shellenv)&quot;&#39;) &gt;&gt; /Users/hyunwoochoi/.zprofile</code></pre><p>해당 명령어는 Homebrew를 PATH에 추가하기 위해 사용되며, .zprofile파일에 HomeBrew관련 설정을 추가해줍니다. </p>
<pre><code> &gt;eval &quot;$(/opt/homebrew/bin/brew shellenv)&quot;
 혹은 

 source ~/.zprofile</code></pre><p>이 명령어는 앞서 생성한 Homebrew의 환경설정을 현재 세션에 적용합니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[상태(State)란 무엇인가?]]></title>
            <link>https://velog.io/@frog_dev/%EC%83%81%ED%83%9CState%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@frog_dev/%EC%83%81%ED%83%9CState%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Sun, 21 Jan 2024 13:16:50 GMT</pubDate>
            <description><![CDATA[<h3 id="들어가며">들어가며</h3>
<p>상태관리란 무엇일까? 
비전공자인 나에게 상태라는 개념은 조금 생소했고, 단순히 useState를 효율적이고 효과적으로 대체한다는 개념은 불충분했다. 누구라도 이해할 수 있게끔 상태에 대해 정의 해보고 상태관리란 무엇이고 어떤 방식이 있으며 왜 중요한지에 대해 적어보려고 한다. </p>
<h3 id="상태란-무엇인가">상태란 무엇인가?</h3>
<p>(Quora 발췌)
State refers to the current condition of a system, object, or process at a specific point
직역하자면 상태는 <strong>특정 시점에서 시스템, 객체 또는 프로세스의 현재 상태</strong>를 말한다.
<bl></p>
<p>관련된 예시를 가져온다면, </p>
<p>1) 상태란 프로그램이 실행되고 있는지?, input을 기다리고 있는지? 혹은 멈춰 있는지를 나타낼때 사용될 수 있다.
2) 프로그램이 특정시점에서 기억하고 있는 것, 예를 들면, 계산 과정을 기억하거나 현재 어떤 동작을 하고 있는지를 나타내는 말이다. </p>
<p>한줄로 내가 이해한 내용을 요약하자면, <strong><em>어플리케이션의 현재 상황이나 데이터를 나타내는 정보를 말한다.</em></strong> </p>
<h3 id="프론트-엔드-개발자에게-상태란">[프론트 엔드 개발자에게] 상태란?</h3>
<p>페이지를 제작 할때, 어떤 값을 입력 받는다면</p>
<ol>
<li>해당 입력값의 정보도 상태이며</li>
<li>네비게이션 바에서의 현재 위치를 기억하는 것도 상태라고 정의할 수 있다. </li>
</ol>
<p>  <a href="https://www.quora.com/What-do-programmers-mean-when-they-use-the-term-state">Quora 링크</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[블로그를 시작하며]]></title>
            <link>https://velog.io/@frog_dev/%EB%B8%94%EB%A1%9C%EA%B7%B8%EB%A5%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%A9%B0</link>
            <guid>https://velog.io/@frog_dev/%EB%B8%94%EB%A1%9C%EA%B7%B8%EB%A5%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%A9%B0</guid>
            <pubDate>Sat, 18 Nov 2023 08:24:14 GMT</pubDate>
            <description><![CDATA[<p><em>블로그를 시작하며</em></p>
<p>나는 오랫동안 누구에게 가르침을 주려면 스스로  완숙한 경지에 이르러야 타인에게 어떠한 지식을 전달할 수 있으리라 믿었다.</p>
<p>개발에 입문한 지 이제 겨우 1년이 내가 마주하는 오류들이 누군가에게는 수 있으며, 누군가에게는 나를 가볍게 판단하는 수단이 되지 않을까 경계했었다.</p>
<p>하지만 초보 개발자로서 겪는 누군가에게는 값진 정보가 될 것이며, 그것을 필요로 하지 않는 사람들은 그냥 보고 지나갈 것이라는 친구의 조언에 이렇게 다시 용기를 내어 블로그를 쓰게 되었다.</p>
<p>해당 블로그는 마주하는 여러 오류에 관해 기술할 것이며, 문제상황과 원인 그리고 해결 방식에 관해 기술하는 방식으로 작성될 것이다. 더 나은 방식이 있다면 그러한 부분들을 조금 더 발전시켜 적어 보는 노력을 할 것이다.</p>
]]></description>
        </item>
    </channel>
</rss>