<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>MINZ-VELOG</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 20 Sep 2024 18:02:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>MINZ-VELOG</title>
            <url>https://velog.velcdn.com/images/minz-cha/profile/1389e995-6a56-4a07-9c54-0b4a63c322c4/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. MINZ-VELOG. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minz-cha" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[React / TS] Property 'label' does not exist on type 'string' 오류]]></title>
            <link>https://velog.io/@minz-cha/React-TS-Property-label-does-not-exist-on-type-string-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@minz-cha/React-TS-Property-label-does-not-exist-on-type-string-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Fri, 20 Sep 2024 18:02:00 GMT</pubDate>
            <description><![CDATA[<p>사실 굉장히 쉽게 접할 수 있으면서도 한번 짚고 넘어가면 그 이후로는 접하지 않을 문제지만, 타입스크립트의 기본 개념과 접하는 오류이기 때문에 정리를 하고자함 !</p>
<h2 id="❌문제코드-예시">❌문제코드 예시</h2>
<blockquote>
<p>구현된 코드의 의도</p>
</blockquote>
<ol>
<li>부모 컴포넌트에서 <code>string[]</code>타입의 <code>textList</code> 변수를 자식 컴포넌트로 전달</li>
<li>자식 컴포넌트에서는 전달받은 <code>string[]</code>타입의 변수를 <code>map</code>을 통해 출력</li>
</ol>
<pre><code class="language-tsx">function ParentComponent () { //부모 컴포넌트
  const [textList, setTextList] = useState&lt;string[]&gt;([]);

  return (
    &lt;Box&gt;
      &lt;ChildComponent list={textList} /&gt;
    &lt;Box&gt;
  )
}</code></pre>
<pre><code class="language-tsx">function ChildComponent (list: string[]){ //자식 컴포넌트
    return (
    &lt;&gt;
      {list.map((listItem, index) =&gt; (
        &lt;Typography key={index}&gt;{listItem}&lt;/Typography&gt;
      ))}
    &lt;/&gt;
  );
}        </code></pre>
<p>위와 같은 코드가 있을 때, 그냥 봤을 때는 문제가 없어보인다. 
하지만 이렇게 구현하면 아래와 같은 오류가 나타난다.</p>
<blockquote>
<p>💥Type &#39;{ list: string[]; }&#39; is not assignable to type &#39;IntrinsicAttributes &amp; string[]&#39;.
  Property &#39;list&#39; does not exist on type &#39;IntrinsicAttributes &amp; string[]&#39;.</p>
</blockquote>
<p>오류의 원인은 <code>ChildComponent</code>에서 <code>list</code>라는 값을 props로 받아야 하는데, 현재는 그저 함수의 매개변수로만 정의되어 있기 때문이다. 즉, <code>ChildComponent</code>의 <code>list</code>는 props 객체의 속성인데, 이를 배열처럼 취급하고 있으니 타입이 맞지 않는다는 오류를 나타내는 것이다.</p>
<p>이렇게 말하면 이해가 조금 어려울 수 있으니 아래의 옳은 코드와 함께 이해해보자.</p>
<h2 id="⭕옳은-코드">⭕옳은 코드</h2>
<pre><code class="language-tsx">function ParentComponent () { //부모 컴포넌트
  const [textList, setTextList] = useState&lt;string[]&gt;([]);

  return (
    &lt;Box&gt;
      &lt;ChildComponent list={textList} /&gt;
    &lt;Box&gt;
  )
}</code></pre>
<pre><code class="language-tsx">interface ChildComponentProps{
 list: string[] 
}  

function ChildComponent ({ list }: ChildComponentProps){ //자식 컴포넌트
    return (
    &lt;&gt;
      {list.map((listItem, index) =&gt; (
        &lt;Typography key={index}&gt;{listItem}&lt;/Typography&gt;
      ))}
    &lt;/&gt;
  );
}        </code></pre>
<p>정말 단순하다 ! </p>
<hr>
<p>자 이제 문제의 코드와 옳은 코드를 비교하여 설명해보자면 ...</p>
<h3 id="1-함수의-매개변수로-labellist를-받는-경우">1. 함수의 매개변수로 labelList를 받는 경우</h3>
<pre><code class="language-tsx">function ChildComponent(list: string[]){ 
    return ( ... )</code></pre>
<p>React 컴포넌트는 props를 객체로 받기 때문에, ChildComponent에서 <code>list</code>를 받아올 때도 객체 형태로 받아야 한다. 즉, <code>list</code>는 props 객체의 속성으로 전달된다.
props로 전달되는 데이터가 <strong>객체 형태</strong>임에도 불구하고, 이 방식은 배열로 처리하려 하기 때문에 TypeScript는 list가 <span style="color:orange">배열이 아니라 props 객체</span>라고 인식하게 된다.</p>
<p>-&gt; 결국 위처럼 입력하면 React 컴포넌트가 아닌 <code>일반 함수</code>처럼 동작한다.</p>
<br/>

<h3 id="2-interface를-사용하여-props를-정의하는-경우">2. interface를 사용하여 props를 정의하는 경우</h3>
<pre><code class="language-tsx">interface ChildComponentProps{
 list: string[] 
}  

function ChildComponent ({ list }: ChildComponentProps){ 
    return ( ... )</code></pre>
<p>이 방식은 React에서 props를 받는 정확한 방식이다. 여기서 <code>ChildComponent</code>는 <strong>React 컴포넌트로 동작</strong>하며, <strong>props는 객체 형태로 전달</strong>된다. 이때 list는 <code>ChildComponentProps</code>로 <span style="color:orange">타입이 정의된 객체의 속성</span>으로 받아야한다.</p>
<p>-&gt; React 컴포넌트로서 정상 작동</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] Python - 20920번: 영단어 암기는 괴로워]]></title>
            <link>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-20920%EB%B2%88-%EC%98%81%EB%8B%A8%EC%96%B4-%EC%95%94%EA%B8%B0%EB%8A%94-%EA%B4%B4%EB%A1%9C%EC%9B%8C</link>
            <guid>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-20920%EB%B2%88-%EC%98%81%EB%8B%A8%EC%96%B4-%EC%95%94%EA%B8%B0%EB%8A%94-%EA%B4%B4%EB%A1%9C%EC%9B%8C</guid>
            <pubDate>Mon, 29 Jul 2024 15:03:10 GMT</pubDate>
            <description><![CDATA[<h1 id="20920번">20920번</h1>
<h2 id="문제입력출력">문제/입력/출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/6218908d-4bba-453b-aa99-9abbb1050b0f/image.png" alt=""></p>
<h2 id="예제-입출력">예제 입출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/19dede2a-ea18-4cc7-ad6d-80f28874fecc/image.png" alt=""></p>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://www.acmicpc.net/problem/20920">백준 20920번</a></p>
<hr>
<h2 id="💡풀이방법">💡풀이방법</h2>
<ul>
<li>접근방법<ul>
<li>영단어 정렬 조건 정리<ol>
<li>자주 나온 단어부터</li>
<li>긴 단어부터</li>
<li>사전순으로</li>
<li>공통조건: M보다 짧은 단어는 제외함</li>
</ol>
</li>
<li><strong>정리</strong> <ul>
<li>각 단어별로 조건 확인</li>
<li>길이가 M 이상인지 확인 후, true라면 단어의 빈도수를 저장</li>
</ul>
</li>
</ul>
</li>
</ul>
<br/>

<h2 id="✏️관련-개념">✏️관련 개념</h2>
<ul>
<li>** collections의 Counter**
데이터의 빈도수를 계산하고 관리하는데 사용함
리스트의 각 항목이 몇 번 나타나는지를 계산하여 딕셔너리 형태로 저장<pre><code class="language-python">data = [&#39;apple&#39;, &#39;orange&#39;, &#39;apple&#39;, &#39;orange&#39;, &#39;banana&#39;]
counter = Counter(data) 
print(counter) # Counter({&#39;apple&#39;: 2, &#39;orange&#39;: 2, &#39;banana&#39;: 1})
print(dict(counter)) # {&#39;apple&#39;: 2, &#39;orange&#39;: 2, &#39;banana&#39;: 1}</code></pre>
</li>
<li>코드 내에서의 Counter
반복을 돌면서 word_count.items()에서 각 <code>(word, count)</code>쌍 순회하며 리스트 요소로 변환<pre><code class="language-python">filtered_words = [
  (word, count) for word, count in word_count.items()
  if (len(word) &gt;= M) 
]
print(filtered_words) # [(&#39;apple&#39;: 2), (&#39;orange&#39;: 2), (&#39;banana&#39;: 1)]</code></pre>
</li>
<li><strong>lambda 이용</strong>
<code>-x[1]</code>: count값(빈도수)이 큰 것부터(내림차순)
<code>-len(x[0])</code>: word의 길이가 긴 것부터(내림차순)
<code>x[0]</code>: 알파벳 순(오름차순)<pre><code class="language-python">filtered_words.sort(key = lambda x: (-x[1], -len(x[0]), x[0]))</code></pre>
</li>
</ul>
<br/>

<h2 id="💡구현-코드">💡구현 코드</h2>
<pre><code class="language-python">from collections import Counter
import sys
input = sys.stdin.read()

def word_study(N, M, words):
    word_count = Counter(words)
    filtered_words = [
        (word, count) for word, count in word_count.items()
        if (len(word) &gt;= M) 
    ]

    filtered_words.sort(key = lambda x: (-x[1], -len(x[0]), x[0]))

    for word, _ in filtered_words:
        print(word)

data = input.split()
N = int(data[0])
M = int(data[1])
words = data[2:]

word_study(N, M, words)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Network] HTTP와 HTTPS]]></title>
            <link>https://velog.io/@minz-cha/HTTP%EC%99%80-HTTPS%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@minz-cha/HTTP%EC%99%80-HTTPS%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Fri, 26 Jul 2024 01:51:00 GMT</pubDate>
            <description><![CDATA[<h1 id="✔️http을-간단히-짚고--">✔️HTTP을 간단히 짚고. . .</h1>
<p>기본적으로 이미 몇번이나 짚었던 개념인데, 한번 더 정리하면서 확인해보기로 하자.</p>
<p><strong>HTTP</strong>(Hyper Text Transfer Protocol)은 <span style="color: orange">클라이언트와 서버간에 요청/응답으로 데이터를 주고 받을 수 있는 프로토콜</span>이다.  </p>
<ul>
<li>TCP/IP 기반</li>
<li>request(요청)/response(응답) 형태</li>
</ul>
<br/>

<h2 id="http-구조">HTTP 구조</h2>
<ul>
<li>HTTP method: 요청의 목적을 담고 있는 <strong>GET, POST, PUT, DELETE</strong> 등이 있다.<ul>
<li>GET: 자원에 대한 요청(조회 개념)</li>
<li>POST: 새로운 자원 생성</li>
<li>PUT: 자원에 대한 변경(수정 개념)</li>
<li>DELETE: 존재하는 자원 삭제
<img src="blob:https://velog.io/0f692b40-70dd-4995-9d71-450f60f117ba" alt="업로드중.."></li>
</ul>
</li>
</ul>
<br/>

<h2 id="http2-http3-">HTTP/2, HTTP/3 ?</h2>
<p>최초의 버전이 HTTP/1.1 이다. HTTP/2, HTTP/3은 예상할 수 있듯이 프로토콜 자체를 업그레이드한 버전이며, 데이터 전송 시스템을 수정하여 효율성을 개선한 것이다. </p>
<ul>
<li>HTTP/2 : 텍스트 형식 대신, 바이너리로 데이터를 교환</li>
<li>HTTP/3: 실시간 스트리밍 및 기타 최신 데이터 전송 요구사항을 보다 효율적으로 지원</li>
</ul>
<hr>
<h1 id="✔️그렇다면-https는-뭘까">✔️그렇다면 HTTPS는 뭘까?</h1>
<p>HTTP는 암호화되지 않은 데이터를 전송하는 프로토콜이기 때문에, 보안면에서는 문제가 될 수 밖에 없다. 이러한 문제를 해결하기 위해 HTTPS가 등장하게 된 것이다. </p>
<p><strong>HTTPS</strong>(Hyper Transfer Protocol Secure)는 말 그대로 <span style="color: orange"> HTTP에 데이터 암호화가 추가된 프로토콜 </span>이다. 즉, 데이터를 안전하게 전송하기 위해 사용된다.</p>
<h2 id="https의-암호화">HTTPS의 암호화</h2>
<p>암호화는 데이터를 읽을 수 없는 형태로 변환하는 과정이며, <strong>대칭키</strong>와 <strong>비대칭키</strong> 방식 2가지가 존재한다.</p>
<ul>
<li><strong>대칭키 암호화</strong><ul>
<li>암호화와 복호화에 동일한 키 사용</li>
<li>빠르고 효율적</li>
<li>키를 안전하게 공유하기가 어려움 (키를 교환하는 과정에서의 도청될 위험)</li>
</ul>
</li>
<li><strong>비대칭키 암호화</strong><ul>
<li>암호화와 복호화에 다른 키 사용</li>
<li>공개키와 개인키로 구성됨(공개키- 누구나 접근 가능, 개인키- 소유자만이 접근 가능)<ul>
<li>공개키와 개인키는 한 쌍</li>
<li>공개키 암호화-개인키 복호화: 개인키는 소유자만이 갖고 있으므로, 소유자만이 볼 수 있음</li>
<li>개인키 암호화-공개키 복호화: 공개키는 모두에게 공개되어 있으므로, 소유자가 인증한 정보임을 알려 신뢰성을 보장할 수 있음</li>
</ul>
</li>
<li>높은 보안성</li>
<li>대칭키에 비해 떨어지는 성능</li>
</ul>
</li>
</ul>
<br/>

<h3 id="https-동작-과정">HTTPS 동작 과정</h3>
<ol>
<li>클라이언트(브라우저)가 서버로 최초 연결 시도를 함</li>
<li>서버는 공개키(엄밀히는 인증서)를 브라우저에게 넘김</li>
<li>브라우저는 인증서의 유효성을 검사하고 세션키 발급</li>
<li>브라우저는 세션키를 보관하며 추가로 서버의 공개키로 세션키를 암호화하여 서버로 전송</li>
<li>서버는 개인키로 암호화된 세션키를 복호화하여 세션키 얻음</li>
<li>클라이언트와 서버는 동일한 세션키를 공유하므로 데이터를 전달할 때 세션키로 암호화/복호화 진행</li>
</ol>
<hr>
<p>결국 HTTP와 HTTPS의 가장 큰 차이는 보안과 관련된 부분이라고 볼 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] Python - 10814번: 나이순 정렬]]></title>
            <link>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-10814%EB%B2%88-%EB%82%98%EC%9D%B4%EC%88%9C-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-10814%EB%B2%88-%EB%82%98%EC%9D%B4%EC%88%9C-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Wed, 24 Jul 2024 15:39:13 GMT</pubDate>
            <description><![CDATA[<h1 id="10814번">10814번</h1>
<h2 id="문제입력출력">문제/입력/출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/5fdb2c49-669a-44e3-ae36-a4079f5c4567/image.png" alt=""></p>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://www.acmicpc.net/problem/10814">백준 10814번</a></p>
<hr>
<h2 id="✏️관련-개념">✏️관련 개념</h2>
<ul>
<li><p><strong>lambda 이용</strong></p>
<pre><code class="language-python">people.sort(key=lambda x: (x[0], x[2]))</code></pre>
<p>이전 <code>append</code>를 통해 <code>people</code>리스트는 <code>(age 나이, name 이름, i 인덱스)</code>형식의 튜플로 이루어져있음
이 상태에서 우선 <code>x[0]</code>(나이)로 정렬 후, <code>x[2]</code>(인덱스-입력된 순서)로 정렬하는 방식으로 풀어냄</p>
<pre><code class="language-python">people = [(25,&quot;Alice&quot;, 1), (21, &quot;Minsu&quot;, 2), (21, &quot;Bob&quot;, 3)] #예시: 튜플을 담고 있는 배열</code></pre>
</li>
<li><p><strong>튜플</strong>
  리스트: [], 튜플: ()
  리스트: 요솟값의 수정, 삭제 가능
  튜플: 요솟값을 바꿀 수 없음</p>
<pre><code class="language-python">  t1 = (1, 2, &quot;a&quot;, &quot;b&quot;)
  t1[0] // 1
  t1[3] // &quot;b&quot;</code></pre>
</li>
</ul>
<br/>

<h2 id="💡구현-코드">💡구현 코드</h2>
<pre><code class="language-python">import sys
input = sys.stdin.read
data = input().splitlines()

n = int(data[0])

people = []
for i in range(1, n + 1):
    age, name = data[i].split()
    age = int(age)
    people.append((age, name, i))

people.sort(key=lambda x: (x[0], x[2]))

for person in people:
    print(person[0], person[1])
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] React 기술 용어 모음 - SPA, JSX]]></title>
            <link>https://velog.io/@minz-cha/TIL-React-%EA%B8%B0%EC%88%A0-%EC%9A%A9%EC%96%B4-%EB%AA%A8%EC%9D%8C-SPA-JSX</link>
            <guid>https://velog.io/@minz-cha/TIL-React-%EA%B8%B0%EC%88%A0-%EC%9A%A9%EC%96%B4-%EB%AA%A8%EC%9D%8C-SPA-JSX</guid>
            <pubDate>Wed, 22 May 2024 10:16:29 GMT</pubDate>
            <description><![CDATA[<h1 id="✔️spa">✔️SPA</h1>
<p>: <strong>Single Page Application</strong>
하나의 HTML 페이지와 애플리케이션 실행에 필요한 JavaScript와 CSS와 같은 모든 리소스를 로드하는 애플리케이션</p>
<p>쉽게 말해, 그 전에는 웹을 보여줄 때 여러 페이지로 구성되어있었다. 이러한 방식은 페이지를 로딩할때마다 서버에서 리소스를 전달받아와서 렌더링을 하기 때문에, 규모가 커짐에 따라 데이터 전송 과부화로 인한 속도 저하와 같은 문제점이 발생한다.
이를 개선하기 위해 <code>React</code>를 사용한다. </p>
<ul>
<li>다른 주소에 다른 화면을 보여주는 것을 <code>Routing(라우팅)</code>이라고 함</li>
</ul>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/ed4d53ff-4c03-445b-b37b-c2976ab40837/image.png" alt=""></p>
<hr>
<h1 id="✔️jsx">✔️JSX</h1>
<ul>
<li>자바스크립트의 확장 문법</li>
<li>자바스크립트에서 HTML을 작성하듯이 비슷하게 작성할 수 있도록 해 주는 것이 JSX의 가장 큰 장점</li>
</ul>
<h2 id="jsx-특징">JSX 특징</h2>
<blockquote>
<p>컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나가 감싸는 형태</p>
</blockquote>
<p><strong>예시 - 잘못된 코드❌</strong></p>
<pre><code class="language-js">function App(){
    return(
        &lt;h1&gt;테스트1&lt;/h1&gt;
        &lt;h2&gt;테스트2&lt;/h2&gt;
    )
}</code></pre>
<p><strong>예시 - 옳은 코드⭕</strong></p>
<pre><code class="language-js">function App(){
    return(
        &lt;div&gt;
            &lt;h1&gt;테스트1&lt;/h1&gt;
            &lt;h2&gt;테스트2&lt;/h2&gt;
        &lt;/div&gt;
    )
}</code></pre>
<blockquote>
<p>자바스크립트 표현 : 자바스크립의 값을 JSX 안에서 렌더링할 수 있음</p>
</blockquote>
<pre><code class="language-js">import React from &#39;react&#39;;

function App() {
    const name = &#39;리액트&#39;;
    return (
    &lt;&gt;
        &lt;h1&gt;{name}&lt;/h1&gt;
        &lt;h2&gt;test&lt;/h2&gt;
    &lt;/&gt;
  );
}

export default App;</code></pre>
<hr>
<p>참고사이트
<a href="https://ko.legacy.reactjs.org/docs/glossary.html">React 공식문서</a>
<a href="https://velog.io/@hongduhyeon/React-SPA">React - SPA란?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] TypeScript 객체 프로퍼티 접근]]></title>
            <link>https://velog.io/@minz-cha/TIL-TypeScript-%EA%B0%9D%EC%B2%B4-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EC%A0%91%EA%B7%BC</link>
            <guid>https://velog.io/@minz-cha/TIL-TypeScript-%EA%B0%9D%EC%B2%B4-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EC%A0%91%EA%B7%BC</guid>
            <pubDate>Wed, 17 Jan 2024 00:34:13 GMT</pubDate>
            <description><![CDATA[<h2 id="객체-접근-방법">객체 접근 방법</h2>
<p>TS + React + Recoil 환경의 개발을 진행하던 중, 기본적인 문제에 부딪혀 한번 짚고넘어가기 위해 글을 작성한다.</p>
<h3 id="👀오류발생하는-부분을-확인해보자">👀오류발생하는 부분을 확인해보자</h3>
<ul>
<li>RecoilState 정의하는 atom.tsx<pre><code class="language-ts">//recoil state 생성
export interface UserTypes {
memberName: string;
memberPhone: string;
memberPassword: string;
}

</code></pre>
</li>
</ul>
<p>export const userState = atom<UserTypes>({
  key: &quot;user&quot;,
  default: {
    memberName: &quot;&quot;,
    memberPhone: &quot;&quot;,
    memberPassword: &quot;&quot;,
  },
});</p>
<pre><code>&lt;br/&gt;

- SignUpForm.tsx
```ts
const onChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    const {
      target: { name, value },
    } = e;

      // 비밀번호
      if (name === &quot;password&quot;) {
      setMemberPassword((prevUser) =&gt; ({
        ...prevUser,
        memberPassword: value,
      }));
    }

    // 비밀번호 확인
    if (name === &quot;password_confirm&quot;) {
      setMemberPasswordConfirm(value);

      if (value?.length &lt; 8) {
        setError(&quot;비밀번호는 8자리 이상으로 입력해주세요.&quot;);
      } else if (value !== memberPassword) {
        setError(&quot;비밀번호가 일치하지 않습니다.&quot;);
      } else {
        setError(&quot;&quot;);
      }
    }
  };
</code></pre><p>여기서 문제가 발생한 부분은 바로 <strong>memberPasswordConfirm</strong>가 <strong>memberPassword</strong>와 일치하는지 확인하는 부분이다.</p>
<pre><code class="language-ts">value !== memberPassword
//Error: &#39;string&#39;이(가) &#39;UserTypes&#39;과(와) 겹치지 않으므로 이 비교는 의도하지 않은 것 같습니다.`</code></pre>
<blockquote>
<p>💥<strong>오류내용</strong>: 사용자가 회원가입하기 위해 입력하는 <strong><code>value</code></strong> 값은 <strong><code>string</code></strong> 타입인데, <strong><code>memberPassword</code></strong>는 <strong><code>UserTypes</code></strong>타입으로 인식하기 때문에 두 값의 타입이 맞지 않아 비교할 수 없음을 의미한다.</p>
</blockquote>
<hr>
<h3 id="💡제대로-객체의-프로퍼티에-접근하자">💡제대로 객체의 프로퍼티에 접근하자</h3>
<blockquote>
<p>✅<strong>해결방법</strong>: <strong><code>memberPassword</code></strong>로 되어있는 부분을, <strong><code>memberPassword.memberPassword</code></strong>로 수정해주면 된다.</p>
</blockquote>
<ul>
<li><code>memberPassword</code>: UserTypes의 객체 전체를 의미</li>
<li><code>memberPassword.memberPassword</code>: UserTypes 객체에서 memberPassword 필드에 해당하는 값을 의미 (실제 password 값)</li>
</ul>
<p>정확히 확인해보기 위해 콘솔값을 띄워보았다.</p>
<pre><code class="language-ts">if (name === &quot;password&quot;) {
    setMemberPassword((prevUser) =&gt; ({
       ...prevUser,
    memberPassword: value,
    }));
    console.log(memberPassword); // 콘솔확인
}</code></pre>
<p>만약 <code>memberPassword</code>변수가 <code>memberPassword</code>의 값만을 나타낸다면, 콘솔엔 비밀번호값만 떠야 맞지만, 객체를 나타낸다면, <code>memberName</code>과 <code>memberPhone</code>값을 나타낼것이다. </p>
<br/>

<p><strong>👀Console 확인</strong></p>
<ul>
<li><p><code>memberPassword</code> 확인 -&gt; 객체 전체의 값이 나타남
<img src="https://velog.velcdn.com/images/minz-cha/post/5e2b9d91-ba2a-450a-ae01-3044d15558ea/image.png" alt=""></p>
</li>
<li><p><code>memberPassword.memberPassword</code> 확인 -&gt; password값만 나타남
<img src="https://velog.velcdn.com/images/minz-cha/post/7280efc1-06a0-4ab9-ade9-da85575a360b/image.png" alt=""></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Recoil로 상태관리하기_atom, selector]]></title>
            <link>https://velog.io/@minz-cha/React-Recoil%EB%A1%9C-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0atom-selector</link>
            <guid>https://velog.io/@minz-cha/React-Recoil%EB%A1%9C-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0atom-selector</guid>
            <pubDate>Wed, 03 Jan 2024 08:52:04 GMT</pubDate>
            <description><![CDATA[<p>react로 개발을 하다보면, 점점 상태관리를 하는 코드가 늘어나기 마련이다. </p>
<p>특히 <code>useState</code>를 난무하는 경우가 발생하며, react의 특성 중 하나인 ‘<strong>단방향 데이터 흐름’</strong>으로 인해 <code>useState</code>로 상태가 변경된 값을 <code>props</code>를 특정 컴포넌트로 계속 전달 → 전달 → 전달하는 방식이 된다.</p>
<p>즉, 복잡한 상태 관리를 위해 여러 개의 <code>useState</code>를 사용해야 하기 대문에 상태가 복잡해지면 코드가 길어지면서, 컴포넌트 계층 구조가 깊어질수록 상태 전달이 번거롭다는 단점이 발생한다.</p>
<p>나는 이러한 상태관리의 복잡성과 번거로움에 지쳐 이를 해결하고자 <code>Recoil</code> 사용을 도입하였다.</p>
<hr>
<h1 id="recoil">Recoil</h1>
<p><code>Recoil</code>  장점:</p>
<ul>
<li>비동기 처리를 용이하게 지원하여 비동기 데이터 흐름 관리 가능</li>
<li>액세스 가능한 상태와 상태 간의 의존성 추적을 제공하여 업데이트를 자동으로 처리 가능</li>
<li><code>useState</code> 와 유사하게 생겼으며 <code>[get, set]</code> 기능 또한 동일하여 쉽게 접근할 수 있음</li>
</ul>
<pre><code class="language-jsx">// useState
const [id, setId] = useState(0);

// recoil
const [count, setCount] = useRecoilState(countState);</code></pre>
<ul>
<li>Recoil을 사용하기 위해서는 부모 컴포넌트에 <code>&lt;RecoilRoot&gt;</code> 를 사용해야함 - 보통 전역으로 사용하므로 루트 컴포넌트에 넣는게 좋음</li>
</ul>
<pre><code class="language-jsx">import React from &#39;react&#39;;
import ReactDOM from &#39;react-dom&#39;;
import &#39;./index.css&#39;;
import App from &#39;./App&#39;;
import { RecoilRoot } from &#39;recoil&#39;;

ReactDOM.render(
  &lt;React.StrictMode&gt;
    &lt;RecoilRoot&gt;
      &lt;App /&gt;
    &lt;/RecoilRoot&gt;
  &lt;/React.StrictMode&gt;,
  document.getElementById(&#39;root&#39;)
);</code></pre>
<hr>
<h2 id="✔️recoil의-atom">✔️Recoil의 atom</h2>
<p>Recoil의 경우, 공식 문서에서 예시 코드를 잘 보여주고 있다.</p>
<p><a href="https://recoiljs.org/docs/basic-tutorial/atoms/">Atoms | Recoil</a></p>
<h3 id="✏️atom이란">✏️Atom이란?</h3>
<p>쉽게 말해 react의 <strong>단방향 데이터 흐름</strong> 특성으로 인해 생기는 불편함을 해소시켜준다.
useState를 사용하는 경우, 상태 전달이 번거로웠지만, atom을 이용하여 해당 상태 구조를 정의해주기만 하면, 그 상태를 어느 컴포넌트에서도 쉽게 접근할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/188873c1-7ac6-4fbf-a450-d9d0a3e12380/image.png" alt=""></p>
<ul>
<li><strong>예시 코드</strong><ul>
<li><code>key</code> : atom을 식별하는데 필요한 고유한 문자열</li>
<li><code>default</code> : 초기값</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">export const todoListState = atom({
  key: &#39;TodoList&#39;,
  default: [],
});</code></pre>
<ul>
<li><strong><code>useState</code> 와 비교</strong></li>
</ul>
<pre><code class="language-jsx">// useState
const [id, setId] = useState(0);

// atom으로 상태 구조 
export const idState = atom({
  key: &#39;idStateKey&#39;,
  default: 0,
});

//recoil
const [id, setId] = useRecoilState(idState);</code></pre>
<br/>

<hr>
<h2 id="✔️recoil의-selector">✔️Recoil의 Selector</h2>
<p><a href="https://recoiljs.org/docs/basic-tutorial/selectors">Selectors | Recoil</a></p>
<h3 id="✏️selector이란">✏️Selector이란?</h3>
<ul>
<li>atom에서 불가능한 비동기 처리와 복잡한 로직 구현 가능</li>
<li>기존에 선언한 <code>atom</code> 을 전/후 처리하여 새로운 값을 반환하거나 기존 <code>atom</code> 값을 수정하는 역할 수행</li>
</ul>
<blockquote>
<p>Selector: derived state(파생된 상태)를 나타내는데 사용
파생된 상태란 기본 상태를 입력으로 받아 변환된 값을 출력하는 상태</p>
</blockquote>
<ul>
<li><strong>예시 코드</strong><ul>
<li><code>key</code> : 고유한 문자열</li>
<li><code>get</code> : 다른 atom이나 selector의 상태를 읽는 데 사용<ul>
<li>다른 atom/selector의 값을 가져와 현재 selector에서 사용할 수 있음</li>
</ul>
</li>
<li><code>set</code> : atom의 상태를 설정하거나 업데이트하는 데 사용<ul>
<li>주로 비동기 작업을 수행한 후 atom의 상태를 업데이트할 때 사용</li>
<li><strong>2개의 매개변수</strong>: 첫번째- recoil의 상태(textState), 두번째 - 어떤값으로 바뀔지, 즉 새로운 값</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">// 사용자의 입력을 저장하는 atom
const textState = atom({
  key: &#39;textState&#39;, // 고유한 키
  default: &#39;&#39;, // 기본값
});

// 텍스트의 길이를 계산하는 selector
// set 함수: 입력된 텍스트를 대문자로 변환하여 atom을 업데이트
const textLengthSelector = selector({
  key: &#39;textLengthSelector&#39;,
  get: ({get}) =&gt; {
    const text = get(textState);
    return text.length;
  },
  set: ({set}, newValue) =&gt; {
    // 예를 들어, 텍스트를 대문자로 변경
    const upperCaseText = newValue.toUpperCase();
    set(textState, upperCaseText);
  }
});</code></pre>
<ul>
<li>컴포넌트에서 이용</li>
</ul>
<pre><code class="language-jsx">// import문은 생략

function TextComponent() {
  const [text, setText] = useRecoilState(textState);
  const textLength = useRecoilValue(textLengthSelector);

  return (
    &lt;div&gt;
      &lt;input type=&quot;text&quot; value={text} onChange={(e) =&gt; setText(e.target.value)} /&gt;
      &lt;p&gt;Text Length: {textLength}&lt;/p&gt;
    &lt;/div&gt;
  );
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] Python - Lv.1 - 달리기 경주]]></title>
            <link>https://velog.io/@minz-cha/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Python-Lv.1-%EB%8B%AC%EB%A6%AC%EA%B8%B0-%EA%B2%BD%EC%A3%BC</link>
            <guid>https://velog.io/@minz-cha/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Python-Lv.1-%EB%8B%AC%EB%A6%AC%EA%B8%B0-%EA%B2%BD%EC%A3%BC</guid>
            <pubDate>Wed, 06 Dec 2023 02:11:39 GMT</pubDate>
            <description><![CDATA[<h1 id="달리기-경주">달리기 경주</h1>
<h2 id="문제--제한사항">문제 / 제한사항</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/bc6e594d-a787-403c-b8f2-d2013304bc3d/image.png" alt=""></p>
<h2 id="입출력-예">입출력 예</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/2cddc614-01ef-48dd-935e-67a45014e03e/image.png" alt=""></p>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/178871">프로그래머스 - Lv1. 달리기 경주</a></p>
<hr>
<h2 id="💡풀이방법">💡풀이방법</h2>
<ul>
<li>문제를 쉽게 풀어보면, <code>callings</code>에서 불린 선수 순서대로 해당 선수의 앞 선수와 순서를 바꾸면서 <code>players</code>의 인덱스 값을 갱신</li>
<li>접근 방법<ol>
<li><code>players</code> 배열을 딕셔너리(<code>player_list</code>)를 통해 초기 위치 정보를 저장</li>
<li>반복문을 통해 <code>callings</code>의 배열에 들어가 있는 선수를 차례대로 호출</li>
<li>현재 불린 선수의 인덱스(<code>current_index</code>) 확인</li>
<li>현재 불린 선수와 그 앞의 선수 인덱스 swap</li>
<li><code>player_list</code>의 현재 불린 선수의 인덱스(<code>current_index</code>) -1<ul>
<li>현재 불린 선수의 앞에 위치했던 선수의 인덱스는 <code>current_index</code>로 갱신</li>
</ul>
</li>
</ol>
</li>
</ul>
<h2 id="👀전체코드">👀전체코드</h2>
<pre><code class="language-python">def solution(players, callings):
    # 딕셔너리를 통해 선수들의 초기 위치 저장
    player_list = {player: i for i, player in enumerate(players)}
    for i in range(len(callings)):
        # 현재 불린 선수
        calling_player = callings[i]
        # 현재 불린 선수의 위치 (인덱스)
        current_index  = player_list[calling_player]
        # calling 선수와 그 앞의 선수의 순서 변경
        players[current_index], players[current_index - 1] = players[current_index - 1], players[current_index]
        # 변경된 순서로 list에 index값 갱신
        player_list[calling_player] = current_index - 1
        player_list[players[current_index]] = current_index

    return players
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] Python - Lv.1 - [PCCP 기출문제] 1번]]></title>
            <link>https://velog.io/@minz-cha/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Python-Lv.1-PCCP-%EA%B8%B0%EC%B6%9C%EB%AC%B8%EC%A0%9C-1%EB%B2%88</link>
            <guid>https://velog.io/@minz-cha/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Python-Lv.1-PCCP-%EA%B8%B0%EC%B6%9C%EB%AC%B8%EC%A0%9C-1%EB%B2%88</guid>
            <pubDate>Wed, 06 Dec 2023 00:28:09 GMT</pubDate>
            <description><![CDATA[<h1 id="pccp-기출문제-1번">PCCP 기출문제 1번</h1>
<h2 id="문제제한사항">문제/제한사항</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/02a13abf-e3b9-4f7b-8063-eaae051b29c5/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/2b91c4f1-5576-4312-9a50-6b3b3dfabaaf/image.png" alt=""></p>
<h2 id="입력출력">입력/출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/19f60e70-b865-41f9-a022-b4e2e39db743/image.png" alt=""></p>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/250137">PCCP 기출문제 1번</a></p>
<hr>
<h2 id="💡풀이방법">💡풀이방법</h2>
<ul>
<li>입출력 예를 보면, 시간이랑 <code>attacks</code>의 배열 값의 첫번째 인덱스 값(공격시간)이 같은 경우 공격을 받게 된다.</li>
<li>변수<ul>
<li>current : 현재 체력<ul>
<li>count : 연속체력회복</li>
<li>attack_fount : 공격여부</li>
</ul>
</li>
</ul>
</li>
</ul>
<ol>
<li>공격시간인 경우 (<code>attacks</code> 배열값의 첫번째 값)<ul>
<li><code>연속회복횟수 = 0</code></li>
<li><code>현재 체력 - 공격값</code></li>
<li>이때 <code>현재 체력 &lt; 0</code> or <code>== 0</code>인 경우: <code>return -1</code></li>
</ul>
</li>
<li>공격시간 아닌 경우<ul>
<li><code>bandage[1]</code>만큼 체력 회복</li>
<li><code>연속회복횟수 += 1</code></li>
<li>이때 <code>연속회복횟수 == bandage[0]</code>인 경우: <code>현재 체력 + bandage[2]</code></li>
</ul>
</li>
</ol>
<h2 id="👀전체코드">👀전체코드</h2>
<pre><code class="language-python">def control_health(num, max_):
    print(&quot;control&quot;)
    if num &gt; max_:
        print(&quot;health&quot;, max_)
        return max_
    else:
        print(&quot;current&quot;, num)
        return num

def solution(bandage, health, attacks):
    current = health # 현재 체력
    count = 0 # 연속 성공

    for i in range(1, attacks[-1][0] + 1):
        current_attack = 0
        attack_found = False 

        for subattack in attacks:
            if i == subattack[0]: #시간 초와 공격시간 같은 경우
                current_attack = subattack[1]
                attack_found = True # 공격 받음
                break

        # 공격 받은 경우
        if attack_found:
            current -= current_attack 
            count = 0
            if current &lt; 0 or current == 0:
                return -1

        # 공격 받지 않은 경우 - 회복
        else: 
            count += 1
            # 연속 회복 성공
            if count == bandage[0]:
                current = current + bandage[1] + bandage[2]
                count = 0
            else:
                current += bandage[1]

        # 회복한 체력이 최대 체력을 넘지 않도록 제어
        current = control_health(current, health)

    return current</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 자바스크립트 기초 프로젝트_counter]]></title>
            <link>https://velog.io/@minz-cha/JS-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EC%B4%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8counter</link>
            <guid>https://velog.io/@minz-cha/JS-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EC%B4%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8counter</guid>
            <pubDate>Sun, 03 Dec 2023 16:51:29 GMT</pubDate>
            <description><![CDATA[<h2 id="👩💻-counter">👩‍💻 counter</h2>
<p>버튼에 따라서 숫자값이 +1 되거나 -1 되는 기능</p>
<h3 id="html">HTML</h3>
<ul>
<li><code>count_number</code> : 버튼에 의해 값이 바뀌는 text</li>
<li><code>button</code> : 버튼에 따라 값 증가, 감소, 리셋</li>
</ul>
<pre><code class="language-html">...
  &lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;div class=&quot;title&quot;&gt;Counter&lt;/div&gt;
      &lt;div class=&quot;count_number&quot;&gt;0&lt;/div&gt;
      &lt;div class=&quot;button_block&quot;&gt;
        &lt;button class=&quot;btn_decrease&quot;&gt;DECREASE&lt;/button&gt;
        &lt;button class=&quot;btn_reset&quot;&gt;RESET&lt;/button&gt;
        &lt;button class=&quot;btn_increase&quot;&gt;INCREASE&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
...</code></pre>
<h3 id="javascript">Javascript</h3>
<ul>
<li><p><code>querySelector</code> 을 통해 각 버튼의 <code>class</code> 명을 불러옴</p>
</li>
<li><p>각 버튼마다 <code>addEventListener</code> 을 통해 <code>click</code> 이벤트 생성</p>
</li>
<li><p><code>textContent</code>로 <code>count</code> 값을 불러와 새로운 숫자 값 부여</p>
<pre><code class="language-jsx">document.addEventListener(&quot;DOMContentLoaded&quot;, function () {
const count = document.querySelector(&quot;.count_number&quot;);
const btnDec = document.querySelector(&quot;.btn_decrease&quot;);
const btnRe = document.querySelector(&quot;.btn_reset&quot;);
const btnInc = document.querySelector(&quot;.btn_increase&quot;);

btnDec.addEventListener(&quot;click&quot;, function () {
  let num = count.textContent;
  num = Number(num) - 1;
  count.textContent = num;
  colorChange();
});

btnRe.addEventListener(&quot;click&quot;, function () {
  count.textContent = 0;
  colorChange();
});

btnInc.addEventListener(&quot;click&quot;, function () {
  let num = count.textContent;
  num = Number(num) + 1;
  count.textContent = num;
  colorChange();
});

function colorChange() {
  if (Number(count.textContent) &lt; 0) {
    count.style.color = &quot;red&quot;;
  } else if (Number(count.textContent) &gt; 0) {
    count.style.color = &quot;green&quot;;
  } else if (Number(count.textContent) == 0) {
    count.style.color = &quot;black&quot;;
  }
}
});</code></pre>
</li>
</ul>
<h3 id="구현결과">구현결과</h3>
<hr>
<h2 id="💭다른-분의-코드">💭다른 분의 코드</h2>
<h3 id="html-1">HTML</h3>
<pre><code class="language-html">...
&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;div class=&quot;title&quot;&gt;Counter&lt;/div&gt;
      &lt;div class=&quot;count_number&quot;&gt;0&lt;/div&gt;
      &lt;div class=&quot;button_block&quot;&gt;
        &lt;button class=&quot;btn decrease&quot;&gt;DECREASE&lt;/button&gt;
        &lt;button class=&quot;btn reset&quot;&gt;RESET&lt;/button&gt;
        &lt;button class=&quot;btn increase&quot;&gt;INCREASE&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
...</code></pre>
<h3 id="js">JS</h3>
<pre><code class="language-js">document.addEventListener(&quot;DOMContentLoaded&quot;, function () {
    let count = 0;
    const value = document.querySelector(&quot;.count_number&quot;);
    const btns = document.querySelectorAll(&quot;.btn&quot;);

    btns.forEach(function (btn) {
        btn.addEventListener(&quot;click&quot;, function (e) {
            const classes = e.currentTarget.classList;
            if (classes.contains(&quot;decrease&quot;)) {
                count--;
            } else if (classes.contains(&quot;reset&quot;)) {
                count = 0;
            } else if (classes.contains(&quot;increase&quot;)) {
                count++;
            }
            if (count &lt; 0) {
                value.style.color = &quot;red&quot;;
            } else if (count &gt; 0) {
                value.style.color = &quot;green&quot;;
            } else if (count === 0) {
                value.style.color = &quot;black&quot;;
            }
            value.textContent = count;
        });
    });
});</code></pre>
<h3 id="구현결과-1">구현결과</h3>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/4475521e-96e4-44e1-90c9-79c53e5eccb3/image.gif" alt=""></p>
<hr>
<h2 id="👀관련개념">👀관련개념</h2>
<h3 id="1-foreach">1. forEach()</h3>
<ul>
<li>배열의 크기만큼 반복 실행되며, 배열 요소의 개수에 따라 콜백 함수가 호출되는 횟수가 결정됨<pre><code class="language-js">const numbers = [10, 25, 30, 45];
</code></pre>
</li>
</ul>
<p>let foundNumber = null;</p>
<p>numbers.forEach(function(number) {
    if (number &gt; 30) {
        foundNumber = number;
    }
});</p>
<p>console.log(foundNumber); // 출력: 45</p>
<pre><code>
- `forEach()` 함수는 반환 값이 없으므로 새로운 배열을 생성하지 않음
```js
const numbers = [1, 2, 3, 4, 5];

const result = numbers.forEach(function(number) {
    return number * 2; 
  // 어떤 값을 반환해도 forEach()의 반환 값은 여전히 undefined
});

console.log(result); // 출력: undefined</code></pre><br/>

<h3 id="2-currenttarget-속성">2. currentTarget 속성</h3>
<ul>
<li><code>target</code> : 이벤트가 발생한 바로 그 요소를 직접 가리킴 </li>
<li><code>currentTarget</code> : 이벤트 리스너(EventListener)를 가진 요소</li>
</ul>
<br/>

<h3 id="3-classlist">3. classList</h3>
<ul>
<li><p>DOMTokenList 객체로 element의 class 속성을 보여줌</p>
<pre><code class="language-js">const classes = element.classList;</code></pre>
</li>
<li><p>class 추가</p>
<pre><code class="language-js">let div = document.querySelector(&#39;#content&#39;);
div.classList.add(&#39;info&#39;);</code></pre>
</li>
<li><p>class 삭제</p>
<pre><code class="language-js">// remove only
let div = document.querySelector(&#39;#content&#39;);
div.classList.remove(&#39;visible&#39;);
</code></pre>
</li>
</ul>
<p>// remove multiple
let div = document.querySelector(&#39;#content&#39;);
div.classList.remove(&#39;block&#39;, &#39;red&#39;);</p>
<pre><code>- 이외에도 replace(교체), contains(존재 확인), toggle(토글) 이 있다.

&lt;br/&gt;

### 4. textContent 
- 텍스트노드를 추가하고, 해당 엘리먼트의 텍스트 값을 반환함

```js
var msg = document.querySelector(&#39;p&#39;).textContent;
console.log(msg);

// return : Hello World! </code></pre><hr>
<p>[참고자료]</p>
<p><a href="https://sisiblog.tistory.com/234">classList 속성</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 자바스크립트 기초 프로젝트_color flipper]]></title>
            <link>https://velog.io/@minz-cha/JS-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EC%B4%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8color-flipper</link>
            <guid>https://velog.io/@minz-cha/JS-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EC%B4%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8color-flipper</guid>
            <pubDate>Wed, 29 Nov 2023 02:55:22 GMT</pubDate>
            <description><![CDATA[<h2 id="👩💻color-flipper">👩‍💻color flipper</h2>
<p>버튼을 클릭하면 랜덤으로 배경색이 바뀌는 기능</p>
<h3 id="html">HTML</h3>
<ul>
<li><code>container</code>: background</li>
<li><code>contenst</code>안에 배경색을 나타내는 <code>p</code>와 클릭 버튼 <code>button</code> 생성<pre><code class="language-html">...
&lt;body&gt;
  &lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;contents&quot;&gt;
      &lt;p&gt;Background Color: &lt;span class=&quot;color&quot;&gt;mint&lt;/span&gt;&lt;/p&gt;
      &lt;button class=&quot;button&quot;&gt;Click Me!&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/body&gt;
...</code></pre>
</li>
</ul>
<h3 id="javascript">Javascript</h3>
<ul>
<li><code>querySelector</code> 를 이용하여 특정 요소를 찾는다.</li>
<li>랜덤으로 변경시킬 color값을 <code>colors</code> 에 배열 형태로 집어 넣는다.</li>
<li><code>handleClick</code> : 버튼이 클릭되었을 때 실행할 동작 정의<ul>
<li><code>randomNumber</code>: colors 경우만큼의 랜덤 숫자</li>
<li><code>background.style.backgroundColor</code> : <code>colors</code> 의 <code>color</code> 로 색상 변경</li>
<li><code>colorText.style.color</code> : <code>colors</code> 의 <code>color</code> 로 텍스트 색상 변경</li>
<li><code>colorText.textContent</code> : <code>colors</code> 의 <code>name</code> 으로 텍스트 변경</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">$(document).ready(function () {
  $(function () {
    const background = document.querySelector(&quot;.container&quot;);
    const colorText = document.querySelector(&quot;.color&quot;);
    const btn = document.querySelector(&quot;button&quot;);

    const colors = [
      { id: 1, name: &quot;red&quot;, color: &quot;#ff0000&quot; },
      { id: 2, name: &quot;orange&quot;, color: &quot;#FFA500&quot; },
      { id: 3, name: &quot;yellow&quot;, color: &quot;#ffff00&quot; },
      { id: 4, name: &quot;lime green&quot;, color: &quot;#32cd32&quot; },
      { id: 5, name: &quot;skyblue&quot;, color: &quot;#87CEEB&quot; },
    ];

    const handleClick = () =&gt; {
      const randomNumber = Math.floor(Math.random() * colors.length);
      background.style.backgroundColor = colors[randomNumber].color;
      colorText.style.color = colors[randomNumber].color;
      colorText.textContent = colors[randomNumber].name;
    };

    btn.addEventListener(&quot;click&quot;, handleClick);
  });
});
</code></pre>
<h3 id="구현-결과">구현 결과</h3>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/bcdfd805-b5ed-486c-9811-5243a82ae4f8/image.gif" alt=""></p>
<hr>
<h2 id="👀관련-개념">👀관련 개념</h2>
<h3 id="1-queryselector">1. <strong>querySelector</strong></h3>
<p>특정 <code>name</code>,<code>id</code>,<code>class</code>를 제한하지 않고 css선택자를 사용하여 요소를 찾는다.
    - querySelector(#id) =&gt; id 값 id를 가진 요소를 찾는다.
    - querySelector(.class) =&gt; class 값 class를 가진 요소를 찾는다.</p>
<br/>

<h3 id="2-getelementbyid">2. <strong>getElementbyId</strong></h3>
<p>괄호 안에 <code>id</code>값을 집어넣어 사용한다.</p>
<ul>
<li><p>html 코드</p>
<pre><code class="language-html">&lt;button id=&quot;test-btn&quot;&gt;바뀌기 전 text&lt;/button&gt;</code></pre>
</li>
<li><p>javascript 코드: <code>test-btn</code> 이라는 <code>id</code> 값을 가진 버튼 요소를 찾고, 해당 버튼을 <code>click</code> 했을 때, 텍스트를 변경하는 코드</p>
<pre><code class="language-jsx">const mode = document.getElementById(&quot;test-btn&quot;);
mode.addEventListener(&quot;click&quot;, function() {
  if (mode.innerText === &quot;바뀌기 전 text&quot;) {
      mode.innerText = &quot;바뀐 text!&quot;;
  } else {
      mode.innerText = &quot;바뀌기 전 text&quot;;
  }
});</code></pre>
<br/>

</li>
</ul>
<h3 id="3-documentbodystylebackgroundcolor">3. <strong>document.body.style.backgroundColor</strong></h3>
<p>body 요소의 배경색을 설정하거나 가져온다.</p>
<pre><code class="language-jsx">document.body.style.backgroundColor = &#39;lightblue&#39;;</code></pre>
<h3 id="4-mathfloor">4. <strong>Math.floor()</strong></h3>
<p>소수 부분을 버림하여 정수 부분만 남긴다.</p>
<pre><code class="language-jsx">let number = 5.78;
console.log(Math.floor(number)); // 5</code></pre>
<h3 id="5-mathrandom">5. <strong>Math.random()</strong></h3>
<p>0 이상 1 미만의 난수를 반환한다.</p>
<pre><code class="language-jsx">// 0부터 5까지의 랜덤 숫자를 얻기
const randomNumber = Math.floor(Math.random() * 6);

// 1부터 5까지의 랜덤 숫자를 얻기
const randomNumber = Math.floor(Math.random() * 5) + 1;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테] JS 프로그래머스 입문문제 풀이 모음(1)_ 사칙연산, 조건문, 배열, 수학]]></title>
            <link>https://velog.io/@minz-cha/%EC%BD%94%ED%85%8C-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%9E%85%EB%AC%B8%EB%AC%B8%EC%A0%9C-%ED%92%80%EC%9D%B4-%EB%AA%A8%EC%9D%8C-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EB%B0%B0%EC%97%B4-%EC%88%98%ED%95%99</link>
            <guid>https://velog.io/@minz-cha/%EC%BD%94%ED%85%8C-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%9E%85%EB%AC%B8%EB%AC%B8%EC%A0%9C-%ED%92%80%EC%9D%B4-%EB%AA%A8%EC%9D%8C-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EB%B0%B0%EC%97%B4-%EC%88%98%ED%95%99</guid>
            <pubDate>Wed, 22 Nov 2023 07:06:10 GMT</pubDate>
            <description><![CDATA[<h2 id="👀주요-개념">👀주요 개념</h2>
<ul>
<li>간단히 개념만 짚으려는 목적이기 때문에 상세 설명은 생략한다. </li>
</ul>
<h3 id="✅숫자-올림내림반올림---math-이용">✅숫자 올림/내림/반올림 - Math 이용</h3>
<ul>
<li>Math.ceil : 올림<pre><code class="language-js">// 1.올림
const ceil_1 = Math.ceil(1); // 1
const ceil_2 = Math.ceil(1.3); // 2
const ceil_3 = Math.ceil(1.7); // 2
</code></pre>
</li>
</ul>
<p>// 2. null 또는 0인 경우
const ceil_4 = Math.ceil(null); // 0
const ceil_5 = Math.ceil(0); // 0</p>
<p>// 3. 음수인 경우
const ceil_6 = Math.ceil(-1); // -1
const ceil_7 = Math.ceil(-1.2); // -1
const ceil_8 = Math.ceil(-1.9); // -1</p>
<pre><code>&lt;br/&gt;

- Math.floor : 내림
```js
// 1.내림
const floor_1 = Math.floor(1); // 1
const floor_2 = Math.floor(1.3); // 1
const floor_3 = Math.floor(2.2); // 2
const floor_4 = Math.floor(2.9); // 2

// 2. null 또는 0인 경우
const floor_5 = Math.floor(null); // 0
const floor_6 = Math.floor(0); // 0

// 3. 음수인 경우
const floor_7 = Math.floor(-1); // -1
const floor_8 = Math.floor(-1.2); // -2
const floor_9 = Math.floor(-1.9); // -2</code></pre><br/>

<ul>
<li>Math.round : 반올림<pre><code class="language-js">const round_1 = Math.round(1); // 1
const round_2 = Math.round(1.3); // 1
const round_3 = Math.round(1.7); // 2
</code></pre>
</li>
</ul>
<p>// 2. null 또는 0인 경우
const round_4 = Math.round(null); // 0
const round_5 = Math.round(0); // 0</p>
<p>// 3. 음수인 경우
const round_6 = Math.round(-1); // -1
const round_7 = Math.round(-1.2); // -1
const round_8 = Math.round(-1.9); // -2</p>
<pre><code>
---

### ✅parseInt: 문자열 -&gt; 숫자 변환
- 문자열의 첫글자가 숫자가 아닌 경우, `NaN`
- 실수값 -&gt; 정수값으로 변환
- 숫자가 아닌 값은 무시하고, 그 이전의 값까지만 출력
- 2진법, 16진법도 처리 가능
```js
console.log(parseInt(&quot;10&quot;)); // 10
console.log(parseInt(&quot;-10&quot;)); // -10
console.log(parseInt(&quot;10.9&quot;)); // 10
console.log(parseInt(10)); // 10
console.log(parseInt(&quot;10nnn13&quot;)); // 10
console.log(parseInt(&quot;10n&quot;)); // 10
console.log(parseInt(&quot;k10&quot;)); // NaN
console.log(parseInt(&quot;10&quot;, 2)); // 2 (2진법)
console.log(parseInt(&quot;0xF&quot;)); // 15 (16진법)</code></pre><hr>
<h3 id="✅tilde-연산자-double-tilde-연산자">✅tilde(<del>) 연산자, double tilde(</del>) 연산자</h3>
<ul>
<li><strong>tilde(~)</strong>: NOT의 비트연산자<pre><code class="language-js">const a = 5;     // 0000000000000101
console.log(~a); // 1111111111111010
// expected output: -6
</code></pre>
</li>
</ul>
<p>const b = -3;    // 1111111111111101
console.log(~b); // 0000000000000010
// expected output: 2</p>
<pre><code>
- **double tilde(~~)**: Math.floor()와 같은 역할
    - 속도측면에서 빠름 (`~~`&gt; `Math.floor`&gt; `parseInt`)
```js
console.log(~~(-4.7)) // -4
console.log(~~(3.7))  // 3</code></pre><hr>
<h3 id="✅최대공약수gcd-최소공배수lcm---유클리드-호제법">✅최대공약수(gcd), 최소공배수(lcm) - 유클리드 호제법</h3>
<blockquote>
<p><strong>유클리드 호제법</strong>: 두 수가 서로 상대방 수를 나누어서 결국 원하는 수를 얻는 알고리즘</p>
</blockquote>
<ul>
<li><strong>최대공약수 (gcd)</strong><ul>
<li>두 수 A와 B의 공통된 약수 중에 가장 큰 정수</li>
</ul>
</li>
</ul>
<p>방법1: 재귀 이용⭕</p>
<pre><code class="language-js">let getGCD = (num1, num2) =&gt; (num2 &gt; 0 ? getGCD(num2, num1 % num2) : num1);</code></pre>
<p>방법2: 재귀 이용❌</p>
<pre><code class="language-js">let getGCD2 = (num1, num2) =&gt; {

    while(num2 &gt; 0){
        let r = num1 % num2;
        num1 = num2;
        num2 = r;
    } 

    return num1;
}</code></pre>
<br/>

<ul>
<li><p><strong>최소공배수</strong></p>
<ul>
<li>두 수, 혹은 그 이상의 여러 수의 공통인 배수 중 가장 작은 수<pre><code class="language-js">let getLCM = (num1, num2) =&gt;{
let lcm = 1;
</code></pre>
</li>
</ul>
<p>while(true){
  if((lcm % num1 == 0) &amp;&amp; (lcm % num2 == 0)) break;
  lcm++;
}
return lcm
}</p>
<pre><code></code></pre></li>
</ul>
<hr>
<h3 id="✅map-has-set-get">✅map, has, set, get</h3>
<p>(추후 자세히 정리하여 올릴 예정)</p>
<hr>
<h3 id="✅문자열-역순---내장함수--반복">✅문자열 역순 - 내장함수 / 반복</h3>
<p>방법1. 내장함수 이용 - <code>split()</code>, <code>reverse()</code>, <code>join()</code></p>
<pre><code class="language-js">function reverseString(str) {
    var splitString = str.split(&quot;&quot;); 
    var reverseArray = splitString.reverse(); 
    var joinArray = reverseArray.join(&quot;&quot;); 
    return joinArray; 
}
reverseString(&quot;hello&quot;); // &quot;olleh&quot;
</code></pre>
<p>방법2. for문 이용</p>
<pre><code class="language-js">function reverseString(str) {
    var newString = &quot;&quot;;
    for (var i = str.length - 1; i &gt;= 0; i--) { 
        newString += str[i]; 
    }
    return newString; 
}

reverseString(&#39;hello&#39;);// &quot;olleh&quot;</code></pre>
<hr>
<h2 id="👀풀이-코드-20문제">👀풀이 코드 (20문제)</h2>
<h3 id="1-두-수의-합">1. 두 수의 합</h3>
<pre><code class="language-js">def solution(num1, num2):
    answer = -1

    answer = num1 + num2
    return answer</code></pre>
<hr>
<h3 id="2-두-수의-차">2. 두 수의 차</h3>
<pre><code class="language-js">function solution(num1, num2) {
    var answer = 0;
    answer = num1 - num2
    return answer;
}</code></pre>
<hr>
<h3 id="3-두-수의-곱">3. 두 수의 곱</h3>
<pre><code class="language-js">function solution(num1, num2) {
    var answer = 0;
    answer = num1 * num2
    return answer;
}</code></pre>
<hr>
<h3 id="4-몫-구하기">4. 몫 구하기</h3>
<pre><code class="language-js">function solution(num1, num2) {
    var answer = 0;
    answer = ~~(num1/num2)
    return answer;
}</code></pre>
<hr>
<h3 id="5-두-수의-나눗셈">5. 두 수의 나눗셈</h3>
<pre><code class="language-js">function solution(num1, num2) {
    var answer = Math.floor(num1 / num2 * 1000)
    return answer;
}</code></pre>
<hr>
<h3 id="6-숫자-비교하기">6. 숫자 비교하기</h3>
<pre><code class="language-js">function solution(num1, num2) {
    if (num1 == num2){
        return 1
    } else { return -1 }
}</code></pre>
<hr>
<h3 id="7-✔️분수의-덧셈">7. ✔️분수의 덧셈</h3>
<pre><code class="language-js">function cal_gcd(a, b) {
    return a % b === 0 ? b : cal_gcd(b, a % b)
}

function solution(denum1, num1, denum2, num2) {
    let denum = denum1 * num2 + denum2 * num1;
    let num = num1 * num2;
    let gcd = cal_gcd(denum, num);

    return [denum / gcd, num / gcd]
}</code></pre>
<hr>
<h3 id="8-배열-두-배-만들기">8. 배열 두 배 만들기</h3>
<pre><code class="language-js">function solution(numbers) {
    var answer = [];
    for (let num of numbers){
        answer.push(num*2)
    }
    return answer;
}</code></pre>
<hr>
<h3 id="9-나머지-구하기">9. 나머지 구하기</h3>
<pre><code class="language-js">function solution(num1, num2) {
    var answer = num1 % num2;
    return answer;
}</code></pre>
<hr>
<h3 id="10-중앙값-구하기">10. 중앙값 구하기</h3>
<pre><code class="language-js">function solution(array) {
    var answer = 0;
    array = array.sort((a,b) =&gt; a-b)
    answer = parseInt(array.length / 2)
    return array[answer]
}</code></pre>
<hr>
<h3 id="11-✔️최빈값-구하기">11. ✔️최빈값 구하기</h3>
<pre><code class="language-js">function solution(array) {
    let counting = new Map();
    let countArray = new Array;
    let maxKey;
    let maxValue = -1;
    let hasMultipleMaxValues = false;

    for (let i of array){
        if (!counting.has(i)){
            counting.set(i,1);
        }else if (counting.has(i)){
            counting.set(i, counting.get(i)+1);
        }
    }

    for (let [key, value] of counting) {
        if (value &gt; maxValue) {
            maxValue = value;
            maxKey = key;
            hasMultipleMaxValues = false;
        }else if (value === maxValue) {
            hasMultipleMaxValues = true;
        }
    }
    return (hasMultipleMaxValues) ? -1: maxKey;
}</code></pre>
<hr>
<h3 id="12-짝수는-싫어요">12. 짝수는 싫어요</h3>
<ul>
<li><code>n</code>이하의 홀수가 오름차순으로 담긴 배열 출력<pre><code class="language-js">function solution(n) {
  var answer = [];
  for (i=0; i&lt;=n; i++){
      if (i%2 != 0){
          answer.push(i)
      }
  }
  return answer;
}</code></pre>
</li>
</ul>
<hr>
<h3 id="13-피자-나눠먹기1">13. 피자 나눠먹기(1)</h3>
<ul>
<li>일곱조각의 피자를 <code>n</code>명이 나눠먹을때, 모든 사람이 한 조각 이상 먹기 위해 필요한 피자의 수<pre><code class="language-js">function solution(n) {
  return Math.ceil(n/7)
}</code></pre>
</li>
</ul>
<hr>
<h3 id="14-피자-나눠먹기2">14. 피자 나눠먹기(2)</h3>
<pre><code class="language-js">function solution(n) {
    let pizza = 6;
    while (pizza % n !== 0) {
        pizza += 6
    } return pizza / 6
}</code></pre>
<hr>
<h3 id="15-피자-나눠먹기3">15. 피자 나눠먹기(3)</h3>
<ul>
<li>피자 조각 수 <code>slice</code></li>
<li>피자를 먹는 사람의 수 <code>n</code></li>
</ul>
<pre><code class="language-js">function solution(slice, n) {
    var answer = 0;
    return answer = Math.ceil(n/slice);
}</code></pre>
<hr>
<h3 id="16-배열의-평균값">16. 배열의 평균값</h3>
<pre><code class="language-js">function solution(numbers) {
    var num = 0;
    for (i = 0; i &lt; numbers.length; i++){
        num += numbers[i]
    }
    return num/numbers.length;
}</code></pre>
<hr>
<h3 id="17-옷가게-할인-받기">17. 옷가게 할인 받기</h3>
<ul>
<li>10만 원 이상 사면 5% 할인</li>
<li>30만 원 이상 사면 10% 할인</li>
<li>50만 원 이상 사면 20% 할인<pre><code class="language-js">function solution(price) {
  var answer = 0;
  if (price &gt;= 500000){
      return Math.floor(price*0.8)
  }else if (500000 &gt; price &amp;&amp; price &gt;= 300000){
      return Math.floor(price*0.9)
  }else if (300000 &gt; price &amp;&amp; price &gt;= 100000){
      return Math.floor(price*0.95)
  }else{
      return price
  }
}</code></pre>
</li>
</ul>
<hr>
<h3 id="18-아이스-아메리카노">18. 아이스 아메리카노</h3>
<ul>
<li>아이스 아메리카노: 한잔에 5,500원</li>
<li><code>money</code>로 최대로 마실 수 있는 아메리카노의 잔 수와 남는 돈 출력<pre><code class="language-js">function solution(money) {
  var answer = [];
  answer.push(parseInt(money/5500))
  money = money - 5500 *(parseInt(money/5500))
  answer.push(money)
  return answer;
}</code></pre>
</li>
</ul>
<hr>
<h3 id="19-나이-출력">19. 나이 출력</h3>
<ul>
<li>2022년을 기준 출생 연도 출력<pre><code class="language-js">function solution(age) {
  var answer = 0;
  answer = 2023 - age;
  return answer;
}</code></pre>
</li>
</ul>
<hr>
<h3 id="20-배열-뒤집기">20. 배열 뒤집기</h3>
<pre><code class="language-js">function solution(num_list) {
    var answer = [...num_list].reverse();
    return answer;
}</code></pre>
<hr>
<ul>
<li>참고자료
<a href="https://hianna.tistory.com/446">Math ceil, floor, round</a>
<a href="https://velog.io/@devjade/JavaScript%EB%A1%9C-%EC%B5%9C%EB%8C%80%EA%B3%B5%EC%95%BD%EC%88%98GCD-%EC%B5%9C%EC%86%8C%EA%B3%B5%EB%B0%B0%EC%88%98LCM-%EA%B5%AC%ED%95%98%EA%B8%B0">JS 최대공약수, 최소공배수</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] Python - 15649번: N과 M (1)]]></title>
            <link>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-15649%EB%B2%88-N%EA%B3%BC-M-1</link>
            <guid>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-15649%EB%B2%88-N%EA%B3%BC-M-1</guid>
            <pubDate>Sun, 12 Nov 2023 17:42:41 GMT</pubDate>
            <description><![CDATA[<h1 id="15649번">15649번</h1>
<h2 id="문제입력출력">문제/입력/출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/d2ce3ad3-4468-40a6-9c87-91529eda4d5d/image.png" alt=""></p>
<h2 id="예제-입출력">예제 입출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/8014aac4-0a8b-44a9-b1e7-b7309038c987/image.png" alt=""></p>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://www.acmicpc.net/problem/15649">백준 15659번</a></p>
<hr>
<h2 id="💡풀이-방법">💡풀이 방법</h2>
<blockquote>
<ol>
<li>1부터 검사 -&gt; 끝까지 출력하면, 그 다음 순서 진행<ul>
<li>1부터 n까지 반복 (<code>for i in range(1, n+1)</code>)<ol start="2">
<li>길이가 <code>m</code>이라면 return </li>
<li><strong><code>dfs</code> 이용!</strong></li>
</ol>
</li>
</ul>
</li>
</ol>
</blockquote>
<p> <img src="https://velog.velcdn.com/images/minz-cha/post/3fb1cdc6-94b6-4369-b72c-8d5914235a84/image.png" alt=""></p>
<h2 id="💡구현-코드">💡구현 코드</h2>
<pre><code class="language-python"> n,m = list(map(int,input().split()))
s = []

def dfs():
    if len(s)==m:
        print(&#39; &#39;.join(map(str,s)))
        return

    for i in range(1,n+1):
        if i not in s:

            s.append(i)
            dfs()
            s.pop()
dfs()</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] Python - 2606번: 바이러스]]></title>
            <link>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-2606%EB%B2%88-%EB%B0%94%EC%9D%B4%EB%9F%AC%EC%8A%A4</link>
            <guid>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-Python-2606%EB%B2%88-%EB%B0%94%EC%9D%B4%EB%9F%AC%EC%8A%A4</guid>
            <pubDate>Wed, 08 Nov 2023 01:02:19 GMT</pubDate>
            <description><![CDATA[<p>내가 제일 취약해하는 DFS, BFS 문제이다..
항상 기피하던 알고리즘 중 하나인데 언제까지 피할 수만은 없으니, 기왕이면 며칠간 꾸준히 풀면서 간파해버리자👀‼️</p>
<h1 id="2606번">2606번</h1>
<h2 id="문제입력출력">문제/입력/출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/d3a02608-fe0a-4a31-ac63-1b139cdaf9a8/image.png" alt=""></p>
<h2 id="예제-입력-및-출력">예제 입력 및 출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/444e2d06-831e-4e43-856e-51d489253949/image.png" alt=""></p>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://www.acmicpc.net/problem/2606">백준 2606번</a></p>
<hr>
<h2 id="💡풀이-방법">💡풀이 방법</h2>
<p>우선 해당 문제는 <code>DFS</code> 알고리즘을 이용하였다.
1에서부터 이어지는 모든 컴퓨터들을 방문하여 확인해야한다.</p>
<p>나같이 dfs, bfs 문제에 약한 사람들은 접근 자체를 어떻게 해야할지 막막할 수 있다.
나는 아래와 같은 순서로 접근하였다.</p>
<blockquote>
<ol>
<li>특정 컴퓨터와 이어진 컴퓨터의 숫자값을 각 배열에 추가한다.<ul>
<li>예를 들어, 1번이 2번과 이어져 있다면, <code>array_1</code>에 2라는 값을 추가해주고, <code>array_2</code>에는 1을 추가해준다.<ol start="2">
<li>컴퓨터 수+1만큼의 length를 가지는 배열(<code>visit</code>)을 선언해준다.</li>
</ol>
<ul>
<li>이는 바이러스가 방문했을 경우: 1, 안했다면: 0이 된다.</li>
</ul>
</li>
<li>모든 인덱스의 default값: 0<ol start="3">
<li><code>dfs</code>를 통해 <code>visit</code>값을 set한다.</li>
</ol>
<ul>
<li><code>array_1</code>부터 시작했을 때, <code>array_1</code>에 들어있는 값은 컴퓨터 1번과 이어져있다는 뜻. 즉, 배열1에 저장되어있는 값의 배열에 방문하여 또 다시 <code>visit</code>값을 <code>1</code>로 set.</li>
</ul>
</li>
<li>ex. <code>array_1 = [3,4]</code>라면, <code>visit</code>의 3번째, 4번째의 값을 <code>1</code>로 set하고, <code>array_3</code>에 접근하여 해당 배열에 저장된 숫자 값도 <code>visit</code>값을 1로 set</li>
</ul>
</li>
</ol>
</blockquote>
<hr>
<h2 id="💡구현-코드">💡구현 코드</h2>
<ol>
<li>특정 컴퓨터와 이어진 컴퓨터의 숫자값을 각 배열에 추가한다.<pre><code class="language-python">n = int(input()) #컴퓨터 수 
m = int(input()) #간선 (이어진 쌍의 수)
</code></pre>
</li>
</ol>
<p>graph = [[] for _ in range(n+1)] #컴퓨터 수 +1 만큼의 배열</p>
<h1 id="간선-수만큼-반복">간선 수만큼 반복</h1>
<p>for i in range(m): 
    x, y = map(int, input().split())</p>
<pre><code>graph[x].append(y)
graph[y].append(x)</code></pre><pre><code>
&lt;br/&gt;

2. 컴퓨터 수(n)+1만큼의 length를 가지는 배열(`visit`)을 선언해준다.
- 컴퓨터 수+1만큼으로 지정하는 이유: 컴퓨터 1번이 방문한 값을 확인하려면 인덱스 값과 동일하게 맞춰주는 것이 편하기 때문 (인덱스 1번 == 컴퓨터 1번이 방문한 컴퓨터)
```python
visit = [0] * (n+1)</code></pre><br/>

<ol start="3">
<li><code>dfs</code>를 통해 <code>visit</code>값을 1로 set한다.<pre><code class="language-python">def dfs(graph, v, visited):
 visit[v] = 1
 for i in graph[v]:
     if visit[i] == 0:
         dfs(graph, i, visited)
</code></pre>
</li>
</ol>
<p>dfs(graph, 1, visit)            </p>
<pre><code>
---

### 👀전체 코드
```python
n = int(input())
m = int(input())

graph = [[] for _ in range(n+1)]

for i in range(m):
    x, y = map(int, input().split())

    graph[x].append(y)
    graph[y].append(x)

visit = [0] * (n+1)

def dfs(graph, v, visited):
    visit[v] = 1
    for i in graph[v]:
        if visit[i] == 0:
            dfs(graph, i, visited)

dfs(graph, 1, visit)
print(visit.count(1) - 1)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] HTML 관련 개념]]></title>
            <link>https://velog.io/@minz-cha/CS-HTML-%EA%B4%80%EB%A0%A8-%EB%A9%B4%EC%A0%91-CS</link>
            <guid>https://velog.io/@minz-cha/CS-HTML-%EA%B4%80%EB%A0%A8-%EB%A9%B4%EC%A0%91-CS</guid>
            <pubDate>Mon, 06 Nov 2023 16:49:00 GMT</pubDate>
            <description><![CDATA[<p>(면접에 나올법한 부분들을 위주로 정리를 해보려고 한다.)</p>
<h1 id="📁html">📁HTML</h1>
<p><strong>Hyper Text Markup Laungauge</strong></p>
<h2 id="📁html-문서-골격">📁HTML 문서 골격</h2>
<h3 id="doctype이란">DOCTYPE이란?</h3>
<p>쉽게 말해, 문서의 타입을 지정</p>
<ul>
<li>세가지 문서 유형: HTML5, XHTML, HTML</li>
<li>일관된 렌더링을 위해 DOCTYPE 명시하는 것이 중요</li>
</ul>
<h3 id="head의-meta-태그"><code>&lt;head&gt;</code>의 meta 태그</h3>
<ul>
<li>&#39;데이터에 대한 데이터&#39;, &#39;어떤 목적으로 만들어진 데이터&#39;를 의미</li>
<li>인코딩 방식, 뷰포트 지정뿐만 아니라 더 많은 작업 수행</li>
</ul>
<br/>

<h2 id="📁시맨틱-태그-semantic-tag">📁시맨틱 태그 (Semantic tag)</h2>
<ul>
<li>의미에 맞는 태그를 사용해 문서를 작성하는 것</li>
<li>특별한 의미가 없는 <code>&lt;div&gt;</code> 태그 대신 <code>&lt;section&gt;</code> <code>&lt;article&gt;</code> <code>&lt;nav&gt;</code> <code>&lt;footer&gt;</code> <code>&lt;aside&gt;</code>와 같은 태그를 상황에 따라 사용하는 것</li>
</ul>
<table>
<thead>
<tr>
<th>태그</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>header</td>
<td>페이지 제목, 소개 글, 로고 or 아이콘, 검색 양식 등</td>
</tr>
<tr>
<td>nav</td>
<td>메뉴, 목차</td>
</tr>
<tr>
<td>aside</td>
<td>간접적으로 문서와 관련된 내용</td>
</tr>
<tr>
<td>main</td>
<td>지배적인 콘텐츠 영역 나타냄</td>
</tr>
<tr>
<td>section</td>
<td>구체적인 시맨틱 태그가 없는 문서의 독립적인 영역</td>
</tr>
<tr>
<td>article</td>
<td>독립적인 배포 또는 재사용되도록 의도된 문서 (게시글, 잡지, 블로그 작성글, 대화형 위젯 등 )</td>
</tr>
<tr>
<td>footer</td>
<td>섹션의 작성자에 대한 정보, 저작권 데이터, 문서링크 포함</td>
</tr>
<tr>
<td>em, strong</td>
<td>em: 기울기체, strong: 볼드체</td>
</tr>
<tr>
<td>p</td>
<td>HTML 문서의 단락 정의</td>
</tr>
</tbody></table>
<h3 id="article-vs-section"><code>&lt;article&gt;</code> vs <code>&lt;section&gt;</code></h3>
<ol>
<li>** <code>&lt;article&gt;</code>** : 요소 자체가 하나의 의미 있는 콘텐츠 블록 영역<ul>
<li>독립적으로 배포되거나 재사용</li>
</ul>
</li>
<li>** <code>&lt;section&gt;</code>** : 페이지의 단일 부분을 그룹화하는데에 유용<ul>
<li>요소의 콘텐츠를 함께 묶는 것이 합리적일 때 사용</li>
</ul>
</li>
</ol>
<br/>

<h2 id="📁seo-search-engine-optimization">📁SEO (Search Engine Optimization)</h2>
<p>사이트를 잘 찾기 쉽도록하는 <strong>검색 엔진 최적화</strong></p>
<ol>
<li>시멘틱하게 HTML 작성</li>
<li><code>&lt;title&gt;</code>을 놓치지 말고 적절하게 작성</li>
<li><code>&lt;meta name=&quot;description&quot;&gt;</code> 이용</li>
<li><code>&lt;meta charset=&quot;UTF-8&quot;&gt;</code> 이용</li>
</ol>
<h2 id="📁html-요소-분류">📁HTML 요소 분류</h2>
<ul>
<li>요소(3가지): Content(내용), Start Tag(시작 태그), End Tag(종료 태그)</li>
</ul>
<h3 id="인라인-vs-블록">인라인 vs 블록</h3>
<ol>
<li><p><strong>인라인 요소 (inline)</strong></p>
<ul>
<li>텍스트나 이미지의 크기에 맞는 필요한 공간만을 차지</li>
<li>높이나 너비를 지정할 수 없으며, 줄 내부 어디서든 시작 </li>
<li>ex) <code>&lt;span&gt;</code> <code>&lt;button&gt;</code> <code>&lt;img&gt;</code></li>
</ul>
</li>
<li><p><strong>블록 요소 (block)</strong></p>
<ul>
<li>이전 요소와 상관없이 개행해 새로운 줄에서 시작</li>
<li>너비는 좌우 양쪽으로 부모의 100% 차지</li>
<li>ex) <code>&lt;div&gt;</code> <code>&lt;article&gt;</code> <code>&lt;form&gt;</code></li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] HTTP(2) - HTTPS, CORS, SOP]]></title>
            <link>https://velog.io/@minz-cha/CS-HTTP2-HTTPS-CORS-SOP</link>
            <guid>https://velog.io/@minz-cha/CS-HTTP2-HTTPS-CORS-SOP</guid>
            <pubDate>Tue, 31 Oct 2023 05:03:52 GMT</pubDate>
            <description><![CDATA[<h2 id="📁https-hyper-transfer-protocol">📁HTTPS (Hyper Transfer Protocol)</h2>
<aside>
💡 HTTP 프로토콜의 문제점
- 서버에서부터 브라우저로 전송되는 정보가 암호화되지 않는다는 점

</aside>

<ul>
<li>이러한 HTTP의 문제점을 HTTPS 프로토콜은 <code>SSL(보안 소켓 계층)</code>을 사용함으로써 해결</li>
<li><strong>SSL</strong> - 서버와 브라우저 사이에 안전하게 암호화된 연결을 만들 수 있게 도와주고 서버 브라우저가 민감한 정보를 주고받을 때, 이가 도난 당하는 것을 막아줌<ul>
<li>사용자가 사이트에 제공하는 정보를 암호화</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/8b66ed26-115f-4f46-9d50-8ec161609eff/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/d91aee54-0d30-4b24-a782-dfebd2ea1b2d/image.png" alt=""></p>
<ul>
<li>HTTPS는 <code>TLS(전송 계층 보안)</code> 프로토콜을 통해서도 보안 유지<ul>
<li><strong>TLS</strong> - 데이터 무결성을 제공하기 때문에 데이터가 전송 중에 수정되거나 손상되는 것을 방지, 인증 기능도 제공</li>
</ul>
</li>
</ul>
<hr>
<h2 id="📁출처-url의-구성">📁출처 (URL의 구성)</h2>
<ul>
<li><strong>Protocol + Host + Port</strong> 가 같으면 동일 출처(Origin)이라고 한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/64037d67-b654-4a75-ab54-9eb71585a34f/image.png" alt=""></p>
<table>
<thead>
<tr>
<th>동일 출처 예시</th>
<th></th>
</tr>
</thead>
<tbody><tr>
<td><a href="http://Example.com:80">http://Example.com:80</a>, <a href="http://example.com">http://example.com</a></td>
<td>HTTP 기본 Port인 80번이 생략되어있으므로 동일 출처</td>
</tr>
<tr>
<td><a href="http://example.com/app1/index.html">http://example.com/app1/index.html</a>, <a href="http://example.com/app2/index.html">http://example.com/app2/index.html</a></td>
<td>Protocol, Host, Port(생략)이 같으며, Path부터 다르므로 동일 출처</td>
</tr>
</tbody></table>
<br/>

<table>
<thead>
<tr>
<th>다른 출처 예시</th>
<th></th>
</tr>
</thead>
<tbody><tr>
<td><a href="http://example.com/app1">http://example.com/app1</a>, <a href="https://example.com/app2">https://example.com/app2</a></td>
<td>Protocol이 다름</td>
</tr>
<tr>
<td><a href="http://example.com">http://example.com</a>, <a href="http://www.example.com">http://www.example.com</a>, <a href="http://myapp.example.com">http://myapp.example.com</a></td>
<td>Host가 다름</td>
</tr>
<tr>
<td><a href="http://example.com">http://example.com</a>, <a href="http://example.com:8080">http://example.com:8080</a></td>
<td>80, 8080으로 포트가 다름</td>
</tr>
</tbody></table>
<hr>
<h2 id="📁cors-cross-origin-resource-sharing-교차-출처-자원-공유">📁CORS (Cross-Origin Resource Sharing, 교차 출처 자원 공유)</h2>
<ul>
<li>출처가 다른 자원들을 공유한다는 뜻</li>
<li>한 출처에 있는 자원에서 다른 출처에 있는 자원에 접근하도록 하는 개념</li>
</ul>
<h3 id="다른-출처의-위험성">다른 출처의 위험성</h3>
<ul>
<li>CORS 정책이 없고 모든 다른 출처 요청이 가능한 경우</li>
<li>굉장히 중요한/유용한 정보를 담고 있는 사이트도 열람 가능</li>
</ul>
<ul>
<li><strong>예시⤵️</strong><blockquote>
<p>🗣 홈페이지를 서핑하고 있는데, script가 심어진 evil.com 페이지를 열었다고 가정하자.
굉장히 유용한 정보를 담고 있는 사이트이지만, 페이지를 열면서 script가 실행되어 은행에 &#39;Delete /account&#39;를 요청하도록 되어 있다. 
결국 AJAX 호출로 은행 API를 호출하여 나의 은행 계좌를 삭제해버리는 사고가 발생한다.</p>
</blockquote>
</li>
</ul>
<hr>
<h2 id="📁sop-same-origin-policy-동일-출처-정책">📁SOP (Same-Origin Policy, 동일 출처 정책)</h2>
<ul>
<li>다른 출처로부터 조회된 자원들의 읽기 접근을 막아 다른 출처 공경을 예방</li>
<li>단, 다른 출처에서 얻은 이미지를 담는 <code>&lt;img&gt;</code>, 외부 주소를 담는 <code>&lt;link&gt;</code> 같은 여러 태그들을 허용</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] HTTP(1) - HTTP의 특징, Connectionless, Stateless ]]></title>
            <link>https://velog.io/@minz-cha/CS-HTTP1-HTTP%EC%9D%98-%ED%8A%B9%EC%A7%95-Connectionless-Stateless</link>
            <guid>https://velog.io/@minz-cha/CS-HTTP1-HTTP%EC%9D%98-%ED%8A%B9%EC%A7%95-Connectionless-Stateless</guid>
            <pubDate>Sun, 22 Oct 2023 17:09:18 GMT</pubDate>
            <description><![CDATA[<h2 id="📁http-hyper-transfer-protocol">📁HTTP (Hyper Transfer Protocol)</h2>
<ul>
<li>서버/클라이언트 간 웹페이지 같은 자원을 주고받을 때 쓰는 통신 규약</li>
<li>WWW 상에서 웹페이지나 이미지 같은 정보를 요청과 응답에 의해 주고받는 프로토콜</li>
</ul>
<br/>

<h2 id="📁http-특징">📁HTTP 특징</h2>
<h3 id="1-request--response">1. <strong>Request &amp; Response</strong></h3>
<pre><code>- 클라이언트가 서버로 HTTP 요청 보내면 서버는 요청에 대한 결과를 만들어서 응답</code></pre><p><img src="https://velog.velcdn.com/images/minz-cha/post/afee0ad1-49a0-41a7-92e8-203d5c47b734/image.png" alt=""></p>
<h3 id="2-connectionless-비연결성">2. <strong>Connectionless (비연결성)</strong></h3>
<pre><code>- 클라이언트와 서버가 한 번 연결을 맺은 후, 클라이언트 요청에 대해 
서버가 응답을 마치면 맺었던 연결을 끊어버리는 성질</code></pre><ul>
<li>장점: 연결 유지를 위한 <strong>리소스를 줄이면 더 많은 연결</strong>을 할 수 있음</li>
<li>단점: 서버는 클라이언트를 기억하고 있지 않기 때문에, 매번 새로운 연결을 시도/해제의 과정을 거쳐야하므로 <strong>연결 및 해제에 대한 오버헤드 발생</strong></li>
</ul>
<h3 id="3-stateless-무상태">3. <strong>Stateless (무상태)</strong></h3>
<pre><code>클라이언트: 전에 뭘 보냈었지? 
서버: 전에 뭘 보냈었지?</code></pre><ul>
<li>HTTP에서 요청을 보낼 때 마다 새로운 응답이 생성</li>
<li>클라이언트와 서버가 서로 연결되어 있는 것이 아니기 때문에 각각의 통신이 독립적</li>
<li>서버가 클라이언트의 상태를 유지하지 않기 때문에 요청을 보낼 때마다 모든 데이터를 매번 보내야함</li>
<li>클라이언트가 서버에 요청할 때 데이터를 담아서 보내기 때문에 아무 서버나 호출해도 됨</li>
</ul>
<br/>    

<hr>
<h2 id="connectionless-단점-극복---keepalive">Connectionless 단점 극복 - KeepAlive</h2>
<ul>
<li>오버헤드를 줄이기 위해 <strong>HTTP1.1</strong>에서 <strong><code>KeepAlive</code></strong> 제공하여 한번에 여러 요청-응답 가능</li>
<li>지정된 시간동안 서버와 클라이언트 사이에서 패킷 교환이 없을 경우, 상대방의 안부를 묻기 위해 패킷을 주기적으로 전송 → 이때 반응이 없으면 접속을 끊게 됨<ul>
<li>주기적으로 클라이언트의 상태를 체크 → 근본적인 해결책 X</li>
</ul>
</li>
</ul>
<br/>    

<hr>
<h2 id="stateless-단점-극복---1-cookie">Stateless 단점 극복 - (1) Cookie</h2>
<p><strong>🍪 stateless이기 때문에, 상태값을 사용할 수 없음 → 단점보완 / 대안책?</strong></p>
<ul>
<li><strong>쿠키(Cookie):</strong> 서버에서 응답으로 보내진 <code>Set-Cookie</code> 라는 <strong>헤더 필드</strong>에 의해 쿠키를 클라이언트에 보존하게 됨<ul>
<li>클라이언트가 다음번에도 같은 서버로 요청을 보내면 자동적으로 쿠키를 싣어서 송신하고, 서버는 클라이언트가 같이 보낸 쿠키를 통해 상태를 관리하고 체크하여 그에 맞는 응답을 보냄</li>
</ul>
</li>
</ul>
<br/>    

<h2 id="stateless-단점-극복---2-session">Stateless 단점 극복 - (2) Session</h2>
<p><strong>🌐 쿠키는 사용자 정보가 브라우저에 저장되기 때문에 보안에 취약함 → 단점보완</strong></p>
<ul>
<li><strong>세션(Session):</strong> 브라우저가 아닌 서버에서 사용자 정보를 저장하는 구조<ul>
<li>서버의 메모리를 차지하게 되고, 만약 동시 접속자 수가 많은 서비스의 경우, 서버 과부화의 원인이 될 수 있음</li>
</ul>
</li>
</ul>
<br/>  

<h3 id="👀쿠키와-세션-비교상대적">👀쿠키와 세션 비교(상대적)</h3>
<table>
<thead>
<tr>
<th></th>
<th>Cookie</th>
<th>Session</th>
</tr>
</thead>
<tbody><tr>
<td>보안</td>
<td>취약</td>
<td>쿠키보다 나음</td>
</tr>
<tr>
<td>속도</td>
<td>빠름</td>
<td>느림</td>
</tr>
<tr>
<td>종료</td>
<td>브라우저 종료 시 남아있음</td>
<td>만료 시간에 상관없이 브라우저 종료 시 삭제</td>
</tr>
</tbody></table>
<br/>    

<h2 id="stateless-단점-극복---3-token-사용-oauth-jwt">Stateless 단점 극복 - (3) Token 사용 (OAuth, JWT)</h2>
<p>🔒 <strong>쿠키와 세션의 단점보완</strong></p>
<ul>
<li><strong>Token 기반의 인증 방식 :</strong> 보호할 데이터를 토큰으로 치환하여 원본 데이터 대신 토큰 사용<ul>
<li>중간에 공격자로부터 토큰이 탈취당하더라도 데이터에 대한 정보를 알 수 없으므로, 보안성이 높음</li>
<li>대표적으로는 <strong><code>OAuth</code></strong>와 <strong><code>JWT</code></strong>이 있습니다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] Python - 1018번: 체스판 다시 칠하기]]></title>
            <link>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-1018%EB%B2%88-%EC%B2%B4%EC%8A%A4%ED%8C%90-%EB%8B%A4%EC%8B%9C-%EC%B9%A0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minz-cha/%EB%B0%B1%EC%A4%80-1018%EB%B2%88-%EC%B2%B4%EC%8A%A4%ED%8C%90-%EB%8B%A4%EC%8B%9C-%EC%B9%A0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 16 Oct 2023 07:23:03 GMT</pubDate>
            <description><![CDATA[<h1 id="1018번">1018번</h1>
<h2 id="문제--입력--출력">문제 / 입력 / 출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/61e2f1c1-ef98-41cb-be48-6fb24b7a5d01/image.png" alt=""></p>
<h2 id="예제-입력-및-출력">예제 입력 및 출력</h2>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/e7eaf548-4180-4304-9613-209f55d029bc/image.png" alt=""></p>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://www.acmicpc.net/problem/1018">백준 1018번</a></p>
<hr>
<h2 id="💡풀이-방법">💡풀이 방법</h2>
<p>.</p>
<ol>
<li><p>n, m 값 입력받기</p>
</li>
<li><p>길이 m으로 이루어져있는 문자열 <code>B</code>, <code>W</code>을 n개 입력받기</p>
</li>
<li><p><strong>각 입력받은 문자열 한 줄씩 검사</strong></p>
<p> 3-1. 만약 문자열이 &#39;BBBBBBBBBWBW&#39;로 이루어질 때, (1)보다 (2)가 더 문자열 바꿀 경우가 적기 때문에 (2)가 더 효율적이며 최솟값을 출력함</p>
<p> 3-2. <strong>체스판이 8X8이므로, 주어진 문자열 길이에 따라 검사 횟수가 달라짐</strong>
 ex) 문자열이 12일 경우, 총 검사하게 될 횟수는 5개</p>
<pre><code> (BBBBBBBB, BBBBBBBB,BBBBBBBW, BBBBBBWB, BBBBBWBW)</code></pre><p><img src="https://velog.velcdn.com/images/minz-cha/post/9393129d-1032-4178-897b-aadb8c27f1dd/image.png" alt=""></p>
</li>
<li><p><code>i,j</code>를 기준으로 <strong>(a,b)</strong>에서 <strong>a+b</strong>값이 짝수인 경우 같은 문자이고, 홀수인 경우 다른 문자이다.</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/minz-cha/post/b1e53d7d-2196-43e8-9b66-283bc229c987/image.png" alt=""></p>
<h2 id="💡구현-코드">💡구현 코드</h2>
<pre><code class="language-python">n, m = map(int, input().split())
board = []
result = []

for _ in range(n):
    board.append(input())

for i in range(n - 7):
    for j in range(m - 7):
        # 첫번째 문자열이 B인 경우와 W인 경우를 나눠서 검사
        first_B = 0
        first_W = 0

        for a in range(i, i + 8):
            for b in range(j, j + 8):
                if (a + b) % 2 == 0:
                    # i+j과 a+b의 값 차이가 짝수일 경우 같은 값을 가짐
                    if board[a][b] != &#39;B&#39;:
                        first_B += 1
                    if board[a][b] != &#39;W&#39;:
                        first_W += 1
                else:
                    if board[a][b] != &#39;W&#39;:
                        fi rst_B += 1
                    if board[a][b] != &#39;B&#39;:
                        first_W += 1

        result.append(first_B)
        result.append(first_W)

print(min(result))</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Firebase를 통해 회원가입, 로그인, 로그아웃 기능 구현]]></title>
            <link>https://velog.io/@minz-cha/React-Firebase%EB%A5%BC-%ED%86%B5%ED%95%B4-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@minz-cha/React-Firebase%EB%A5%BC-%ED%86%B5%ED%95%B4-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Mon, 16 Oct 2023 06:29:18 GMT</pubDate>
            <description><![CDATA[<h1 id="🔥firebase">🔥Firebase</h1>
<p>Firebase에 대해 간단한 개념을 우선 정리해보자.</p>
<blockquote>
<p>Firebase : 실시간 DB, 인증, 스토리지, 분석 등 다양한 기능을 제공하는 모바일/웹앱 개발 플랫폼</p>
</blockquote>
<p>1) <span style="color:orange"><strong>Authentication</strong></span>: 간편한 다중 플랫폼 로그인
    - 이메일 인증, 소셜미디어 계정 인증, 전화번호 인증방식 제공
    - 보안강화, 사용자 인증 과정 안전하게 처리
2) <span style="color:orange"><strong>FireStore</strong></span>: NoSQL DB
    - Firebase에서 제공하는 NoSQL형식의 클라우드 DB
    - 실시간 데이터 동기화 지원 (ex. 실시간 채팅)
3) <span style="color:orange"><strong>Storage</strong></span>: 사진 및 동영상 저장
    - 사용자 파일 저장 및 공유, 강력한 보안
4) <span style="color:orange"><strong>Hosting</strong></span>: 웹앱 호스팅
    - 정적 및 동적 콘텐츠 모두 호스팅 가능, 웹앱 간단 배포</p>
<h3 id="장점">장점</h3>
<ul>
<li>백엔드 서버 없이 개발 가능</li>
<li>실시간 데이터베이스</li>
<li>Google 플랫폼 통합</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>쿼리 제한</li>
<li>비용</li>
<li>migration 어려움</li>
</ul>
<hr>
<h1 id="코드-살펴보기">코드 살펴보기</h1>
<h2 id="👀firebase-연동">👀Firebase 연동</h2>
<ul>
<li><strong>firebaseConfig</strong><ul>
<li>Firebase 연동에 필요한 값들은 모두 <code>.env</code>에 따로 저장해두었다.</li>
<li>Firebase앱의 구성 정보를 포함하는 JS 객체</li>
<li>Firebase를 사용하여 웹 애플리케이션을 초기화하고 firebase 앱 인스턴스를 설정하는 typescript 코드 </li>
<li>Firebase 프로젝트 구성정보 포함</li>
<li>환경변수를 통해 동적으로 코드</li>
</ul>
</li>
</ul>
<pre><code class="language-ts">import { initializeApp, FirebaseApp, getApp } from &quot;firebase/app&quot;;
import &quot;firebase/auth&quot;;

export let app: FirebaseApp;

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_ID,
};

try {
  app = getApp(&quot;app&quot;);
} catch (e) {
  app = initializeApp(firebaseConfig, &quot;app&quot;);
}

const firebase = initializeApp(firebaseConfig);

export default firebase;</code></pre>
<br/>

<ul>
<li>Firebase 앱 인스턴스를 초기화 시도<ul>
<li><code>app</code>이라는 이름의 Firebase 앱이 존재하지 않는 경우, <code>initializeApp</code>을 통해 Firebase 앱 초기화<pre><code class="language-ts">try {
app = getApp(&quot;app&quot;);
} catch (e) {
app = initializeApp(firebaseConfig, &quot;app&quot;);
}</code></pre>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="👀login-상태-확인">👀login 상태 확인</h2>
<ul>
<li>사용자가 <code>login</code>인 상태: 로그인 상태임을 콘솔에 띄움</li>
<li>사용자가 <code>logout</code>인 상태: 로그아웃 상태임을 콘솔에 띄움</li>
</ul>
<pre><code class="language-ts">import {getAuth, onAuthStateChanged} from &quot;firebase/auth&quot;

//mount시 useEffect를 통해 초기 사용자 로그인 상태 확인
useEffect(()=&gt;{
  onAuthStateChanged(auth, (user)=&gt;{
    if(user) {
      console.log(&quot;로그인 상태&quot;)
    }else {
      console.log(&quot;로그아웃 상태&quot;)
    }
    setInit(true)
  })
}, [auth]);</code></pre>
<ul>
<li><strong>onAuthStateChanged</strong>: Firebase Authentication 서비스에서 제공하는 메서드, 인증 상태가 변경될때마다 호출되는 리스너 설정<ul>
<li>사용자 객체를 인자로 받는 콜백 함수 등록</li>
<li>사용자의 로그인 상태 확인 후 적절한 작업 수행</li>
<li>로그인 상태일 때는 사용자의 정보를, 아니라면 null return</li>
</ul>
</li>
</ul>
<hr>
<h2 id="👀signup-구현">👀signUp 구현</h2>
<ul>
<li>email: 정규식을 이용하여 입력값 형식 제한</li>
<li>password: 8자리 이상의 입력값으로 제한</li>
<li>passwordConfirm: password값과 일치해야함</li>
</ul>
<pre><code class="language-ts">  //회원가입 입력값 관리
  const onChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    const {
      target: { name, value },
    } = e;

    if (name === &quot;email&quot;) {
      setEmail(value);
      console.log(value);
      //email 정규식
      const emailRegex = /^[a-zA-Z0-9-_]+@[a-zA-Z.]+$/;

      if (!value?.match(emailRegex)) {
        setError(
          &quot;이메일 형식이 올바르지 않습니다. 영문 대소문자, 숫자와 특수기호(_),(-),(@)만 사용 가능합니다.&quot;
        );
      } else {
        setError(&quot;&quot;);
      }
    }
    if (name === &quot;password&quot;) {
      setPassword(value);

      if (value?.length &lt; 8) {
        setError(&quot;비밀번호는 8자리 이상으로 입력해주세요.&quot;);
      } else if (passwordConfirm?.length &gt; 0 &amp;&amp; value !== passwordConfirm) {
        setError(&quot;비밀번호와 비밀번호 확인 값이 다릅니다.&quot;);
      } else {
        setError(&quot;&quot;);
      }
    }
    // 비밀번호 확인 (passwordConfirm)도 위와 비슷한 형태

  //&#39;회원가입하기&#39; 버튼 클릭 시  
  const onSubmit = async (e: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {
    e.preventDefault();
    try {
      const auth = getAuth(app);
      await createUserWithEmailAndPassword(auth, email, password);
      toast.success(&quot;회원가입에 성공하였습니다.&quot;);
      navigate(&quot;/&quot;);
    } catch (error: any) {
      toast.error(error?.code);
      console.log(error);
    }
  };</code></pre>
<br/>

<h3 id="✔️회원가입-input값-관리">✔️회원가입 input값 관리</h3>
<ul>
<li>*<em>이벤트 객체 타입 지정 부분 *</em><pre><code>e: React.ChangeEvent&lt;HTMLInputElement&gt;</code></pre></li>
</ul>
<br/>

<ul>
<li><strong>비구조화 할당</strong><ul>
<li><code>e</code>로부터 <code>taget</code>속성 추출</li>
<li>input의 <code>name</code>과 input의 <code>value</code>(현재 입력값)<pre><code class="language-ts">const {
target: { name, value },
} = e;</code></pre>
</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>비구조화 할당</strong>
: JS나 TypeScript와 같은 프로그래밍언어에서 변수를 객체나 배열에서 추출하여 사용하는 문법
-&gt; 객체나 배열의 내부 속성이나 요소를 간편하게 변수에 할당. 할당하려는 변수의 이름과 일치하는 속성이나 요소를 추출하여 할당</p>
</blockquote>
<pre><code class="language-js">const person = {name: &quot;John&quot;, age: 30}
const {name, age} = person;
console.log(name) //John
console.log(age) //30</code></pre>
<ul>
<li><p><strong>email input값</strong></p>
<ul>
<li><p><code>name</code>이 <code>email</code>인 경우</p>
</li>
<li><p>입력된 값으로 email값을 설정 <code>setEmail</code></p>
</li>
<li><p>만약 입력된 값이 emailRegex(이메일 정규식)에 벗어날 경우 error </p>
<pre><code class="language-ts">if (name === &quot;email&quot;) {
setEmail(value);
const emailRegex = /^[a-zA-Z0-9-_]+@[a-zA-Z.]+$/;

if (!value?.match(emailRegex)) {
  setError(
      &quot;이메일 형식이 올바르지 않습니다. 영문 대소문자, 숫자와 특수기호(_),(-),(@)만 사용 가능합니다.&quot;
  );
} else {
  setError(&quot;&quot;);
}
}</code></pre>
</li>
</ul>
</li>
</ul>
<br/> 

<h3 id="✔️회원가입하기-버튼-클릭-시-onsubmit">✔️&#39;회원가입하기&#39; 버튼 클릭 시 (onSubmit)</h3>
<ul>
<li><p><strong>React에서 사용자가 form을 제출할 때 실행될 이벤트 핸들러</strong></p>
<pre><code class="language-ts">const onSubmit = async (e: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {}</code></pre>
</li>
<li><p><strong>e.preventDefault()</strong>
기본 제출 동작을 중단, form이 실제로 서버 제출되는 것을 중단하고 JS 함수가 대신 실행되도록 함</p>
</li>
</ul>
<ul>
<li><strong>createUserWithEmailAndPassword</strong>
입력된 email, password를 해당 메서드에 전달하여 회원가입에 성공할 경우 <code>toast.success</code>를 띄우고, <code>useNavigate</code>를 통해 홈화면으로 가도록 구현<pre><code class="language-ts">await createUserWithEmailAndPassword(auth, email, password);
toast.success(&quot;회원가입에 성공하였습니다.&quot;);
navigate(&quot;/&quot;);</code></pre>
</li>
</ul>
<hr>
<h2 id="👀login-구현">👀login 구현</h2>
<ul>
<li><p>login input값의 onChange는 회원가입과 매우 비슷한 형태로 구현됨</p>
</li>
<li><p>&#39;로그인하기&#39;버튼을 클릭했을 때 동작하는 <code>onSubmit</code></p>
<pre><code class="language-ts">const onSubmit = async (e: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {
  e.preventDefault();
  try {
    const auth = getAuth(app);
    await signInWithEmailAndPassword(auth, email, password);
    toast.success(&quot;로그인에 성공하였습니다.&quot;);
  } catch (error: any) {
    toast.error(error?.code);
    console.log(error);
  }
};</code></pre>
</li>
<li><p><strong>signWithEmailAndPassword</strong>
입력한 email과 password값을 해당 메서드로 전달</p>
</li>
</ul>
<hr>
<h2 id="👀logout-구현">👀logout 구현</h2>
<ul>
<li><strong>logout 버튼 클릭 시</strong><pre><code class="language-ts">const onSignOut = async () =&gt; {
try {
  const auth = getAuth(app);
  await signOut(auth);
  toast.success(&quot;로그아웃 되었습니다.&quot;);
} catch (error: any) {
  console.log(error);
  toast.error(error?.code);
}
};</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] JS - Lv.2 - 전화번호 목록]]></title>
            <link>https://velog.io/@minz-cha/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Lv.2-%EC%A0%84%ED%99%94%EB%B2%88%ED%98%B8-%EB%AA%A9</link>
            <guid>https://velog.io/@minz-cha/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Lv.2-%EC%A0%84%ED%99%94%EB%B2%88%ED%98%B8-%EB%AA%A9</guid>
            <pubDate>Sun, 01 Oct 2023 19:17:24 GMT</pubDate>
            <description><![CDATA[<h1 id="전화번호-목록">전화번호 목록</h1>
<h2 id="문제">문제</h2>
<blockquote>
<ul>
<li>전화번호부에 적힌 전화번호 중, 한 번호가 다른 번호의 접두어인 경우가 있는지 확인하려 합니다.</li>
</ul>
</blockquote>
<ul>
<li>전화번호부에 적힌 전화번호를 담은 배열 phone_book 이 solution 함수의 매개변수로 주어질 때, 어떤 번호가 다른 번호의 접두어인 경우가 있으면 false를 그렇지 않으면 true를 return 하도록 solution 함수를 작성해주세요.</li>
</ul>
<h2 id="제한사항">제한사항</h2>
<ul>
<li>phone_book의 길이는 1 이상 1,000,000 이하입니다.<ul>
<li>각 전화번호의 길이는 1 이상 20 이하입니다.</li>
<li>같은 전화번호가 중복해서 들어있지 않습니다.</li>
</ul>
</li>
</ul>
<h3 id="문제-바로가기">문제 바로가기</h3>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42577">프로그래머스 - 전화번호 목록</a></p>
<hr>
<h2 id="💡풀이-코드">💡풀이 코드</h2>
<ol>
<li><p>받은 문자열을 <code>sort</code></p>
</li>
<li><p><code>phone_book[i+1]</code>에서 <code>phone_book[i]</code>만큼 자른 값이 <code>phone_book[i]</code>와 같은 경우, 접두어
 -&gt; <code>false</code> 반환
 -&gt; 아니라면 <code>true</code> 반환</p>
<pre><code class="language-js">function solution(phone_book) {
 phone_book.sort(); 

 for (let i = 0; i &lt; phone_book.length - 1; i++) {
     if (phone_book[i] === phone_book[i + 1].substring(0, phone_book[i].length)) {
     return false;
     }
 }
 return true; 
}</code></pre>
</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>