<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>glory_young.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 27 Jul 2025 06:12:14 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>glory_young.log</title>
            <url>https://velog.velcdn.com/images/young_k/profile/b20c4801-86d0-4375-972c-132148659e2f/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. glory_young.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/young_k" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[백준 9465: 스티커/C++]]></title>
            <link>https://velog.io/@young_k/%EB%B0%B1%EC%A4%80-9465-%EC%8A%A4%ED%8B%B0%EC%BB%A4C</link>
            <guid>https://velog.io/@young_k/%EB%B0%B1%EC%A4%80-9465-%EC%8A%A4%ED%8B%B0%EC%BB%A4C</guid>
            <pubDate>Sun, 27 Jul 2025 06:12:14 GMT</pubDate>
            <description><![CDATA[<h3 id="📌문제접근">📌문제접근</h3>
<p>문제 : <a href="https://www.acmicpc.net/problem/9465">백준 9465: 스티커</a></p>
<ul>
<li>2*n 행렬의 스티커가 있고, 스티커는  0~100사이 정수값을 가짐</li>
<li>한 스티커를 선택하면 해당 스티커와 인접한 좌우상하의 스티커는 사용할 수 없음</li>
<li>최대 점수가 되는 스티커 조합의 점수를 결과로 출력</li>
<li>1 &lt;= n &lt;= 100,000</li>
</ul>
<p><strong>접근 방법</strong></p>
<ul>
<li>n이 10만까지의 값을 가지므로 n^2의 시간복잡도는 불가 -&gt; 이중 for문이 있으면 안되겠다.</li>
<li>스티커의 모든 점수는 양수이기에 스티커를 선택할 수 있다면 선택하는게 무조건 좋다.</li>
<li>2*n 이라고 할때 2 *(n-1)의 결과값을 이용할 수 있을까?<ul>
<li>[0][n]을 선택하는 경우, [0][n-1] 스티커는 사용 불가, [1][n-1] 스티커 사용 가능</li>
<li>또는 [*][n-1] 스티커는 선택하지 않고, [1][n-2] 스티커 사용 가능</li>
<li>두 값을 비교하여 최대값을 선택하면 됨.</li>
</ul>
</li>
</ul>
<h3 id="📌제출코드">📌제출코드</h3>
<pre><code>#include &lt;iostream&gt;
#include &lt;algorithm&gt;

using namespace std;

int main(){
    int T;

    cin &gt;&gt; T;

    for (int t=0; t&lt;T; t++){
        int n;
        cin &gt;&gt; n;

        int arr[2][100001] = {0,};
        int dp[2][100001] = {0, };
        int result = 0;

        for (int i = 1; i &lt;= n; i++){
            cin &gt;&gt; arr[0][i];
        }
        for (int i = 1; i &lt;= n; i++){
            cin &gt;&gt; arr[1][i];
        }

        if (n == 1){
            result = max(arr[0][1], arr[1][1]);
            cout &lt;&lt; result &lt;&lt; &#39;\n&#39;;
            continue;
        }
        if (n == 2){
            result = max(arr[0][1]+arr[1][2], arr[1][1]+arr[0][2]);
            cout &lt;&lt; result &lt;&lt; &#39;\n&#39;;
            continue;
        }

        dp[0][1] = arr[0][1];
        dp[1][1] = arr[1][1];
        dp[0][2] = arr[0][2] + arr[1][1];
        dp[1][2] = arr[1][2] + arr[0][1];


        if (n &gt;= 3){
            for (int i = 3; i &lt;= n; i++){
                dp[0][i] = arr[0][i] + max(dp[1][i-1], dp[1][i-2]);
                dp[1][i] = arr[1][i] + max(dp[0][i-1], dp[0][i-2]);
            }
            result = max(dp[0][n], dp[1][n]);
            cout &lt;&lt; result &lt;&lt; &#39;\n&#39;;
        }
    }
    return 0;
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD - 3주차 SQL 기본]]></title>
            <link>https://velog.io/@young_k/SQLD-3%EC%A3%BC%EC%B0%A8-SQL-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@young_k/SQLD-3%EC%A3%BC%EC%B0%A8-SQL-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Sun, 20 Jul 2025 11:45:15 GMT</pubDate>
            <description><![CDATA[<h1 id="sql-기본">SQL 기본</h1>
<h2 id="관계형-데이터베이스">관계형 데이터베이스</h2>
<p>데이터를 어떤 목적에 따라 가공하여 유용한 정보로 변환
이러한 데이터를 일정한 체계에 따라 통합하여 디스크나 메모리에 저장한 것을 <strong>데이터베이스</strong>라고 함. 응용 프로그램에 종속적이지 않도록 미들웨어 형태로 만든 것.</p>
<p>데이터베이스를 구축하고 관리할 수 있는 기능을 제공하는 시스템 소프트웨어를 데이터베이스 관리 시스템(<strong>DBMS</strong>)라고 함</p>
<h3 id="관계형-데이터베이스-1">관계형 데이터베이스</h3>
<p>2차원 구조의 행과 열로 구성된 테이블 형태</p>
<ul>
<li><p>연산을 수학적으로 최적화할 수 있음</p>
</li>
<li><p>SQL(Structured Query Language)라는 공통의 질의언어를 정의하여 정보를 다룰 수 있음</p>
</li>
<li><p>table</p>
</li>
<li><p>스키마 = 칼럼헤더</p>
</li>
<li><p>column = 필드(속성) = attribute</p>
</li>
<li><p>row = 레코드 = tuple</p>
</li>
</ul>
<h3 id="sqlstructured-query-language">SQL(Structured Query Language)</h3>
<p>수학적 이론을 바탕으로 원하는 결과 ㅈ데이터를 추출할때 사용하는 명령문
데이터베이스의 구조를 정의하고, 데디터를 조작하고, 데이터를 정의할 수 있는
절차적(How) + 비절차적(What) 언어</p>
<ul>
<li><p>DDL (데이터 정의언어)</p>
</li>
<li><p>데이터의 구조(스키마)를 정의하는 명령어</p>
</li>
<li><p>create, alter, drop, rename, truncate</p>
</li>
<li><p>DDL 명령어는 오라클에서는 커밋이 자동으로 수행되어 롤백 불가하고, SQL서버에서는 자동커밋모드를 끄거나 명시적 트랜잭션을 선언하는 경우 롤백 가능</p>
</li>
<li><p>DML (데이터 조작 언어)</p>
</li>
<li><p>데이터 조회, 입력, 수정, 삭제</p>
</li>
<li><p>커밋 전에 롤백이 가능</p>
</li>
<li><p>selet, insert, update, delete, merge</p>
  <aside>

<ul>
<li>drop - 스키마까지 삭제. 저장공간 릴리즈. 로그 안남김</li>
<li>truncate - 스키마 유지 데이터만 삭제. 저장공간 릴리즈. 로그 안남김</li>
<li>delete - 데이터 삭제. 저장공간 릴리즈 X. 로그남겨 롤백 가능</aside>
</li>
</ul>
</li>
<li><p>DCL (데이터 제어 언어)</p>
</li>
<li><p>사용자 접근 권한 같은 보안과 제어</p>
</li>
<li><p>grant revoke</p>
</li>
<li><p>TCL (트랜잭션 제어 언어)</p>
</li>
<li><p>트랜잭션 제어. DCL의 일부로 보기도 함</p>
</li>
<li><p>commit, rollback, savepoint</p>
</li>
</ul>
<h2 id="select문">SELECT문</h2>
<p>특정 열을 조회할 수 있음</p>
<p><strong>F W G H S O →</strong> 해당 순서로 처리됨</p>
<ul>
<li>select [칼럼] from [테이블]</li>
<li>테이블 뒤에 별명은 공백으로, 속성 뒤에 별명은 as로</li>
<li>산술 연산자 : ( ), *, /, %, +, -</li>
<li>Null과 산술연산 결과는 Null. 0으로 나누는 경우는 오류</li>
<li>합성 연산자 : ||</li>
<li>문자열을 연결하 때 사용</li>
</ul>
<p><strong>함수</strong></p>
<ul>
<li><p>lower(문자열) / upper(문자열) : 소문자로/대문자로</p>
</li>
<li><p>chr(ASCII코드값) :  아스키코드에 해당하는 문자로 반환</p>
</li>
<li><p>trim(?방향, ?제거할 문자, 문자열): 문자열에서 공백 또는 특정 문자열 제거</p>
</li>
<li><p>방향은 leading, tailing, both가 있음. both가 기본값</p>
</li>
<li><p>제거할 문자는 공백이 기본값</p>
</li>
<li><p>ltrim, rtrim : 왼쪽/오른쪽 끝에서 trim</p>
</li>
<li><p>substr(문자열, 시작점, ?길이) : 시작점에서 길이만큼 문자열 반환</p>
</li>
<li><p>length(문자열) : 문자열 길이 반환</p>
</li>
<li><p>replace(문자열, 변경 대상, ?변경 후) : 특정 문자열을 찾아 변경</p>
</li>
<li><p>abs(숫자) : 절대값 반환</p>
</li>
<li><p>mod(숫자1, 숫자2) : 1을 2로 나눈 나머지</p>
</li>
<li><p>round(숫자, ?소수점 정수) : 반올림</p>
</li>
<li><p>trunc(숫자, ?소수점 정수) : 버림</p>
</li>
<li><p>sign(숫자) : 양수는 1, 음수는 -1, 0은 0</p>
</li>
<li><p>ceil(숫자) : 크거나 같은 최소 정수</p>
</li>
<li><p>floor(숫자) : 작거나 같은 최소 정수</p>
</li>
<li><p>sysdate : 오늘 날짜를 날짜형으로 반환</p>
</li>
<li><p>extract(avg from 날짜) : 날짜의 특정 부분 추출</p>
</li>
<li><p>avg = year/month/day/hour/minute/second</p>
</li>
<li><p>to_number, to_char, to_date : 형변환</p>
</li>
<li><p>암시적 형변환도 있으나 성능 저하나 에러를 가져올 수 있어 명시적 형변환이 좋음</p>
</li>
<li><p>nvl(avg1, avg2) : (avg1 != Null) ? avg1 : avg2</p>
</li>
<li><p>nullif(avg1, avg2) : (avg1 == avg2) ? Null : avg1</p>
</li>
<li><p>coalsce(list…) : 인자를 순서대로 평가하여 Null이 아닌 첫번째 인자 반환</p>
</li>
<li><p>case when [칼럼] = 값1 then 값A … (else 값N) end
case [칼럼] when 값1 then 값A … (else 값N) end
: 칼럼이 특정 값을 가지면 이를 새 값으로 대체하여 반환</p>
</li>
</ul>
<h2 id="where절">WHERE절</h2>
<p>select, update, delete에 사용 가능. insert에는 사용 불가
from 절에서 정의한 별명 사용 가능.</p>
<p>where [조건식]</p>
<ul>
<li><p>단일행 비교 연산자 : =, &lt;, &lt;=, &gt;, &gt;=, is null</p>
</li>
<li><p>다중행 비교 연산자</p>
</li>
<li><p>in : 리스트 중 동일한 값이 하나라도 있으면 참</p>
</li>
<li><p>exists : 서브쿼리의 결과가 한 건이라도 있으면 참</p>
</li>
<li><p>all : 모두 참이면 참</p>
</li>
<li><p>any : 하나라도 참이면 참</p>
</li>
<li><p>단일행 부정 비교연산자 : !=,^=, &lt;&gt;, is not null</p>
</li>
<li><p>다중행 부정 비교연산자</p>
</li>
<li><p>not in : 리스트 중 동일한 값이 하나도 없으면 참</p>
</li>
<li><p>not exists : 서브쿼리의 결과가 한 건도 없으면 참</p>
</li>
<li><p>between A and B : A보다 크거나 같고 B보다 작거나 같으면 참</p>
</li>
<li><p>like : 패턴 문자열 검색. %는 0개 이상의 문자, _는 1개의 문자를 의미함</p>
</li>
<li><p>not between A and B : A보다 작거나 B보다 크면 참</p>
</li>
<li><p>not like : 패턴과 매칭되는 것이 하나도 없으면 참</p>
</li>
<li><p>and, or, not</p>
</li>
</ul>
<h2 id="group-by-having절">GROUP BY, HAVING절</h2>
<p>group by를 통해 데이터를 그룹핑 할 수 있음</p>
<p>그룹핑한 다음에 해당 그룹에 대해 집계함수를 사용하여 통계값을 구할 수 있음</p>
<ul>
<li>count, sum, avg, min, max</li>
<li>중첩된 집계함수의 경우 결과는 1건이 됨</li>
<li>avg(*)는 불가</li>
</ul>
<p>having으로 필터링할 조건을 명시할 수 있음. 그룹핑 후에 수행됨. 
(where절은 집계함수를 사용할 수 없음)</p>
<h2 id="order-by절">ORDER BY절</h2>
<p>칼럼을 조회할 때 정렬을 수행함</p>
<p>order by 칼럼 (ASC/ DESC)</p>
<ul>
<li>기본은 오름차순으로 정렬</li>
</ul>
<h2 id="조인">조인</h2>
<p>두 테이블을 하나로 병합하는 것</p>
<ul>
<li><p>두 테이블 간 PK와 FK의 연관성에 의해 성립하거나</p>
</li>
<li><p>연관성이 없더라도 논리적인 값들의 연관만으로도 조인을 성립할 수 있음</p>
</li>
<li><p>조인은 O(N^2)의 시간복잡도를 가짐</p>
</li>
<li><p><strong>equi join</strong></p>
</li>
<li><p>칼럼값이 정확하게 일치할때 성립
where절 조건이 등식인 경우</p>
</li>
<li><p><strong>non equi join</strong></p>
</li>
<li><p>where 절 조건이 등식이 아닌 부등식인 경우</p>
</li>
<li><p>3개 이상의 테이블을 조인하는 경우 n개의 테이블에 대해서 n-1개의 조인이 발생</p>
</li>
<li><p><strong>outer join</strong></p>
</li>
<li><p>조건에 맞는 행만 병합된 것을 inner join이라고 함</p>
</li>
<li><p>조건에 맞지 않는 행까지 병합한 것을 outer join이라고 함 (left outer join, right outer join, full outer join)</p>
</li>
</ul>
<h3 id="표준-조인">표준 조인</h3>
<p>DBSM 별 SQL문을 따로 사용하는 불편을 줄이기 위해 표준 문법(ANSI SQL) 사용.</p>
<p>표준 조인에서는 기준조건은 where절이 아닌 on절을 사용하여 from에 조인 종류를 명시함.</p>
<ul>
<li><p>from [t.name] (join) [t.name] on 조건;</p>
</li>
<li><p>inner join
: 교집합 개념. (null이 없도록 조인) 기준이 되는 키에 따른 칼럼값이 존재하는 것만 병합</p>
</li>
<li><p>outer join
: 합집합 개념</p>
<ul>
<li>left outer join
: 왼쪽 테이블의 모든 행을 포함시키면서 조일</li>
<li>right outer join
: 오른쪽 테이블의 모든 행을 포함시키면서 조인</li>
<li>full outer join
: 왼쪽과 오른쪽의 모든 행을 포함시키면서 조인</li>
</ul>
</li>
<li><p>natural join
: 같은 이름의 칼럼에 대해서는 동일한 칼럼값을 가진 행만 병합되는 조인
SQL server는 지원 안함. on 절을 사용할 수 없음.</p>
</li>
<li><p>cross join
: 왼쪽 테이블의 각 행에 대해 오른쪽 테이블 모든 행의 대응을 조합하여 결과 출력
M*N개의 행이 생성됨 (모든 경우의 수)
where절 없이 from절에 테이블을 나열하면 cross join이 됨</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD - 2주차 데이터 모델과 SQL]]></title>
            <link>https://velog.io/@young_k/2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-SQL</link>
            <guid>https://velog.io/@young_k/2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-SQL</guid>
            <pubDate>Sun, 20 Jul 2025 10:32:23 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터-모델과-sql">데이터 모델과 SQL</h1>
<h2 id="1-정규화">1. 정규화</h2>
<ul>
<li>데이터베이스 이상현상 (Anomaly)
: 데이터를 입력, 수정, 삭제하는 과정에서 일관성이 깨지는 경우<ul>
<li>삽입이상</li>
<li>데이터 삽입 시 의도하지 않은 정보까지 삽입</li>
<li>갱신이상</li>
<li>중복 저장된 데이터 중 하나만 갱신</li>
<li>삭제이상</li>
<li>데이터 삭제 시 의도하지 않은 정보까지 삭제</li>
</ul>
</li>
</ul>
<p>⇒ 이러한 문제를 방지하기 위해 중복을 최소화하며 테이블을 잘 조직된 상태로 분해하는 과정을 
<strong>정규화</strong>라고 함</p>
<h3 id="제1정규형">제1정규형</h3>
<p>모든 속성이 하나의 속성값을 가지는 상태 (atomic values) (속성의 원자성 확보)</p>
<h3 id="제2정규형">제2정규형</h3>
<p>주식별자가 복합식별자인 경우, 일반속성이 주식별자의 일부에만 종속성을 가질 때(→ 부분 함수종속성), 이를 제거한 상태</p>
<p>(ex)</p>
<p>(함수종속성)</p>
<p>[관서번호, 납부자번호] → {직급명, 통신번호}
[관서번호] → {관서명, 관서등록일자}</p>
<p>(테이블)</p>
<p>관서번호, 납부자번호 | 관서명, 관서등록일자, 직급명, 통신번호</p>
<p>⇒ 2차 정규화를 하면</p>
<p>관서번호 | 관서명, 관서등록일자
납부자번호, 관서번호 | 직급명, 통신번호</p>
<h3 id="제3정규형">제3정규형</h3>
<p>주식별자가 아닌 일반 속성간 함수종속성이 존재 (→ 이행함수종속성), 이를 제거한 상태</p>
<p>a→ b, b→c 이면 a→c 관계가 성립
제3정규화의 수행 결과 분리된 엔터티들은 서로 비식별자 관계임</p>
<hr>
<h2 id="2-관계와-조인의-이해">2. 관계와 조인의 이해</h2>
<p>정규화로 테이블이 분해된 상황에서는 조회 시 조인 발생이 많아지면서 성능이 떨어질 수 있음
데이터 정합성과 조회성능 간 트레이드 오프 관계가 성립</p>
<p><strong>성능 데이터 모델링</strong></p>
<ol>
<li>데이터 모델링 시 정규화를 정확하게 수행</li>
<li>데이터베이스 용량산저을 수행</li>
<li>발생되는 트랜잭션의 유형 파악</li>
<li>용량과 트랜잭션의 유형에 따라 반정규화 수행</li>
<li>이력모델의 조정, PK/FK 조정, 슈퍼타입/서브타입 조정 등을 수행</li>
<li>성능관점에서 데이터 모델을 검증</li>
</ol>
<h3 id="테이블의-반정규화">테이블의 반정규화</h3>
<p>데이터의 조회성능이 중요한 경우 반정규화가 필요</p>
<p>데이터의 중복을 허용하거나 데이터를 그룹핑하여 조회성능을 높임</p>
<p><strong>반정규화 수행 절차</strong></p>
<ol>
<li>반정규화 대상 조사
: 범위처리 빈도수 조사, 통계성 프로세스 조사, 테이블 조인 개수 등</li>
<li>다른 방법 검토
: 뷰 테이블 생성, 인덱스 조정, 클러스터링 적용, 응용 애플리케이션에서의 처리 등 대안 검토</li>
<li>반정규화 적용</li>
</ol>
<p><strong>1. 테이블 병합</strong></p>
<p>발생빈도가 높아서 아예 하나로 합치는 것</p>
<p>※ 슈퍼타입/서브타입 관계 테이블 병합</p>
<p><strong>2. 테이블 분할</strong></p>
<ul>
<li>수직분할
: 한 테이블에 너무 많은 칼럼이 존재하는 경우. 특정 속성에만 접근이 빈번한 경우.</li>
<li>수평분할
: 속성값에 따라 구분하여 조회하는 경우. 스키마는 원래 테이블과 동일.</li>
</ul>
<p><strong>3. 테이블 추가</strong></p>
<ul>
<li>중복 테이블 추가
: 다른 업무에 있는 테이블과 동일한 구조의 테이블을 추가하여 원격 조인을 제거</li>
<li>통계 테이블 추가
: 통계값 연산을 미리 계산하여 저장하는 테이블 추가</li>
<li>이력 테이블 추가
: 변경 이력 등 이력 데이터 관리를 위한 테이블 추가</li>
<li>부분 테이블 추가
: 디스크 I/O를 줄이기 위한 방법으로 특별히 자주 사용하는 속성만 모아서 추가</li>
</ul>
<h3 id="칼럼의-반정규화">칼럼의 반정규화</h3>
<ol>
<li>중복 칼럼 추가
: 조인을 감소시키기 위해 자주 사용하는 칼럼을 추가</li>
<li>파생 칼럼 추가
: 트랜잭션 처리 시 계산에 의한 부하를 줄이기 위해 계산값을 별도의 칼럼으로 추가</li>
<li>이력 테이블 칼럼 추가
: 이력 테이블에 조회 조건에 해당하는 기능성 칼럼 추가</li>
<li>PK에 의한 칼럼 추가
: PK를 파싱해서 추가적인 내용을 조회하는 경우 이를 일반속성으로 추가</li>
<li>응용 시스템 오작동을 위한 칼럼 추가
: 이전 데이터를 임시적으로 중복하여 보관하는 기법 (백업 데이터)</li>
</ol>
<h3 id="관계의-반정규화">관계의 반정규화</h3>
<p>여러 관계를 거쳐 다수의 조인을 통해 처리가 가능하지만 중복된 관계를 추가로 맺음</p>
<hr>
<h2 id="3-트랜잭션의-이해">3. 트랜잭션의 이해</h2>
<p>All or Nothing
작업이 완전하게 처리되거나 전혀 처리되지 않아야 함. 중간에 미완결된 상태로 중단되어서는 안됨</p>
<p><strong>트랜잭션 관련 명령</strong></p>
<ul>
<li>commit - 작업을 정상처리 완료 후에 DB 반영</li>
<li>rollback - 작업 취소하고 이전상태로</li>
<li>savepoint - 부분 작업 취소를 위한 저장점 지정</li>
</ul>
<p><strong>트랜잭션 특성</strong></p>
<p>데이터를 읽고 쓸 때 한번에 수행되어야하는 논리적 작업단위</p>
<ul>
<li>원자성</li>
<li>all or nothing</li>
<li>일관성</li>
<li>트랜잭션 이전에 오류가 없다면 트랜잭션 이후에도 오류 없음</li>
<li>고립성</li>
<li>독립적으로 수행되어 다른 트랜잭션이 간섭하거나 영향을 미치지 않음</li>
<li>영속성</li>
<li>트랜잭션의 결과는 데이터베이스에 영구적으로 저장</li>
</ul>
<p>트랜잭션 격리수준이 낮을때는</p>
<ul>
<li>dirty read</li>
<li>non-repeatable read</li>
<li>phantom read
문제가 생길 수 있음</li>
</ul>
<hr>
<h2 id="4-null">4. NULL</h2>
<p>값이 입력되지 않은 상태. 값이 없는 상태
0과 공백과 문자열 “NULL”과 다른 상태임</p>
<hr>
<h2 id="5-본직식별자--인조식별자">5. 본직식별자 &amp; 인조식별자</h2>
<p>본질식별자
: 업무에 존재하는 원래 식별자</p>
<p>인조식별자
: 원래 존재하지는 않지만 업무가 복잡하여 인위적으로 만든 식별자</p>
<p>읹조식별자를 주식별자로추가하는 경우 추가적인 연산없이 시퀀스나 키 제약조건 등을 통해 주식별자를 생성할 수 있어 편의성이 향상됨.</p>
<p>반면 데이터 중복이 발생하고 별도의 인덱스 생성 등이 필요하다는 단점있음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD - 1주차 데이터 모델의 이해]]></title>
            <link>https://velog.io/@young_k/SQLD-1%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@young_k/SQLD-1%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Sun, 29 Jun 2025 11:49:29 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터-모델의-이해">데이터 모델의 이해</h1>
<h2 id="1-모델링">1. 모델링</h2>
<h3 id="모델링">모델링</h3>
<p>: 현실세계를 대상의로 일종의 모델(모형)을 만드는 것. 
약속된 표기법에 따라 <strong>도식화</strong> 해야 함. 업무의 흐름을 가시화하고 명세화하기 위함(업무 형상화)
또한 모델링은 <strong>추상화</strong>를 기본으로 함
필요한 수준에서 데이터를 추상화하여 단순명료하게 표현하는 것이 중요</p>
<ul>
<li>데이터 모델링 : 정보시스템을 구축하기 위해 데이터베이스를 설계하는 것<h3 id="특징">특징</h3>
</li>
<li>추상화 : 대상의 주요 특징을 추출하여 일정한 형식으로 표현</li>
<li>단순화 : 현실세계를 그대로 표현하지 않고 단순하게 표현</li>
<li>명확화 : 모델링 결과를 보는 사람이 같은 해석을 할 수 있도록 모홈함이 없게 기술</li>
</ul>
<p><strong>따라서 데이터 모델링이란 일정한 표기법을 사용하여 대상이 되는 데이터를 추상화, 단순화, 명확화하여 표현하는 것</strong></p>
<h4 id="유의사항">유의사항</h4>
<ul>
<li>중복 최소화 : 같은 정보 중복하여 저장하지 않음</li>
<li>비유연성 최소화 : 데이터 정의와 데이터 사용 프로세스 분리</li>
<li>비일관성 최소화 : 연관관계를 명확하게 정의하여 데이터가 일관성있게 유지되어야 함</li>
</ul>
<h3 id="모델링-관점">모델링 관점</h3>
<ul>
<li>데이터 관점 
: 데이터에 집중. 정적분석, 구조분석 등을 기반으로 함</li>
<li>프로세스 관점 
: 업무 흐름에 집중. 동적분석, 도메인분석 등을 기반으로 함</li>
<li>데이터와 프로세스의 상관 관점 
: 데이터와 프로세스가 서로 어떻게 관계를 맺고 영향을 주고받는지. CRUD 분석을 기반으로 함</li>
</ul>
<h3 id="모델링-단계">모델링 단계</h3>
<ul>
<li>개념적 데이터 모델링
: 가장 높은 추상화 레벨. 업무와 개념 중심으로 포괄적인 수준에서 모델링. 엔터티와 속성 도출(EA 수립)</li>
<li>논리적 데이터 모델링 
: 데이터 모델의 키, 속성, 관계 등을 표현. 서로 다른 DBMS에 적용 가능한 수준의 추상화 단계. 중복 데이터 최소화, 식별자 도출 및 관계 정의.</li>
<li>물리적 데이터 모델링 
: 특정 DBMS에 맞추어 구현. 가장 낮은 수준의 추상화 레벨. 테이블, 인덱스, 함수 등을 생성.</li>
</ul>
<h3 id="ansi-sparc-3단계-스키마-구조">ANSI-SPARC 3단계 스키마 구조</h3>
<p>데이터 독립성을 보장하기 위한 설계방법</p>
<ul>
<li><p>외부 스키마
: 사용자 관점. 사용자 또는 애블리케이션(응용 프로그래머)이 바라보는 데이터베이스 스키마 정의. 다중 사용자 뷰</p>
</li>
<li><p>개념 스키마
: 설계자 관점. 몯느 사용자가 바라보는 데이터베이스 스키마를 통합. 통합된 뷰</p>
</li>
<li><p>내부 스키마
: 개발자 관점(DBMS의 SQL문을 작성하는). 디스크나 메모리 상의 물리적, 실질적 저장구조. 물리적 뷰</p>
<p><strong>논리적 데이터 독립성</strong>
: 외부 스키마와 개념 스키마 간의 독립성
<strong>물리적 데이터 독립성</strong>
: 개념 스키마와 내부 스키마 간의 독립성</p>
</li>
</ul>
<h3 id="erd-entity-relationship-diagram">ERD (Entity Relationship Diagram)</h3>
<p>데이터 모델링에 대한 문서화 방법 (여러가지 표기법이 있지만 해당 책에서는 IE 표기법 사용)</p>
<ul>
<li>엔터티 : 박스로 표현. 엔터티 이름은 박스 상단에 표시.</li>
<li>속성 : 박스 안에 리스트로 표현. 주식별자와 일반 속성은 칸막이로 구분</li>
<li>관계 : 박스를 연결한 선으로 표현. 식별자 관계는 실선, 비식별자 관계는 점선.</li>
<li>카디널리티 : O은 0, 세로 실선은 1, 까치발 모양은 다수(2 이상)를 의미.</li>
</ul>
<h4 id="작성순서">작성순서</h4>
<p>엔터티 도출 - 엔터티 배치(중요한 엔터티는 왼쪽 상단) - 관계 설정 - 관계명 기술 - 참여도 기술 - 필수,선택 여부 기술</p>
<h2 id="2-엔터티-entity">2. 엔터티 (Entity)</h2>
<h3 id="엔터티">엔터티</h3>
<p>데이터베이스 구성요소 중 독립적으로 식별 가능한 객체
속성이라는 하위요소를 가짐</p>
<h3 id="특징-1">특징</h3>
<ul>
<li>업무에 필요로 하고 관리하고자 하는 정보</li>
<li>유일한 식별자 가짐</li>
<li>영속적으로 존재하는 인스턴스가 두 개 이상인 집합</li>
<li>하위요소로 반드시 속성을 가짐</li>
<li>다른 엔터티와 한 개 이상의 관계를 가짐(통계성 엔터티나 코드성 엔터티의 경우 관계 생략)</li>
</ul>
<h3 id="분류">분류</h3>
<h4 id="발생시점상속관계에-따라">(발생시점/상속관계에 따라)</h4>
<ul>
<li>기본 엔터티 : 고유한 주식별자를 가지는 독립적으로 생성되는 엔터티</li>
<li>중심 엔터티 : 주식별자를 상속받아 생성되어 업무의 중심 역할을 하는 엔터티</li>
<li>행위 엔터티 : 두 개 이상의 엔터티를 상속받아 생성되는 엔터티</li>
</ul>
<h4 id="물리적-형태-여부에-따라">(물리적 형태 여부에 따라)</h4>
<ul>
<li>유형 엔터티 : 물리적 형태가 존재</li>
<li>개념 엔터티 : 개념적으로 정의</li>
<li>사건 엔터티 : 업무 수행중 발생하는 행위나 이벤트</li>
</ul>
<p><em>교차 엔터티</em>
: M:N 관계를 해소하기 위해 만들어진 엔터티</p>
<h2 id="3-속성-attribute">3. 속성 (Attribute)</h2>
<h3 id="속성">속성</h3>
<p>엔터티에 대해 자세하고 구체적인 정보를 나타내는 엔터티의 하위요소
속성은 자신이 가질 수 있는 속성값의 집합이라고 할 수 있음</p>
<p>하나의 엔터티 인스턴스에서 각각의 속성은 한 개의 속성값만을 가져야 함
만약 하나 이상의 속성값을 가지는 경우에 1차 정규화를 수행하여 한 개의 속성값만 갖도록 해야 함.</p>
<ul>
<li>한 개의 엔터티는 두 개 이상의 인스턴스를 가짐</li>
<li>한 개의 엔터티는 두 개 이상의 속성을 가짐</li>
<li>한 개의 속성은 한 개의 속성값만 가짐</li>
</ul>
<h3 id="분류-1">분류</h3>
<h4 id="속성의-특성에-따라">(속성의 특성에 따라)</h4>
<ul>
<li>기본 속성 
: 엔터티가 본래 가지고 있어야 하는 속성</li>
<li>설계 속성 
: 본래 가지는 속성은 아니지만 설계 시 필요하다고 판단되어 도출된 속성</li>
<li>파생 속성 
: 다른 속성으로부터 계산되거나 특정 규칙에 따라 변형되어 만들어진 속성</li>
</ul>
<h4 id="구성방식에-따라">(구성방식에 따라)</h4>
<ul>
<li>PK(Primary Key, 기본키) 속성
: 엔터티에서 인스턴스를 유일하게 식별할 수 있는 속성</li>
<li>FK(Foreign Key, 외래키) 속성
: 관계를 통해 다른 엔터티의 속성을 가져와 포함시킨 속성</li>
<li>일반 속성
: PK나 FK가 아닌 나머지 일반 속성</li>
</ul>
<h3 id="도메인">도메인</h3>
<p>속성이 가질 수 있는 값의 범위(값의 데이터 타입과 크기)를 정의한 것</p>
<h2 id="4-관계">4. 관계</h2>
<h3 id="관계">관계</h3>
<p>엔터티 간 맺고 있는 연관성
존재적 관계와 행위적 관계로 나눌 수 있으나 EDR에서는 둘을 구분하지 않음</p>
<ul>
<li>존재적 관계
: 일종의 소속관계. 존재 자체로 서로 연관성을 갖는 관계</li>
<li>행위적 관계
: 특정 행위나 이벤트를 일으킬 경우에 연관성이 발생하는 관계</li>
</ul>
<p><em>연관관계</em> : 존재 자체로 연관성을 가짐
<em>의존관계</em> : 특정 행위를 할 때만 연관성을 가짐</p>
<h3 id="표기법">표기법</h3>
<ul>
<li>관계명 (Membership)
: 관계의 이름</li>
<li>관계차수 (Cardinality)
: 관계를 맺는 엔터티 인스턴스의 차수. 1:1, 1:M, M:N</li>
<li>관계선택사양 (Optionalty)
: 필수적 관계인지 선택적 관계인지 (null 가능 여부)
선택적 관계인 경우 까치발 기호에 O을 붙임</li>
</ul>
<h2 id="5-식별자">5. 식별자</h2>
<h3 id="식별자">식별자</h3>
<p>엔터티 인스턴스를 유일하게 구별하는 속성
해당 인스턴스의 대표 속성</p>
<h3 id="주식별자">주식별자</h3>
<p>해당 엔터티 인스턴스를 유일하게 구별해주는 식별자로 PK에 있는 속성
유일성, 최소성, 불변성, 존재성을 만족해야 함.</p>
<ul>
<li>유일성 : 인스턴스를 유일하게 구별</li>
<li>최소성 : 유일성을 보장하면서 최소 개수의 속성</li>
<li>불변성 : 최초 부여된 값이 변경되지 않고 유지</li>
<li>존재성 : 반드시 값을 가져야 함 (null 안됨)</li>
</ul>
<h3 id="분류-2">분류</h3>
<h4 id="대표성-여부">(대표성 여부)</h4>
<ul>
<li>주식별자</li>
<li>보조식별자
: 해당 엔터티를 유일하게 구별할 수 있는 식별자이기는 하나 대표성을 가지지 못함. 다른 엔터티와 참조관계 연결 불가</li>
</ul>
<p><em>후보키</em> : 유일성과 최소성을 만족하는 속성. 주식별자와 보조식별자를 포함</p>
<h4 id="스스로-생성-여부">(스스로 생성 여부)</h4>
<ul>
<li>내부식별자
: 엔터티 내부에서 스스로 만들어지는 식별자</li>
<li>외부식별자
: 관계를 통해 다른 엔터티로부터 받아오는 식별자(FK)</li>
</ul>
<h4 id="속성의-수">(속성의 수)</h4>
<ul>
<li>단일식별자
: 식별자를 구성하는 속성이 하나</li>
<li>복합식별자
: 식별자를 구성하는 속성이 둘 이상</li>
</ul>
<h4 id="대체-여부">(대체 여부)</h4>
<ul>
<li>본질식별자
: 업무에 존재하는 본래의 식별자 (원조식별자)</li>
<li>인조식별자
: 업무에 존재하지 않으나 원조식별자가 너무 복잡하여 인위적으로 만든 식별자 (대리식별자)</li>
</ul>
<h3 id="비식별자-관계">(비)식별자 관계</h3>
<h4 id="식별자-관계">식별자 관계</h4>
<ul>
<li>강한 연결 관계</li>
<li>부모 엔터티의 식별자가 자식 엔터티의 주식별자 구정에 포함</li>
<li>ERD 상에서 실선으로 표현</li>
<li>부모 엔터티 인스턴스와 자식 엔터티 인스턴스가 같은 생명주기를 가지는 경우 적합</li>
</ul>
<h4 id="비식별자-관계-1">비식별자 관계</h4>
<ul>
<li>약한 연결 관계</li>
<li>부모 엔터티의 식별자가 자식 엔터티의 일반 속성이 됨</li>
<li>ERD 상에서 점선으로 표현</li>
<li>부모 엔터티 인스턴스와 자식 엔터티 인스턴스가 다른 생명주기를 가지는 경우 적합</li>
<li>부모 엔터티 인스턴스에 참조값이 없어도 자식 엔터티 인스턴스가 생성될 수 있을 때 고려</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[DFS, BFS 정리 및 활용(백준 11724)]]></title>
            <link>https://velog.io/@young_k/DFS-BFS-%EC%A0%95%EB%A6%AC-%EB%B0%8F-%ED%99%9C%EC%9A%A9%EB%B0%B1%EC%A4%80-11724</link>
            <guid>https://velog.io/@young_k/DFS-BFS-%EC%A0%95%EB%A6%AC-%EB%B0%8F-%ED%99%9C%EC%9A%A9%EB%B0%B1%EC%A4%80-11724</guid>
            <pubDate>Sat, 28 Jun 2025 14:34:51 GMT</pubDate>
            <description><![CDATA[<h3 id="📌문제접근">📌문제접근</h3>
<p>문제: <a href="https://www.acmicpc.net/problem/11724">백준 11724(연결요소의 개수)</a>
이 문제를 통해 그래프 탐색 알고리즘의 대표적인 두 가지 방법인 <strong>DFS</strong>와 <strong>BFS</strong>에 대해 설명하고자 한다.
문제는 3가지 방법으로 해결하였다.</p>
<ol>
<li>DFS - 재귀함수 활용</li>
<li>DFS - 스택 활용</li>
<li>BFS - 큐 활용</li>
</ol>
<h2 id="🐣dfs-depth-first-search-깊이-우선-탐색">🐣DFS (Depth-First Search, 깊이 우선 탐색)</h2>
<p>시작 노드에서 가능한 깊게 들어간 뒤, 더이상 갈 수 없으면 다시 돌아와 다른 경로를 탐색하는 방식이다.</p>
<ul>
<li>스택이나 재귀함수를 통해 구현</li>
<li><strong>어떤 노드를 방문했는지</strong> 반드시 검사해야 함</li>
<li><strong>모든 경로를 완전 탐색</strong>할 때 유리</li>
</ul>
<p><img src="https://velog.velcdn.com/images/young_k/post/ba7f20f4-4e42-4da4-bda8-efb4ef1359a7/image.png" alt=""></p>
<p>위의 방법으로 그래프를 탐색하는 것을 깊이우선탐색이라고 한다.
종료 후 방문한 노드를 확인하면 <strong>1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 6 -&gt; 5</strong> 순서가 된다.
6에서 5를 방문할 때에는 <strong>4 -&gt; 3 -&gt; 2</strong> 순서로 올라가면 인접한 노드가 있는지 탐색한다. 이러한 진행을 <strong>백트래킹(backtracking)</strong>이라고 한다.</p>
<h3 id="dfs-구현방법-재귀-기반">DFS 구현방법 (재귀 기반)</h3>
<ol>
<li>시작노드 방문(visit 표시)</li>
<li>인접한 노드 방문
2-1. 인접한(방문 가능한) 노드가 없으면 종료. 이전 노드로 돌아감.
2-2. 인접한(방문 가능한) 노드가 있으면 방문(visit 표시, 재귀 호출)</li>
<li>시작노드로 돌아갈 때까지(또는 스택이 모두 빌 때까지) 2번 단계를 반복</li>
<li>visit이 표시되지 않은 정점부터 다시 DFS 진행</li>
</ol>
<h3 id="📌재귀함수를-이용한-dfs-코드">📌재귀함수를 이용한 DFS 코드</h3>
<pre><code class="language-c++">void DFS(int root){
    visited[root] = true; // (1단계) root노드 방문 기록.

    // (2단계)
    for(int i = 0 ; i &lt; nodes[root].size(); i++){ 
        int next = nodes[root][i];
        if (!visited[next]) { // (2-2단계) 인접한 노드 방문을 위한 재귀함수 호출
            DFS(next);
        } // (3단계) 방문할 노드가 없으면 dfs 종료
    }
}

int main() {
  ...  
  // (4단계) 방문하지 않은 노드에서 DFS 진행
  for (int i = 1; i &lt;= n; i++){
      if(!visited[i]) {
          count++;
          DFS(i);
      }
  }

}</code></pre>
<h3 id="📌stack을-이용한-dfs-코드">📌Stack을 이용한 DFS 코드</h3>
<p>스택으로 구현할 때에는 LIFO(Last-in First-out)의 구조로 인해, 같은 깊이 중에서 탐색하고 싶은 정점을 역순으로 넣어야 원하는 탐색 순서를 얻을 수 있다.</p>
<p>위와 같은 탐색 경로를 스택에 저장하는 경우에
1번을 방문하여 인접한 2, 3, 4를 스택에 넣을 때 순서대로 넣으면
<strong>(stack) : 1 - 2 - 3 - 4</strong>
순서로 들어있어 <code>top()</code>으로 확인한 값이 2가 아닌 4가 된다. 그래서 i = 0부터 순서대로 그래프를 탐색하고 싶다면 인접한 노드를 역순으로 넣어야 <code>top()</code>으로 2를 확인할 수 있다.
<strong>(stack) : 1 - 4 - 3 - 2</strong></p>
<pre><code class="language-c++">for (int i = 1; i &lt;= n; i++){
    if(!visited[i]) {
          count++;
          visited[i] = true; // (1단계) 시작 노드 방문 표시
          vertex.push(i);

          while(!vertex.empty()){ // (3단계)스택이 빌 때까지 반복
              int current = vertex.top();
              vertex.pop();

            // (2단계) current 노드와 연결된 노드를 스택에 역순으로 저장
              for (int j = nodes[current].size() - 1; j &gt;= 0; j--){
                  int next = nodes[current][j];
                  if(!visited[next]) {
                      visited[next] = true;
                      vertex.push(next);
                  }
            }    
        }
    }
  }</code></pre>
<h2 id="🐣bfs-breadth-first-search-너비-우선-탐색">🐣BFS (Breadth-First Search, 너비 우선 탐색)</h2>
<p>BFS는 시작 노드에서 인접한 노드를 모두 방문하고 다음 깊이의 노드를 탐색하는 방식이다. (같은  깊이를  먼저 탐색함)</p>
<ul>
<li>큐를 이용하여 구현</li>
<li><strong>어떤 노드를 방문했는지</strong> 반드시 검사해야 함</li>
<li>같은 깊이를 먼저 탐색하기에 <strong>최단 거리 탐색에 유리</strong></li>
</ul>
<h3 id="bfs-구현-방법">BFS 구현 방법</h3>
<ol>
<li>시작 노드 방문 (visit 표시)</li>
<li>인접한 노드 탐색
2-1. 인접한(방문 가능한) 노드가 없으면 큐를 <code>pop()</code> 하여 다음 노드 탐색
2-2. 인접한(방문 가능한) 노드가 있으면 큐에 넣음 (visit 표시)</li>
<li>큐가 소진될 때까지 2단계 반복</li>
</ol>
<p><img src="https://velog.velcdn.com/images/young_k/post/686152b1-be28-4d53-9ef5-b19cd3c63388/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/young_k/post/a58ec3c9-64f2-4021-9587-e80492f3c511/image.PNG" alt=""></p>
<h3 id="📌queue를-이용한-bfs-코드">📌Queue를 이용한 BFS 코드</h3>
<p>큐는 FIFO(First-in First-out)이기에 같은 깊이의 노드를 넓게 탐색할 수 있다.</p>
<pre><code class="language-c++">for (int i = 1; i &lt;= n; i++){
      if(!visited[i]) {
          count++;
          visited[i] = true; // (1단계) 시작 노드 방문 표시
          vertex.push(i);

          while(!vertex.empty()){ // (3단계) 큐가 빌 때까지 반복
              int current = vertex.front();
              vertex.pop();

            // (2단계) current 노드와 연결된 노드를 큐에 저장
              for (int j = 0; j &lt; nodes[current].size(); j++){
                  int next = nodes[current][j];
                  if(!visited[next]) {
                      visited[next] = true;
                      vertex.push(next);
                  }
            }
        }
    }
 }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 21일차 TIL]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-21%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-21%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Mon, 21 Apr 2025 08:56:44 GMT</pubDate>
            <description><![CDATA[<h3 id="📌문제접근">📌문제접근</h3>
<p>문제 : <a href="https://leetcode.com/problems/intersection-of-two-arrays/description/">LeetCode 349. Intersection of Two Arrays</a></p>
<h3 id="📌제출코드">📌제출코드</h3>
<pre><code>class Solution {
public:
    vector&lt;int&gt; intersection(vector&lt;int&gt;&amp; nums1, vector&lt;int&gt;&amp; nums2) {
        vector&lt;int&gt; result;
        set&lt;int&gt; n1(nums1.begin(), nums1.end());
        set&lt;int&gt; n2(nums2.begin(), nums2.end());

        for (auto&amp; n : n2) {
            if (n1.find(n) != n1.end()) {
                result.push_back(n);
            }
        }
        return result;
    }
};</code></pre><p><img src="https://velog.velcdn.com/images/young_k/post/7ab0b66e-f184-46b2-ab6b-d58a83acc0b4/image.png" alt=""></p>
<h3 id="📌오늘의-회고">📌오늘의 회고</h3>
<p>19, 20일차 코딩테스트 문제는 풀지 못했다. 현생이 바빴지만 반성합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 13일차 TIL]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-13%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-13%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Wed, 16 Apr 2025 04:14:14 GMT</pubDate>
            <description><![CDATA[<h3 id="📌문제접근">📌문제접근</h3>
<p>문제 : <a href="https://www.acmicpc.net/problem/1181">백준 1181 : 단어정렬</a></p>
<p>알파벳 소문자로 이루어진 N개의 단어가 들어오면 아래와 같은 조건에 따라 정렬하는 프로그램을 작성하시오.</p>
<p>길이가 짧은 것부터
길이가 같으면 사전 순으로
단, 중복된 단어는 하나만 남기고 제거해야 한다.</p>
<ul>
<li>중복 제거</li>
<li>길이 순 정렬</li>
<li>사전순 정렬 (같은 길이일 때)</li>
</ul>
<h3 id="📌제출코드">📌제출코드</h3>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;map&gt;
#include &lt;vector&gt;

using namespace std;

int main() {
    int n;
    string str;
    map&lt;string, int&gt; strMap;
    map&lt;int, vector&lt;string&gt;&gt; intStrMV;

    cin &gt;&gt; n;
    for (int i = 0; i &lt; n ; i++) {
        cin &gt;&gt; str;
        strMap.insert({str, str.length()});
    }
    for (auto s : strMap) {
        intStrMV[s.second].push_back(s.first);
    }
    for (auto&amp; im : intStrMV) {
        for(auto&amp; strv : im.second) {
            cout &lt;&lt; strv &lt;&lt; endl;
        }
    }
    return 0;    
}</code></pre><h3 id="📌문제-해결">📌문제 해결</h3>
<ol>
<li><p>중복제거
C++에서 <code>map</code>과 <code>set</code>은 <strong>중복된 key를 자동으로 제거</strong>하고, key값을 <strong>오름차순으로 정렬</strong>하는 특성을 가지고 있다. 이러한 특성을 활용하면 문제가 요구하는 두가지 조건을 자연스럽게 만족할 수 있다,
(1) 중복된 단어는 하나만 남긴다. 
(2) 길이가 같으면 사전순으로 정렬한다.
또한, 기본 조건인 <strong>길이가 짧은 순으로 정렬</strong>을 처리하기 위해, 사용자의 입력을 받을 때 각 문자열의 길이 정보를 함께 저장할 수 있는 <code>map&lt;string, int&gt;</code>를 사용하였다.
<code>set</code>을 통해 문자열만 저장하고 나중에 <code>.length()</code>를 길이를 계산할 수도 있지만 이후 과정을 고려하여 문자열과 길이를 함께 저장할 수 있는 <code>map</code>을 선택하였다.</p>
</li>
<li><p>길이순 + 사전순 정렬
<code>map&lt;string, int&gt;</code>에서 이미 사전순으로 자동 정렬되고 value에는 문자열 길이가 저장되어 있으므로, 이를 기반으로 다시 문자열 길이를 기준으로 정렬하면 문제의 조건을 모두 충족할 수 있다.
이를 위해 <code>map&lt;int,vector&lt;string&gt;&gt;</code> 형태를 사용하여, 문자열 길이(int)를 key로 하고 해당 길이에 속하는 문자열들을 <strong>vector로 체이닝</strong>하여 저장하였다. 이 구조에서 <code>map</code>의 특성에 따라 길이는 자동으로 오름차순 정렬되며, 각 <code>vector&lt;string&gt;</code>안에는 이미 사전순으로 정렬된 문자열들이 있게 된다. 이를 이중<code>for</code>문으로 순회하면 문제의 모든 요구조건을 만족한 출력이 가능하다.</p>
</li>
</ol>
<h3 id="📌오늘의-회고">📌오늘의 회고</h3>
<p>자료구조의 기본 특성을 알고 있어야 문제 해결 방향을 잡기 쉽다.<img src="https://velog.velcdn.com/images/young_k/post/8018c7b3-cca2-490f-aaa5-16263ed5e4d6/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 12일차 TIL (백준 25757)]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-12%EC%9D%BC%EC%B0%A8-TIL-%EB%B0%B1%EC%A4%80-25757</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-12%EC%9D%BC%EC%B0%A8-TIL-%EB%B0%B1%EC%A4%80-25757</guid>
            <pubDate>Tue, 15 Apr 2025 04:12:38 GMT</pubDate>
            <description><![CDATA[<h3 id="📌문제접근">📌문제접근</h3>
<p>문제 : <a href="https://www.acmicpc.net/problem/25757">백준 25757 : 임스와 함께하는 미니게임 </a>
유형 : 문자열, 해시테이블</p>
<p>임스가 미니게임을 같이할 사람을 찾고 있습니다.</p>
<p>플레이할 미니게임으로는 윷놀이 $Y$, 같은 그림 찾기 $F$, 원카드 $O$가 있습니다. 각각 2, 3, 4 명이서 플레이하는 게임이며 인원수가 부족하면 게임을 시작할 수 없습니다.</p>
<p>사람들이 임스와 같이 플레이하기를 신청한 횟수 $N$과 임스가 플레이할 게임의 종류가 주어질 때, 최대 몇 번이나 임스와 함께 게임을 플레이할 수 있는지 구하시오.</p>
<p>1) 첫 줄에 총 신청 횟수 N과 진행할 게임이 주어진다
2) N명의 사람 이름이 주어진다. 이때 이름이 동일하면 동일한 사람이다.
2-1) 동일한 이름이 들어오는 것은 무시해도 된다.
3) 한 사람은 한 번만 게임을 할 수 있다.
3-1) 임스는 모든 게임에 참여하므로 실제 필요한 인원은 게임별로 1, 2, 3명이다.</p>
<h3 id="📌제출코드">📌제출코드</h3>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;unordered_set&gt;

using namespace std;

int main() {
    int n;
    char game;

    cin &gt;&gt; n &gt;&gt; game;
    string user;
    unordered_set&lt;string&gt; userSet;

    for (int i = 0; i &lt; n; i++) {
        cin &gt;&gt; user;
        userSet.insert(user);        
    }
    int count = userSet.size();
    if (game == &#39;Y&#39;) {
        cout &lt;&lt; count &lt;&lt; endl;
        return 0;
    }
    if (game == &#39;F&#39;) {
        cout &lt;&lt; count/2 &lt;&lt; endl;
        return 0;
    }
    if (game == &#39;O&#39;) {
        cout &lt;&lt; count/3 &lt;&lt; endl;
        return 0;
    }
    return 0;
}</code></pre><h3 id="📌문제-해결">📌문제 해결</h3>
<ol>
<li>중복되는 인물 처리
동일한 이름은 동일한 사람으로 간주되므로 중복되는 인물은 무시하고 전체 인원 수만 계산하면 된다. 각 이름이 가지는 특별한 의미는 없기 때문에 map이 아닌 set으로 인물을 저장하고 탐색하였다. <img src="https://velog.velcdn.com/images/young_k/post/e90e4cab-ec7f-419a-9955-fe49af953a20/image.png" alt="">
unordered_set은 중복된 값을 자동으로 무시하기 때문에 이 문제에 적합하며, 최총 인원수는 .size()를 통해 간편하게 확인할 수 있다.</li>
</ol>
<h3 id="📌오늘의-회고">📌오늘의 회고</h3>
<p>해시 테이블 활용이 익숙해지고 있는 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 11일차 TIL (LeetCode 187)]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-11%EC%9D%BC%EC%B0%A8-TIL-LeetCode-187</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-11%EC%9D%BC%EC%B0%A8-TIL-LeetCode-187</guid>
            <pubDate>Mon, 14 Apr 2025 05:11:45 GMT</pubDate>
            <description><![CDATA[<h3 id="📌문제접근">📌문제접근</h3>
<p>문제 : <a href="https://leetcode.com/problems/repeated-dna-sequences/description/">LeetCode 187. Repeated DNA Sequences</a>
유형 : 문자열, 비트맵, 해시테이블</p>
<p>1) string에서 반복되는 substring 찾기
2) substring의 길이가 10으로 고정되어있기에 길이가 11이상인 string부터 확인하면 된다
3) substring을 잘라내여 &lt;string, int&gt; 해시맵에 저장하고 동일한 substring이 있는 경우 int값을 +1 한다</p>
<h3 id="📌제출코드">📌제출코드</h3>
<ol>
<li><p>substring 이용</p>
<pre><code>class Solution {
 string subStr;
 unordered_map&lt;string, int&gt; strMap;
public:
 vector&lt;string&gt; findRepeatedDnaSequences(string s) {
     vector&lt;string&gt; result;
     int len = s.length();
     if (len &lt; 11) 
         return result;

     for (int i = 0; i &lt;= len-10; i++) {
         subStr = s.substr(i, 10);
         auto key = strMap.find(subStr);
         if (key != strMap.end()) {
            key-&gt;second++;
             continue;
         } 
         strMap.insert({subStr, 0});    
     }
     for (auto&amp; k : strMap) {
         if (k.second &gt; 0)
             result.push_back(k.first);
     }
     return result;
 }
};</code></pre></li>
<li><p>2비트 인코딩을 이용한 슬라이딩 비트마스크 + 해시맵</p>
<pre><code>class Solution {
 unordered_map&lt;char, int&gt; charToBit = {
     {&#39;A&#39;, 0b00}, {&#39;C&#39;, 0b01}, {&#39;G&#39;, 0b10}, {&#39;T&#39;, 0b11}
 };
 unordered_map&lt;int, int&gt; bitMap;
 vector&lt;string&gt; result;
</code></pre></li>
</ol>
<p>public:
    vector<string> findRepeatedDnaSequences(string s) {
        int len = s.length();
        if (len &lt;= 10) return result;
        int bit = 0;</p>
<pre><code>    for (int i = 0; i &lt; 10 ; i++) {
        bit = bit &lt;&lt; 2 | charToBit[s[i]];
    }
    bitMap.insert({bit, 0});
    int mask = (1 &lt;&lt; 20) - 1;
    for (int i = 1; i &lt; len - 9; i++) {
        bit = (bit &lt;&lt; 2 | charToBit[s[i + 9]]) &amp; mask;

        auto b = bitMap.find(bit);
        if (b != bitMap.end()) {
            b-&gt;second++;
            if (b-&gt;second == 1 ) result.push_back(s.substr(i, 10));
            continue;
        }
        bitMap.insert({bit, 0});
    }
    return result;
}  </code></pre><p>};</p>
<pre><code>### 📌문제 해결
비트연산이 익숙치 않아서 개념을 한번 정리하고 구현하였다.
2비트 인코딩을 이용한 해시맵 방식이 시간효율성 면에서 훨씬 뛰어났다.

**비트 인코딩과 마스킹**

DNA는 &#39;A&#39;, &#39;C&#39;, &#39;G&#39;, &#39;T&#39; 4개의 문자로 되어있어 각각을 2비트 이진수로 표현할 수 있다. 이를 위해</code></pre><p>unordered_map&lt;char, int&gt; charToBit = {
{&#39;A&#39;, 0b00}, {&#39;C&#39;, 0b01}, {&#39;G&#39;, 0b10}, {&#39;T&#39;, 0b11}
}; </p>
<pre><code>해시맵을 사용해 각 문자를 대응되는 비트값으로 매핑한다.
문제에서는 중복된 10글자 DNA 시퀀스를 찾는 것이 목표이며, 각 글자를 2비트로 표현하면 총 20비트이기에 10글자를 int(32비트)에 담을 수 있다. 이를 비트 연산을 통해 순차적으로 인코딩한다.</code></pre><p>bit = (bit &lt;&lt; 2) | 다음_비트;</p>
<pre><code>하지만 비트 인코딩을 반복하다 보면 20비트를 초과한 상위 비트가 남게 될 수 있기에 항상 최근 10글자만 유지하기 위해 마스킹을 적용한다.</code></pre><p>int mask = (1 &lt;&lt; 20) - 1; //하위 20비트가 1인 카스트
bit = (bit &lt;&lt; 2 | 다음_비트) &amp; mask;</p>
<p>```
&amp;mask를 통해 하위 20비트에만 유지하고, 상위비트를 제거하여 bit 변ㅅ는 항상 최근 10글자의 정보만 담게 된다.</p>
<h3 id="📌오늘의-회고">📌오늘의 회고</h3>
<p>문제를 푸는 것은 어렵지 않았지만 구현 코드의 시간효율이 좋지 않았다. 비트맵을 이용하여 다시 풀 예정이다.</p>
<p>+) 2비트 인코딩을 통한 문제 해결 코드 업로드 완료</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 10일차 TIL (백준 2358)]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-10%EC%9D%BC%EC%B0%A8-TIL-%EB%B0%B1%EC%A4%80-2358</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-10%EC%9D%BC%EC%B0%A8-TIL-%EB%B0%B1%EC%A4%80-2358</guid>
            <pubDate>Sat, 12 Apr 2025 14:53:57 GMT</pubDate>
            <description><![CDATA[<h2 id="📌문제접근">📌문제접근</h2>
<p>문제 : 백준 2358 (<a href="https://www.acmicpc.net/problem/2358">https://www.acmicpc.net/problem/2358</a>)
유형 : 정렬, 해시테이블</p>
<p>평면에 n개의 점이 있다. 그중 두 개 이상의 점을 지나면서 x축 또는 y축에 평행한 직선이 몇 개인지 알아내는 프로그램을 작성하시오.</p>
<p>입력 n(1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 줄에는 각 점의 좌표가 주어진다. 같은 좌표가 여러 번 주어질 수 있으며, 그런 경우 서로 다른 점으로 간주한다. 좌표는 절댓값이 231보다 작은 정수이다.</p>
<p>1) x축 또는 y축에 평행하려면 y좌표가 동일한 두 점이거나 x좌표가 동일한 두점이면 된다.
2) n이 (1 ≤ n ≤ 100,000) 이므로 시간복잡도에 신경을 써보자.</p>
<h2 id="📌제출코드">📌제출코드</h2>
<pre><code>#include &lt;iostream&gt;
#include &lt;unordered_map&gt;

using namespace std;


int main() {
    int n, x, y;
    unordered_map&lt;int, int&gt; xCount, yCount;    

    cin &gt;&gt; n;
    for (int i = 0; i &lt; n; i++) {
        cin &gt;&gt; x &gt;&gt; y;
        xCount[x]++;
        yCount[y]++;
    }

    int result = 0;
    for (auto&amp; p : xCount) {
        if (p.second &gt; 1) result++;
    }
    for (auto&amp; p : yCount) {
        if (p.second &gt; 1) result++;
    }

    cout &lt;&lt; result &lt;&lt; endl;

    return 0;     
}</code></pre><h3 id="📌문제-해결">📌문제 해결</h3>
<p>문제의 기본적인 해결 방법은 동일한 x, y좌표가 몇번 들어오는지 카운트 하여 2번 이상인 경우 하나의 평행선을 만들 수 있다. =&gt; 좌표값을 key로 하는 해시맵에 등장 횟수를 카운트 하여 저장한다.</p>
<ol>
<li><p>&#39;같은 좌표는 서로 다른 점으로 간주한다&#39; 의 해석
가장 많은 시간을 고민하게 했던 부분이다.
우선 나의 해석은 (1) 같은 좌표는 서로 다른 점으로 카운트 한다. (2) 서로 다른 두 점으로 평행선을 만들 수 있다. (3) 그러므로 x좌표와 y좌표의 개수를 카운트 할때 해당 key값에 완전히 동일한 좌표의 점만 들어온 경우에는 평행선을 만들 수 없고, 다른 점이 있어야 평행선을 만들 수 있다.
위의 내용을 표현하기 위해서 count를 저장하는 맵뿐 아니라 해당 좌표의 점이 중복되는 점인지 다른 점인지를 확인하는 추가적인 자료구조(적절한 자료구조를 생각하지 못함)이 필요했다. 몇 시간을 고민하는데 원하는 구현이 어려워 문제를 구글링했더니
<img src="https://velog.velcdn.com/images/young_k/post/f1e4a751-d49f-451c-b9d6-ba20a6fb3f22/image.png" alt="">
입력이 같은 두 점으로도 직선을 만들 수 있다는 것을 알게되었다.
그럼 (2)에 대한 고려없이 (1)만 고려하여 카운트를 하면 되기에 구현을 빠르게 마쳤다. 문제 해석의 애매함으로 고민을 많이 했지만 여러가지 구현 방법을 고민했던 시간이 의미있었다..</p>
</li>
<li><p>시간복잡도
해시맵을 이용하여 탐색과 삽입에 평균 O(1)의 시간복잡도가 되도록 구현하였다. 최종 코드의 시간복잡도는 평균 O(n)이다.<img src="https://velog.velcdn.com/images/young_k/post/d9cfab5b-ff76-4ce9-97e1-ec8b47fb2d6a/image.png" alt=""></p>
</li>
</ol>
<hr>
<h3 id="📌오늘의-회고">📌오늘의 회고</h3>
<p>원하는 구현을 위해 자료구조 공부가 더 필요함을 느꼈다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ map, unordered_map (hash map) 차이점과 활용법 정리]]></title>
            <link>https://velog.io/@young_k/C-map-unorderedmap-hash-map-%EC%B0%A8%EC%9D%B4%EC%A0%90%EA%B3%BC-%ED%99%9C%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@young_k/C-map-unorderedmap-hash-map-%EC%B0%A8%EC%9D%B4%EC%A0%90%EA%B3%BC-%ED%99%9C%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 10 Apr 2025 05:17:38 GMT</pubDate>
            <description><![CDATA[<h2 id="1-map">1. map</h2>
<ul>
<li>map은 내부적으로 균형이진트리 구조로 구성됨</li>
<li>각 노드에 &lt;key, value&gt; 쌍을 저장</li>
<li>중복 key를 허용하지 않음</li>
<li>key가 자동으로 정렬됨 (key가 비교 연산 가능해야 함)</li>
<li>탐색, 삽입, 삭제에 O(log n) 소요</li>
</ul>
<h2 id="2-unordered_map-hash-map">2. unordered_map (hash map)</h2>
<ul>
<li>unordered_map은 해시 테이블 기반의 구조</li>
<li>map과 마찬가지로 &lt;key, value&gt; 쌍을 저장함</li>
<li>하지만 key를 정렬하는 것이 아닌 해시 함수를 통한 해시값을 기반으로 저장</li>
<li>동일한 해시값을 가지는 경우(충돌)을 처리할 방법이 필요함
(ex. 2차해시함수, 체이닝)</li>
<li>탐색, 삽입, 삭제는 평균 O(1), 최악의 경우 O(n)소요</li>
</ul>
<h2 id="3-활용">3. 활용</h2>
<h3 id="헤더--선언">헤더 &amp; 선언</h3>
<pre><code>#include &lt;map&gt;
#include &lt;unordered_map&gt;

map&lt;string, int&gt; m;
unordered_map&lt;string, int&gt; um;</code></pre><h3 id="데이터-삽입">데이터 삽입</h3>
<pre><code>m.insert({&quot;Tom&quot;, 100});
um.insert({&quot;Alice&quot;, 300});

m[&quot;Tom&quot;] = 100;
um[&quot;Alice&quot;] = 300;</code></pre><h3 id="데이터-찾기">데이터 찾기</h3>
<pre><code>auto it = m.find(key);
// key가 존재하면 해당 iterator 반환. 없으면 m.end() 반환</code></pre><h3 id="데이터-접근-범위-기반-for문">데이터 접근 (범위 기반 for문)</h3>
<pre><code>for (auto&amp; it : m) {
    cout &lt;&lt; &quot;key: &quot; &lt;&lt; it.first &lt;&lt; &quot; value: &quot; &lt;&lt; it.second &lt;&lt; endl;
}</code></pre><h3 id="데이터-삭제">데이터 삭제</h3>
<ol>
<li>특정 위치 삭제 (iterator)<pre><code>m.erase(m.begin()+1);</code></pre></li>
<li>key값으로 삭제<pre><code>m.erase(key);</code></pre></li>
<li>모든 요소 삭제<pre><code>m.erase(m.begin(), m.end()); // 범위 삭제
m.clear(); // 전체 삭제</code></pre></li>
</ol>
<h3 id="비어있는지-확인">비어있는지 확인</h3>
<pre><code>m.empty(); // 비어있으면 true 반환. 아니면 false</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 09일차 TIL (LeetCode 706)]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-10%EC%9D%BC%EC%B0%A8-TIL-LeetCode-706</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-10%EC%9D%BC%EC%B0%A8-TIL-LeetCode-706</guid>
            <pubDate>Thu, 10 Apr 2025 04:30:28 GMT</pubDate>
            <description><![CDATA[<h2 id="문제접근">문제접근</h2>
<p>문제 : LeetCode 706. Design HashMap
(<a href="https://leetcode.com/problems/design-hashmap/description/">https://leetcode.com/problems/design-hashmap/description/</a>)</p>
<p>해시맵을 이용하여 &lt;key, value&gt;를 put, get, remove하는 함수를 구현하라.</p>
<p>1) 해시맵에 대한 이해
<a href="https://velog.io/@young_k/C-map-unorderedmap-hash-map-%EC%B0%A8%EC%9D%B4%EC%A0%90%EA%B3%BC-%ED%99%9C%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC">C++ map, unordered_map 정리</a></p>
<h2 id="제출코드">제출코드</h2>
<pre><code>#include &lt;vector&gt;
#define SIZE 10000
class MyHashMap {
private:
    vector&lt;vector&lt;pair&lt;int, int&gt;&gt;&gt; hv;
    int hashKey;

public:
    MyHashMap() : hv(SIZE) {

    }

    void put(int key, int value) {
        hashKey = key%SIZE;
        if (hv[hashKey].empty()) {
            hv[hashKey].push_back({key, value});
            return;
        }
        for(auto&amp; k : hv[hashKey]) {
            if (k.first == key) {
                k.second = value;
                return;
            }
        }
        hv[hashKey].push_back({key, value});
        return;
    }

    int get(int key) {
        hashKey = key%SIZE;
        if (hv[hashKey].empty()) return -1;
        for (auto&amp; k : hv[hashKey]) {
            if (k.first == key) return k.second;
        }
        return -1;
    }

    void remove(int key) {
        hashKey = key%SIZE;
        if (hv[hashKey].empty()) return;
        for (auto it = hv[hashKey].begin(); it != hv[hashKey].end(); it++) {
           if (it-&gt;first == key) {
            hv[hashKey].erase(it);
            return;
           }
        }
        return;

    }
};

/**
 * Your MyHashMap object will be instantiated and called as such:
 * MyHashMap* obj = new MyHashMap();
 * obj-&gt;put(key,value);
 * int param_2 = obj-&gt;get(key);
 * obj-&gt;remove(key);
 */</code></pre><h3 id="문제-해결">문제 해결</h3>
<ol>
<li>해시맵 이해
처음에는 해시맵에 대한 이해 없이 &lt;key, value&gt; 쌍을 단순히 벡터에 저장하고 선형 탐색으로 구현하였다. 기능 구현에는 성공했지만 해시맵의 핵심인 해시 함수를 활용하지 못했기 때문에, 이후 해시 함수를 적용한 방식으로 문제를 다시 해결하였다.</li>
<li>해시 함수 및 충돌 관리
충돌 해결 방법으로는 이중 해시보다는 구현이 간단한 체이닝 방식을 선택하였고, 2차원 벡터를 이용해 구조를 설계하였다. 연결 리스트와 벡터 중 고민한 끝에 탐색 속도가 더 빠른 벡터를 사용해 구현하였다.</li>
</ol>
<hr>
<h3 id="오늘의-회고">오늘의 회고</h3>
<p>함수 기능뿐 아니라 요구하는 구조에 맞게 구현하도록 하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 08일차 TIL (LeetCode 2283)]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-09%EC%9D%BC%EC%B0%A8-TIL-LeetCode-2283</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-09%EC%9D%BC%EC%B0%A8-TIL-LeetCode-2283</guid>
            <pubDate>Wed, 09 Apr 2025 05:48:59 GMT</pubDate>
            <description><![CDATA[<h2 id="문제접근">문제접근</h2>
<p>문제 : LeetCode 2283. Check if Number Has Equal Digit Count and Digit Value
(<a href="https://leetcode.com/problems/check-if-number-has-equal-digit-count-and-digit-value/description/">https://leetcode.com/problems/check-if-number-has-equal-digit-count-and-digit-value/description/</a>)
유형 : 문자열/해시</p>
<p>1) 입력된 문자열에서 각 숫자가 몇번 나왔는지 카운트 한다
2) 카운트한 값과 입력된 문자열을 비교한다</p>
<h2 id="제출코드">제출코드</h2>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

using namespace std;

class Solution {
public:
    bool digitCount(string num) {
        vector&lt;int&gt; numCount(10, 0);
        string numTrue;
        int n = num.length();

        for (int i = 0; i &lt; n; i++) {
            int m = (int)num[i] - &#39;0&#39;;
            numCount[m]++;
        }
        for (int i = 0; i &lt; n; i++) {
            numTrue += (char)(numCount[i] + &#39;0&#39;);
        }
        if (numTrue == num)
            return true;
        else
            return false;
    }
};</code></pre><h3 id="문제해결">문제해결</h3>
<p>시간복잡도 : O(n)
문자형과 정수형을 섞어서 코드를 작성할 때 실수하지 않도록 주의 하기</p>
<hr>
<h3 id="오늘의-회고">오늘의 회고</h3>
<p>매일 꾸준히 공부하기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 07일차 TIL (백준 3986: 좋은 단어)]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-07%EC%9D%BC%EC%B0%A8-TIL-%EB%B0%B1%EC%A4%80-3986-%EC%A2%8B%EC%9D%80-%EB%8B%A8%EC%96%B4</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-07%EC%9D%BC%EC%B0%A8-TIL-%EB%B0%B1%EC%A4%80-3986-%EC%A2%8B%EC%9D%80-%EB%8B%A8%EC%96%B4</guid>
            <pubDate>Tue, 08 Apr 2025 02:40:46 GMT</pubDate>
            <description><![CDATA[<h2 id="문제접근">문제접근</h2>
<p>문제 : 백준 3986 (<a href="https://www.acmicpc.net/problem/3986">https://www.acmicpc.net/problem/3986</a>)
유형 : stack</p>
<p>A, B로 이루어진 문자열을 N개 입력받는다. 문자열에서 A는 A끼리, B는 B끼리 선을 이어 서로 겹치지 않으면 좋은 단어로 판단한다. 좋은 단어의 개수를 출력한다.</p>
<p>1) strng을 이용해 문자열 입력 받기
2) 겹치지 않고 선이 그어지려면 문자열의 중심 부분부터 짝꿍이 만들어져야 한다
3) 짝꿍이 있는 문자는 문자열에서 무시해도 된다</p>
<p>-&gt; 단어를 stack으로 받아서 이전 문자와 동일한지 비교하여 짝꿍을 찾는다</p>
<h2 id="제출코드">제출코드</h2>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;stack&gt;


using namespace std;

int main() {
    int n, count = 0;
    string str;
    stack&lt;char&gt; s;

    cin &gt;&gt; n;

    for (int i = 0; i &lt; n; i++) {
        cin &gt;&gt; str;
        if (str.length()%2 == 1) continue;

        for (char c : str) {
            if (!s.empty() &amp;&amp; s.top() == c)
                s.pop();
            else s.push(c);
        }
        if (s.empty()) count++;
        while(!s.empty()) s.pop();
    }
    cout &lt;&lt; count &lt;&lt; endl;
    return 0;
}</code></pre><h3 id="문제-해결">문제 해결</h3>
<ol>
<li>처음 구현시에는 A와 B를 구분하여 스택을 만들어 두개의 스택 상태를 매번 확인하여 문자열을 검사하였다. 구현 중에 단순히 짝꿍을 찾아주면 되는 문제인데 너무 복잡하게 로직을 짜고 있다는게 느껴져서 처음부터 다시 구현했다. 이전에 구현했던 계산기 괄호 입력과 동일한 문제라는 것을 깨닫고 하나의 stack으로 상태와 top()을 확인하여 짝꿍을 확인할 수 있었다.</li>
<li>range-based for loop (범위 기반 for 루프)
c++ 11부터 도입된 범위 기반 for 루프를 통해 좀 더 간단하게 모든 요소를 확인할 수 있다.</li>
</ol>
<hr>
<h3 id="오늘의-회고">오늘의 회고<img src="https://velog.velcdn.com/images/young_k/post/b5c8bac7-0cba-4bd3-9ae5-1098fdf21969/image.png" alt=""></h3>
<p>시간 내로 문제를 해결해보자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ stack, queue 기본 및 사용방법 정리]]></title>
            <link>https://velog.io/@young_k/C-stack-queue-%EA%B8%B0%EB%B3%B8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@young_k/C-stack-queue-%EA%B8%B0%EB%B3%B8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 07 Apr 2025 03:58:59 GMT</pubDate>
            <description><![CDATA[<h2 id="stack-queue-기본">stack, queue 기본</h2>
<p>stack은 LIFO(Last-in, first-out) 데이터 구조이다.
순서대로 a, b, c, d의 입력이 들어온다면 데이터를 꺼낼 때는 d, c, b, a 순서로 마지막 들어온 데이터부터 접근할 수 있다.</p>
<p>queue는 FIFO(First-in, first-out) 데이터 구조이다.
순서대로 a, b, c, d의 입력이 들어온다면 데이터를 꺼낼 때도 a, b, c, d 순서로 접근할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/young_k/post/89adc51f-1fac-48d4-84fe-cf927a5f2658/image.png" alt=""></p>
<h2 id="c-함수-정리">C++ 함수 정리</h2>
<h3 id="stack">stack</h3>
<pre><code>#include &lt;stack&gt;

std::stack&lt;type&gt; s;
</code></pre><ul>
<li>empty()
bool 타입. stack이 비어있는지 판단.
비어있으면 true, 비어있지 않으면 false 반환.</li>
<li>pop()
stack의 맨 위에 있는 요소를 제거함. return 값 없음.</li>
<li>push()
stack의 맨 위에 요소를 추가함. return 값 없음.</li>
<li>size()
stack의 현재 길이를 반환.</li>
<li>top()
stack의 맨 위의 요소에 대한 참조를 반환.</li>
</ul>
<h3 id="queue">queue</h3>
<pre><code>#include &lt;queue&gt;

std::queue&lt;type&gt; q;</code></pre><ul>
<li>empty()
bool 타입. queue가 비어있는지 판단.
비어있으면 true, 비어있지 않으면 false 반환.</li>
<li>pop()
queue의 첫 번째 요소를 제거함. return 값 없음.</li>
<li>push()
queue의 뒤에 요소를 추가함. return 값 없음.</li>
<li>size()
queue의 현재 길이를 반환.</li>
<li>front()
queue의 첫 번째 요소에 대한 참조를 반환.</li>
<li>back()
queue의 마지막 요소 반환. 가장 최근에 추가된 요소의 참조 반환.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 06일차 TIL]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-06%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-06%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Mon, 07 Apr 2025 02:59:08 GMT</pubDate>
            <description><![CDATA[<h2 id="문제접근">문제접근</h2>
<p>문제 : LeetCode 70. Climbing Stairs (<a href="https://leetcode.com/problems/climbing-stairs/description/">https://leetcode.com/problems/climbing-stairs/description/</a>)</p>
<p>1) 1칸과 2칸의 조합으로 n칸을 올라야 함
2) n칸 오르는 방법 
: (n-1)칸을 오르고 + 1칸 오르기
: (n-2)칸을 오르고 + 2칸 오르기
3) n=1 -&gt; 1, n=2 -&gt; 2</p>
<h2 id="제출코드">제출코드</h2>
<pre><code>class Solution {
public:
    int climbStairs(int n) {
        int result = 0;
        if (n == 1) return 1;
        if (n == 2) return 2;
        int s1 = 1, s2 = 2, s3;
        for (int i = 2; i &lt; n ; i++) {
            s3 = s1 + s2;
            s1 = s2;
            s2 = s3;
        }
        return s2;
    }
};</code></pre><h3 id="문제-해결">문제 해결</h3>
<ol>
<li>재귀함수 시간복잡도 문제
처음에는 f(n) = f(n-1) + f(n-2) 형태의 단순 재귀함수로 문제를 구현하였다. 그러나 이 방식은 동일한 계산을 반복적으로 수행하게 되어 시간복잡도가 O(2ⁿ)으로 매우 비효율적이다.
이를 해결하기 위해 재귀 호출 대신 변수를 사용하여 값을 직접 저장하고 누적하는 방식으로 중복 계산을 방지하였다. n = 1, n = 2일 때의 base case를 기준으로, n &gt; 2인 경우에는 반복문을 통해 직접 값을 더해가며 계산하였다.
이 방식은 반복문을 한 번만 수행하므로 시간복잡도는 O(n)으로 효율적이다.</li>
</ol>
<hr>
<h3 id="오늘의-회고">오늘의 회고</h3>
<p>시간복잡도를 고려하여 구현하기.<img src="https://velog.velcdn.com/images/young_k/post/e56d195f-0314-469a-89fa-6af00fc225cd/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 04, 05일차 TIL]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-05%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-05%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Sun, 06 Apr 2025 15:32:39 GMT</pubDate>
            <description><![CDATA[<h2 id="문제접근">문제접근</h2>
<p>문제 : 
LeetCode 232. Implement Queue using Stacks
(<a href="https://leetcode.com/problems/implement-queue-using-stacks/submissions/1599103736/">https://leetcode.com/problems/implement-queue-using-stacks/submissions/1599103736/</a>)
LeetCode 225. Implement Stack using Queues (<a href="https://leetcode.com/problems/implement-stack-using-queues/description/">https://leetcode.com/problems/implement-stack-using-queues/description/</a>)</p>
<ol>
<li>stack과 queue에 대한 이해 필요
<a href="https://velog.io/@young_k/C-stack-queue-%EA%B8%B0%EB%B3%B8-%EC%A0%95%EB%A6%AC">자료구조 stack, queue</a></li>
</ol>
<h2 id="제출코드">제출코드</h2>
<pre><code>#include &lt;stack&gt;

class MyQueue {
private:
stack&lt;int&gt; s_main;
stack&lt;int&gt; s_sub;

public:
    MyQueue() {

    }

    void push(int x) {
        s_main.push(x);
    }

    int pop() {
        while (s_main.size() &gt; 1) {
            s_sub.push(s_main.top());
            s_main.pop();
        }
        int result = s_main.top();
        s_main.pop();
        while(!s_sub.empty()) {
            s_main.push(s_sub.top());
            s_sub.pop();
        }

        return result;
    }

    int peek() {
        while (s_main.size() &gt; 1) {
            s_sub.push(s_main.top());
            s_main.pop();
        }
        int result = s_main.top();

        while(!s_sub.empty()) {
            s_main.push(s_sub.top());
            s_sub.pop();
        }

        return result;
    }

    bool empty() {
        return s_main.empty();
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj-&gt;push(x);
 * int param_2 = obj-&gt;pop();
 * int param_3 = obj-&gt;peek();
 * bool param_4 = obj-&gt;empty();
 */</code></pre><pre><code>#include &lt;queue&gt;

class MyStack {
private:
    queue&lt;int&gt; q1;
    queue&lt;int&gt; q2;

public:
    MyStack() {

    }

    void push(int x) {
        q1.push(x);
    }

    int pop() {
        while(q1.size()&gt;1) {
            q2.push(q1.front());
            q1.pop();
        }
        int result = q1.front();
        q1.pop();
        while(!q2.empty()) {
            q1.push(q2.front());
            q2.pop();
        }
        return result;

    }

    int top() {
        while(q1.size()&gt;1) {
            q2.push(q1.front());
            q1.pop();
        }
        int result = q1.front();
        q2.push(result);
        q1.pop();
        while(!q2.empty()) {
            q1.push(q2.front());
            q2.pop();
        }
        return result;
    }

    bool empty() {
        return q1.empty();
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj-&gt;push(x);
 * int param_2 = obj-&gt;pop();
 * int param_3 = obj-&gt;top();
 * bool param_4 = obj-&gt;empty();
 */</code></pre><hr>
<h3 id="오늘의-회고">오늘의 회고</h3>
<p>쉬는 기간동안 배운 것들을 많이 까먹었다. 더 많은 공부가 필요할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 03일차 TIL]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-03%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-03%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Wed, 02 Apr 2025 03:09:32 GMT</pubDate>
            <description><![CDATA[<h2 id="문제접근">문제접근</h2>
<p>문제 : 백준 31458 (<a href="https://www.acmicpc.net/problem/31458">https://www.acmicpc.net/problem/31458</a>)
분류 : 문자열 구현</p>
<p>T개의 문자열을 입력받는다. 
문자열은 공백이 없는 &quot;!!n!!&quot; 형태로 받아 두가지 규칙(팩토리얼, 논리반전)을 적용하여 출력한다. 정수 n 에는 0 또는 1이 들어간다. 정수 앞/뒤로 &#39;!&#39;가 붙을 수 있다. 각 자리에 0~30개의 !가 붙을 수 있다.</p>
<p>1) 수식의 개수 T를 입력받음
2) 문자열에서 정수 앞 !, 정수, 정수 뒤 !를 구분
3) 정수 뒤 !는 bool형태로 확인하여 판단
4) 정수 앞 !는 홀수/짝수개인지 판단
5) 결과 출력</p>
<h2 id="제출코드">제출코드</h2>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;

using namespace std;

int main() {
    int n, num, front, len;
    bool answer, check_num, back;
    string str;

    cin &gt;&gt; n;
    cin.ignore();

    for (int i = 0; i &lt; n; i++) {
        check_num = false;
        back = false;
        front = 0;

        getline(cin, str);
        len = str.length();

        for (int j = len ; j &gt; 0; j--) {
            if (str[j-1] == &#39;0&#39; || str[j-1] == &#39;1&#39;) {
                check_num = true;
                num = str[j-1] - &#39;0&#39;;
                continue;
            }
            if (check_num == false) back = true;
            else front++;

        }

        if (back == true) answer = 1;
        else answer = num;

        if (front%2 == 0) cout &lt;&lt; answer &lt;&lt; endl;
        else cout &lt;&lt; !answer &lt;&lt; endl;    
    }
    return 0;
}</code></pre><h3 id="문제-해결">문제 해결</h3>
<p><strong>1. 문자열에서의 정수</strong>
string으로 문자열을 받아 중간에 써있는 정수도 char형태라는 것을 까먹었다.</p>
<p>if(str[j-1] == 0 || str[j-1] == 1)
처음에는 정수 0과 1로 조건을 설정해 해당 if문을 건너뛰었다. 코드를 검토하는 과정에서 이를 깨닫고
if(str[j-1] == &#39;0&#39; || str[j-1] == &#39;1&#39;)
num = str[j-1] - &#39;0&#39;;
으로 수정하였다.</p>
<hr>
<h3 id="오늘의-회고">오늘의 회고</h3>
<p>구현에만 초점을 두고 빠르게 하려고 하니 기초적인 부분에서 문제가 생긴다. 지금은 실력 상승보다느 머릿속 깊은 곳에 있는 내용을 하나씩 꺼내서 정리하는 수준이다. 앞으로 열심히 해야지..! 화이팅!<img src="https://velog.velcdn.com/images/young_k/post/f3d200d7-e802-4267-ac51-2377b99a08fa/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 02일차 TIL]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-02%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-02%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Tue, 01 Apr 2025 07:57:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/young_k/post/64ac9455-d4c9-4562-b081-623af48fe470/image.png" alt=""></p>
<h2 id="문제접근">문제접근</h2>
<p>문제 : 백준 10820 (<a href="https://www.acmicpc.net/problem/10820">https://www.acmicpc.net/problem/10820</a>)
유형 : 문자열 구현</p>
<p>n (1 &lt;= n &lt;= 100)줄의 문자열을 받아 각 문자열에 대해 소문자, 대문자, 숫자, 공백의 개수를 구분하여 출력. </p>
<p>1) 공백을 포함한 문자열을 입력받기에 cin이 아닌 getline을 이용.
1-1) 몇 줄의 문자열이 입력될지 모르기에 while문으로 루프를 돌리고 break 조건을 생각함.
2) string으로 문자열을 받아 앞에서부터 하나씩 접근하여 문자를 구분.
3) low_c, up_c, num, space 변수에 개수 저장
4) 결과 출력</p>
<h2 id="제출코드">제출코드</h2>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;cctype&gt;

using namespace std;

int main() {
    string str;
    vector&lt;int&gt; low_v, up_v, num_v, space_v;

    char c;
    int count=0;
    int low_c, up_c, num, space; 


    while(1){
        getline(cin, str);
        if (cin.eof()) break;
        low_c = 0;
        up_c = 0;
        num = 0;
        space = 0;

        count++;
        for (int i=0;;i++) {
            c = str[i];
            if (islower(c) != 0) low_c++;
            else if(isupper(c) != 0) up_c++;
            else if (isdigit(c) != 0) num++;
            else if (isspace(c) != 0) space++;
            else break;
        }
        low_v.push_back(low_c);
        up_v.push_back(up_c);
        num_v.push_back(num);
        space_v.push_back(space);


    }
    for (int i =0; i &lt; count; i++) {
        cout &lt;&lt; low_v[i] &lt;&lt; &quot; &quot; &lt;&lt; up_v[i] &lt;&lt; &quot; &quot; &lt;&lt; num_v[i] &lt;&lt; &quot; &quot; &lt;&lt; space_v[i] &lt;&lt; endl;
    }

    return 0;
}</code></pre><h3 id="구현과정-문제-해결">구현과정 문제 해결</h3>
<p><strong>1. 입력 종료 시점(?)의 문제</strong></p>
<p>처음 구현할 당시에는 while문 루프 상황에서 break포인트로
getline(cin, str);
if(str.empry()) break; 
로 구현하였다.</p>
<p>이렇게 구현하면 생기는 문제는 (1) 사용자 입력이 &#39;\n&#39;로 끝난 후에 한번 더 엔터를 입력해야 된다. (2) (이건 회고하는 과정에서 생각한건데) 말그대로 빈 문자열을 무시하게 된다. 라는 두가지 문제가 생긴다.
백준에서 제공하는 입력 예시에서 모든 문장의 마지막이 &#39;\n&#39;로 끝나기에 무엇으로 break 조건을 설정할지 고민했다.</p>
<p>결론은 질문게시판을 통해 EOF로 문자열의 종료를 알려주는 방법으로 구현하였다. EOF를 알고있었지만 파일과 문자열을 동일 선상에서 생각하고 있지 않아서 (크기를 알지 못한 채) 연속으로 입력되는 문자열을 처리하는 다른 방법이 있을거라 생각하느라 시간이 많이 지체되고 헤맸다.
이번 경험으로 알게 되었으니 이게 코딩테스트 스터디의 좋은점이 아닐까싶다. 알던 것도 더 열심히 생각하고 고민하게 된다.</p>
<p>최종적으로는
if(cin.eof()) break;
로 구현하였다. 참고로 cin.eof()는 eof일 때 true(1)을 반환하고 나머지 상황에는 false를 반환한다. 콘솔에서 eof를 나타내고 싶다면 &#39;Ctrl+x&#39;를 통해 입력할 수 있다.</p>
<p><strong>2. 입출력 방식</strong>
이건 문제는 아니지만 구현하다보니 억울했던 부분이다.
백준 예시입력과 예시출력이 여러줄로 묶여있어서 입력을 모두 받은 후에 한번에 출력을 해야된다고 이해했다.</p>
<p>그래서 개수를 저장한 변수 값들을 바로 출력하지 않고 한 번 더 저장할 공간이 필요했다. 이는 vector를 통해 각 문자별 벡터를 만들어 첫번째 문자열부터 개수를 하나씩 저장하여 while문이 종료된 후에 for문으로 순서대로 돌며 출력하게 하였다.
다른 사람들의 결과를 보니 (입력-출력)을 함께 반복시켜도 문제가 없더라... 굳이 vector까지 사용을 안해도 됐었는데 아쉽다. </p>
<hr>
<h3 id="오늘의-회고">오늘의 회고</h3>
<p>아직 모르는 내용과 함수가 많다. 초반에는 문제를 푸는 것과 다른 사람들의 답안을 보면서 비교하며 공부하는 것이 도움될 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[99클럽 코테스터디 6기 01일차 TIL]]></title>
            <link>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-01%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@young_k/99%ED%81%B4%EB%9F%BD-%EC%BD%94%ED%85%8C%EC%8A%A4%ED%84%B0%EB%94%94-6%EA%B8%B0-01%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Mon, 31 Mar 2025 12:43:44 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/young_k/post/b9a57063-32d0-4c43-afc0-dbba8eff83f4/image.png" alt="">
25/03/31
개발자 취업 준비를 위해 99클럽 코테스터디를 시작했습니다.
앞으로 꾸준히 공부할 저를 응원하고 기대하며 TIL을 작성해보려 합니다.
함께 스터디를 하는 여러분을 응원하며 의미있는 4주를 보내봐요!!</p>
<h2 id="문제-접근">문제 접근</h2>
<p>문제 : 백준 1032 (<a href="https://www.acmicpc.net/problem/1032">https://www.acmicpc.net/problem/1032</a>)
분류 : 문자열</p>
<p>n개의 파일 이름을 입력받아 1)모두 동일한 문자는 그대로 출력 2)다른 문자는 &#39;?&#39;로 출력하여 파일 이름의 패턴을 분석.</p>
<h3 id="접근방법">접근방법</h3>
<p>1) 문자열 처리를 위해 string 헤더 사용
2) 중첩 for문을 이용해 string arr에 입력된 파일 이름을 자리별로 비교하여 출력 string에 추가함.
2-1) [0]-&gt;[len]까지 반복하며(첫번째 for문)
2-2) 각 파일이름을 직전 파일이름과 비교 (두번째 for문)
2-3) 
문제(직전 파일 이름과 다른 경우) 검출 -&gt; answer += &#39;?&#39;
문제 없음 -&gt; 해당 문자를 answer에 추가</p>
<h2 id="제출-코드">제출 코드</h2>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
using namespace std;


int main() {
    int n, len;
    string file_name[51];

    cin &gt;&gt; n;

    for (int i =0; i &lt;n; i++) {
        cin &gt;&gt; file_name[i];
    }

    len = file_name[0].length();    

    if(n == 1) {
        cout &lt;&lt; file_name[0];
        return 0;    
    }

    string answer;
    for(int i=0;i&lt;len;i++) {
        for(int j=1;j&lt;n;j++) {        
            if(file_name[j-1].at(i) == file_name[j].at(i)) {
                if (j == n-1) 
                    answer += file_name[j].at(i);
            }
            else {
                answer +=&#39;?&#39;;
                break;
            }
        }
    }

    cout &lt;&lt; answer &lt;&lt; endl;

    return 0;
}</code></pre><hr>
<h3 id="오늘의-회고">오늘의 회고</h3>
<p>오랜만에 문제를 풀려고 하니 손도 굳고 어리도 굳어서... 시간이 오래걸렸다.
혼자서 문제를 풀때는 타임어택의 부담이 크지 않았는데 99클럽으로 문제를 풀면서 타임어택의 부담감으로 최종 코드가 난잡해졌다.
아직 라이브러리 활용이나 기본적인 알고리즘 지식이 부족하지만 부족해서 스터디를 하는거니 열심히 해보겠습니다.</p>
<p>** 다른 분들의 TIL을 보니 더 많은 분석과 회고를 작성하셨네요... 앞으로의 과정에서 발전하는 모습을 보이겠습니다.</p>
<hr>
<h3 id="99클럽-코테스터디-목표">99클럽 코테스터디 목표</h3>
<ul>
<li>c++과 파이썬으로 비기너 문제 100% 풀기</li>
<li>TIL 70% 이상 작성</li>
<li>미들러 문제 50% 이상 풀기</li>
<li>자료구조 및 알고리즘 심화 공부</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>