<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>markme</title>
        <link>https://velog.io/</link>
        <description>기록</description>
        <lastBuildDate>Mon, 24 Jul 2023 10:46:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. markme. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mar_f" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[3장. 시스템 설계 면접 공략법]]></title>
            <link>https://velog.io/@mar_f/3%EC%9E%A5.-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%84%A4%EA%B3%84-%EB%A9%B4%EC%A0%91-%EA%B3%B5%EB%9E%B5%EB%B2%95</link>
            <guid>https://velog.io/@mar_f/3%EC%9E%A5.-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%84%A4%EA%B3%84-%EB%A9%B4%EC%A0%91-%EA%B3%B5%EB%9E%B5%EB%B2%95</guid>
            <pubDate>Mon, 24 Jul 2023 10:46:30 GMT</pubDate>
            <description><![CDATA[<h2 id="시스템-설계-면접시-진행과정">시스템 설계 면접시 진행과정</h2>
<ol>
<li>문제 이해 및 설계 범위 확정 : 3분~10분</li>
<li>개략적 설계안 제시 및 동의 구하기 : 10분~15분</li>
<li>상세 설계 : 15분~25분</li>
<li>마무리 : 3분~5분</li>
</ol>
<h2 id="해야할것">해야할것</h2>
<ul>
<li>질문하기</li>
<li>문제의 요구사항 이해</li>
<li>정답이라고 확신하지 말것</li>
<li>면접관과 소통해라</li>
<li>가능하다면 여러해법을 제시해라</li>
<li>개략적 설계에 면접관이 동의하면, 세부사항을 설명해라</li>
<li>면접관의 아이디어를 이끌어내라</li>
<li>포기하지 말라</li>
</ul>
<h2 id="하지-말아야-할-것">하지 말아야 할 것</h2>
<ul>
<li>전형적인 면접 문제에는 대비</li>
<li>요구사항이나 가정들을 분명히 하지않은 상태에서 설계를 제시하지 마라</li>
<li>처음부터 특정 컴포넌트의 세부사항을 너무 깊이 설명하지 마라</li>
<li>진행 중에 막혔다면, 힌트를 청하기 주저하지 말라</li>
<li>의견을 일찍, 그리고 자주 구해라</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2장. 개략적인 규모 추정]]></title>
            <link>https://velog.io/@mar_f/2%EC%9E%A5.-%EA%B0%9C%EB%9E%B5%EC%A0%81%EC%9D%B8-%EA%B7%9C%EB%AA%A8-%EC%B6%94%EC%A0%95</link>
            <guid>https://velog.io/@mar_f/2%EC%9E%A5.-%EA%B0%9C%EB%9E%B5%EC%A0%81%EC%9D%B8-%EA%B7%9C%EB%AA%A8-%EC%B6%94%EC%A0%95</guid>
            <pubDate>Wed, 19 Jul 2023 04:40:11 GMT</pubDate>
            <description><![CDATA[<p>어떤 설계가 요구사항에 부합하는지 확인하기 위해서 개략적인 규모 추정이 필요하다.</p>
<h2 id="2의-제곱수">2의 제곱수</h2>
<h3 id="데이터-볼륨단위">데이터 볼륨단위</h3>
<p>최소 단위는 1byte, 8bit로 구성
ASCII 문자 하나가 차지하는 메모리 크기가 1바이트</p>
<table>
<thead>
<tr>
<th align="left">2의 x제곱</th>
<th>근사치</th>
<th align="center">이름</th>
<th align="right">축약형</th>
</tr>
</thead>
<tbody><tr>
<td align="left">10</td>
<td>1천(thousand)</td>
<td align="center">1Kilobyte</td>
<td align="right">1KB</td>
</tr>
<tr>
<td align="left">20</td>
<td>1백만(million)</td>
<td align="center">1Megabyte</td>
<td align="right">1MB</td>
</tr>
<tr>
<td align="left">30</td>
<td>1억(billion)</td>
<td align="center">1Gigabyte</td>
<td align="right">1GB</td>
</tr>
<tr>
<td align="left">40</td>
<td>1조(trillion)</td>
<td align="center">1Terabyte</td>
<td align="right">1TB</td>
</tr>
<tr>
<td align="left">50</td>
<td>1000조(quadrillion)</td>
<td align="center">1Petabyte</td>
<td align="right">1PB</td>
</tr>
</tbody></table>
<h2 id="응답지연-값">응답지연 값</h2>
<ul>
<li>메모리는 빠르지만 디스크는 아직도 느리다.</li>
<li>디스크 탐색(seek)은 가능한 한 피해라</li>
<li>단순한 압축 알고리즘은 빠르다.</li>
<li>데이터를 인터넷으로 전송하기 전에 가능하면 압축해라</li>
<li>데이터 센터는 보통 여러지역에 분산되어 있고, 센터들 간에 데이터를 주고받는데는 시간이 걸린다.<h2 id="가용성에-관계된-수치들">가용성에 관계된 수치들</h2>
고가용성 (High Availability)</li>
<li>오랜 시간동안 지속적으로 운영될 수 있는 능력</li>
<li>퍼센트로 표현. 100%는 시스템이 한번도 중단된적 없었음을 의미</li>
</ul>
<p>SLA (Service Level Agreement)</p>
<ul>
<li>서비스 사용자가 보편적으로 사용하는 용어</li>
<li>서비스 사업자와 고객 사에에 맺어진 합의</li>
<li>9가 많을 수록 좋다고 보면됨</li>
</ul>
<h2 id="면접-팁">면접 팁</h2>
<ul>
<li>근사치를 활용한 계산 : 계산 결과의 정확함을 평가하는게 아니라면 적절한 근사치를 활용해 시간 절약</li>
<li>가정을 적어둬라</li>
<li>단위를 붙여라</li>
<li>많이 출제되는 개략적 규모 추정 문제는 QPS, 최대 QPS, 저장소 요구량, 캐시 요구량, 서버 수 등을 측정하는 것이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[1장. 사용자 수에 다른 규모 확장성]]></title>
            <link>https://velog.io/@mar_f/1%EC%9E%A5.-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%88%98%EC%97%90-%EB%8B%A4%EB%A5%B8-%EA%B7%9C%EB%AA%A8-%ED%99%95%EC%9E%A5%EC%84%B1</link>
            <guid>https://velog.io/@mar_f/1%EC%9E%A5.-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%88%98%EC%97%90-%EB%8B%A4%EB%A5%B8-%EA%B7%9C%EB%AA%A8-%ED%99%95%EC%9E%A5%EC%84%B1</guid>
            <pubDate>Wed, 19 Jul 2023 04:23:28 GMT</pubDate>
            <description><![CDATA[<h2 id="단일서버">단일서버</h2>
<p>복잡한 시스템을 구상하기 전, 기본적으로 다음과 같은 시스템 구조로 시작할 수 있다.
<img src="https://velog.velcdn.com/images/mar_f/post/f70fccc8-d354-4777-8316-234aeacce084/image.png" alt="단일서버로 구성된 시스템 구조"></p>
<h2 id="데이터-베이스">데이터 베이스</h2>
<p><img src="https://velog.velcdn.com/images/mar_f/post/a9ac500f-9aef-4479-8abf-d46988307cd6/image.png" alt="단일서버 + 
DB로 구성된 시스템 구조"></p>
<h3 id="데이터베이스-종류">데이터베이스 종류</h3>
<p><img src="https://velog.velcdn.com/images/mar_f/post/80c5ae3c-7826-41a6-9099-1674f28e9cc9/image.png" alt="데이터베이스 종류"></p>
<h4 id="관계형-db">관계형 DB</h4>
<ul>
<li>자료를 테이블과 열, 칼럼으로 표현</li>
<li>SQL을 사용해 데이터를 INSERT, DELETE, UPDATE, JOIN 등을 할 수 있다.<h4 id="nosql-db">NoSQL DB</h4>
</li>
<li>키-값 저장소, 그래프 저장소, 칼럼 저장소, 문서 저장소가 대표적으로 있다.<h4 id="언제-nosql-db를-사용할까">언제 NoSQL DB를 사용할까?</h4>
</li>
<li><strong>아주 낮은 응답 지연시간</strong>이 요구될때 (RDB에서 Join을 통해 시간이 오래걸릴 수 있음)</li>
<li>다루는 데이터가 <strong>비정형(unstructured)</strong> 이라 관계형 데이터가 아님 (이미지, 비디오, 웹페이지와 같은 경우)</li>
<li>데이터(JSON, YAML, XML 등)를  직렬화하거나 역직렬화 할 수 있기만 하면됨 </li>
<li><blockquote>
<p>데이터 직렬화 : 데이터를 JSON, YAML, XML과 같은 형식으로 변환</p>
</blockquote>
</li>
<li><blockquote>
<p>데이터 역직렬화 : 직렬화된 데이터를 원래의 데이터 형태로 복원하는 과정</p>
</blockquote>
</li>
</ul>
<h2 id="수직적-규모-확장-vs-수평적-규모-확장">수직적 규모 확장 vs 수평적 규모 확장</h2>
<h3 id="수직적-규모-확장">수직적 규모 확장</h3>
<ul>
<li>서버의 성능 향상 (더 좋은 CPU, 더 좋은 RAM)</li>
<li>한계가 있음. 무한대로 CPU, RAM을 추가할 수 없다.</li>
<li>하나의 서버로 운영되어서 자동복구(failover)/다중화(redundancy) 방안이 없다. -&gt; 서버에 장애가 발생하면 웹사이트/앱은 완전히 중단됨<h3 id="수평적-규모-확장">수평적 규모 확장</h3>
</li>
<li>서버의 대수를 증가 </li>
<li><blockquote>
<p>로드밸런서 도입</p>
</blockquote>
</li>
<li><blockquote>
<p>데이터베이스 다중화</p>
</blockquote>
<h4 id="로드밸런서">로드밸런서</h4>
<img src="https://velog.velcdn.com/images/mar_f/post/8c783385-cc89-41ce-a924-48d7b648071d/image.png" alt=""></li>
<li>로드밸런서의 public IP 주소로 접속 </li>
<li><blockquote>
<p>클라이언트는 직접 웹 서버로 접근하지 않는다. </p>
</blockquote>
</li>
<li><blockquote>
<p>서버간 통신에는 private IP 주소 이용
(private IP : 같은 네트워크에 속한 서버 사이의 통신에만 쓰일 수 있음)</p>
</blockquote>
</li>
<li>이점</li>
<li><blockquote>
<p>서버 1이 다운되어도 서버2를 사용하면 됨. 웹 사이트 전체가 다운되는 일이 방지된다.</p>
</blockquote>
</li>
<li><blockquote>
<p>부하를 나누기 위해 새로운 서버 추가 가능</p>
</blockquote>
</li>
</ul>
<h4 id="데이터베이스-다중화">데이터베이스 다중화</h4>
<p><img src="https://velog.velcdn.com/images/mar_f/post/1f58fe4e-473e-48fe-a2b0-0603b1f53a0e/image.png" alt=""></p>
<ul>
<li><p>주(master)-부(slave) 관계 설정</p>
</li>
<li><blockquote>
<p>주데이터 서버 : 쓰기 연산 (write operation)</p>
</blockquote>
</li>
<li><blockquote>
<p>부데이터 서버 : 읽기 연산 (read operation)</p>
</blockquote>
</li>
<li><p>이점</p>
</li>
<li><blockquote>
<p>더 나은 성능 : 쓰기,읽기 연산을 분산시켜 처리할 수 있는 쿼리가 늘어나므로 성능이 좋아진다.</p>
</blockquote>
</li>
<li><blockquote>
<p>안전성(reliability) : 데이터를 지역적으로 떨어진 여러 장소에 다중화를 시켜서 자연재해 등으로 데이터 베이스 서버 일부가 다운되어도 데이터는 보존된다.</p>
</blockquote>
</li>
<li><blockquote>
<p>가용성(availability) : 하나의 데이터베이스 서버에 장애가 발생해도 다른 서버에 있는 데이터를 가져와 계속 서비스 가능</p>
</blockquote>
</li>
<li><p>대응방법</p>
</li>
<li><blockquote>
<p>부서버가 한대인데 다운 : 주서버가 임시적으로 읽기연산 받음. 이후 새로운 부서버가 장애 서버를 대체</p>
</blockquote>
</li>
<li><blockquote>
<p>부서버 여러대인 경우 다운 : 다른 부서버가 읽기연산 처리. 이후 새로운 부서버가 장애 서버를 대체</p>
</blockquote>
</li>
<li><blockquote>
<p>주서버 다운 : 만약 하나의 부서버만 있다면 이게 주서버가 되면서 모든 연산 처리. 이후 새로운 부서버 추가. 부서버 데이터가 최신 상태가 아니면 <strong>복구 스크립트</strong> 추가
(다중마스터, 원형다중화를 도입하면 이런 상황 대처할 수 있음)</p>
</blockquote>
<h2 id="캐시">캐시</h2>
<p>값비싼 연산결과 또는 자주 참조되는 데이터를 메모리 안에 두고, 뒤이은 요청이 보다 빨리 처리될 수 있도록 하는 저장소
<img src="https://velog.velcdn.com/images/mar_f/post/d77a697d-0dce-4b3b-841e-28a362c8e53d/image.png" alt="읽기 주도형 캐시 전략"></p>
</li>
<li><p>이를 <strong>읽기 주도형 캐시 전략</strong> 이라고 한다.</p>
</li>
<li><p>캐시할 데이터 종류, 크기, 액세스 패턴에 맞는 캐시 전략을 선택하면 된다.</p>
</li>
<li><p>캐시 서버는 주로 API를 이용해 사용한다.</p>
<h3 id="주의할점">주의할점</h3>
</li>
<li><p>데이터 종류 : 캐시는 휘발성 메모리에 두어서 영속적으로 보관할 데이터는 저장하지 않는다.</p>
</li>
<li><p>만료 (expire) 정책 : 만료된 데이터는 캐시에서 삭제된다. 따라서 캐시 데이터 관리를 위해 만료 정책이 필요하다.</p>
</li>
<li><blockquote>
<p>만료기한 짧음 : 데이터베이스를 너무 자주 읽는다.</p>
</blockquote>
</li>
<li><blockquote>
<p>만료기한 너무 김 : 원본 데이터와 차이가 날 수 있다.</p>
</blockquote>
</li>
<li><p>일관성 : 저장소의 원본은 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션으로 처리되지 않을때 일관성 깨질 수 있음</p>
</li>
<li><p>장애대응 : 캐시 서버 한대만 두면 단일 장애 지점 (Single Poing Of Failure, SPOF)가 되어버릴 수 있다. -&gt; 캐시 서버 분산</p>
</li>
<li><p>캐시 메모리</p>
</li>
<li><blockquote>
<p>너무 작음 : 데이터가 너무 자주 캐시에서 밀려난다. 성능 떨어짐</p>
</blockquote>
</li>
<li><blockquote>
<p>따라서 캐시 메모리를 과할당(overprovision)하는게 좋다.</p>
</blockquote>
</li>
<li><p>데이터 방출(eviction)정책 : 캐시가 꽉차면 데이터 방풀을 해야한다.</p>
</li>
<li><blockquote>
<p>LRU(Least Recently Used) : 마지막으로 사용된 시점이 가장 오래된 데이터를 내보내는 정책</p>
</blockquote>
</li>
<li><blockquote>
<p>LFU(Least Frequently Used) : 사용 빈도가 가장 낮은 데이터를 내보내는 정책</p>
</blockquote>
</li>
<li><blockquote>
<p>FIFO(First In First Out) : 가장 먼저 들어온 데이터를 가장 먼저 내보내는 정책</p>
</blockquote>
<h2 id="콘텐츠-전송-네트워크-cdn">콘텐츠 전송 네트워크 (CDN)</h2>
</li>
<li><p><strong>정적 콘텐츠 전송</strong> 시 사용하며, <strong>지리적으로 분산</strong> 된 서버의 네트워크</p>
</li>
<li><p>이미지, 비디오, CSS, JavaScript 파일 등 캐시
<img src="https://velog.velcdn.com/images/mar_f/post/770ab834-1e9d-4ef8-a143-dc66ebeba03c/image.png" alt=""></p>
<h3 id="고려사항">고려사항</h3>
</li>
<li><p>비용 : 보통 third-party providers에 의해 운영. 따라서 자주 사용되지 않는 콘텐츠는 CDN에서 제외</p>
</li>
<li><p>적절한 만료 시한 설정 : time-sensitive 콘텐츠는 만료 시점을 잘 정해야한다. 너무 길면 콘텐츠의 신선도가 떨어지고, 너무 짧으면 원본 서버에 빈번히 접속함</p>
</li>
<li><p>CDN 장애 대처 : 클라인트 측에서 CDN이 장애나면 원본 서버로부터 데이터를 가져오도록 구성할 수 있다.</p>
</li>
<li><p>콘텐츠 무효화</p>
</li>
<li><blockquote>
<p>CDN 서비스 사업자가 제공하는 API를 이용해 콘텐츠 무효화</p>
</blockquote>
</li>
<li><blockquote>
<p>콘텐츠의 다른 버전을 서비스하도록 object-versioning 이용. URL 마지막에 버전 번호를 인자로 주면됨. (ex : image.png?v=2)</p>
</blockquote>
<h2 id="무상태stateless-웹-계층">무상태(stateless) 웹 계층</h2>
<p>웹 계층을 수평적으로 확장하는 방법</p>
</li>
<li><blockquote>
<p>상태 정보(사용자 세션 데이터와 같은)를 웹 계층에서 제거</p>
</blockquote>
</li>
<li><blockquote>
<p>상태정보를 관계형 데이터베이스나 NoSQL, Memcached/Redis 같은 캐시 시스템에 보관하고 필요할때 갖고옴</p>
</blockquote>
<h2 id="데이터-센터">데이터 센터</h2>
</li>
<li><p>장애가 없는 상황에서 사용자는 가장 가까운 데이터 센터로 안내된다. 이것을 지리적 라우팅이라고 함. 
(geoDNS : 사용자의 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정할 수 있도록 하는 DNS 서비스)</p>
</li>
<li><p>데이터 센터를 이용하면 하나에 시미각한 장애가 발생하면 모든 트래픽은 장애가 없는 데이터 센터로 전송된다.</p>
</li>
</ul>
<h3 id="고려사항-1">고려사항</h3>
<ul>
<li>트래픽 우회 : 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 찾아야함. 지리적으로 고려하는 건 GeoDNS 이용</li>
<li>데이터 동기화(synchronization) : 한곳에 장애가 났을때 다른곳에서 동일한 데이터를 사용하기 위해서는 데이터를 여러 데이터센터에 다중화를 한다.</li>
<li>테스트와 배포 : 자동화된 배포 도구는 모든 데이터 센터에 동일한 서비스가 설치되도록 하는데 중요한 역할</li>
</ul>
<h2 id="메세지-큐">메세지 큐</h2>
<ul>
<li>메세지의 무손실을 보장하는 비동기 통신(asynchronous communication)을 지원하는 컴포넌트이다. </li>
<li>서비스 또는 서버 간 결합이 느슨해져서 규모 확장성이 보장되어야 하는 안정적 애플리케이션을 구상하기 좋다.</li>
<li>사용예</li>
<li><blockquote>
<p>사진 보정 애플리케이션 : 보정은 시간이 오래 걸리니깐 비동기적으로 처리하면 편하다.</p>
</blockquote>
<h2 id="로그-메트릭-그리고-자동화">로그, 메트릭 그리고 자동화</h2>
</li>
<li>로그 : 에러 로그를 모니터링 하면 시스템의 오류와 문제들을 보다 쉽게 찾아낼 수 있다. 로그를 단일 서비스로 모아주는 도구를 사용하면 더 편리하게 검색 해볼 수 있다. (ex : Avo)</li>
<li>메트릭 : 사업현황에 관한 유용한 정보 + 시스템의 현재 상태 파악</li>
<li><blockquote>
<p>호스트 단위 메트릭 : CPU, 메모리, 디스크 I/O에 관한 메트릭</p>
</blockquote>
</li>
<li><blockquote>
<p>종합 메트릭 : 데이터베이스 계층의 성능, 캐시 계층의 성능</p>
</blockquote>
</li>
<li><blockquote>
<p>핵심 비지니스 메트릭 : 일별 능동 사용자, 수익, 재방문</p>
</blockquote>
</li>
<li>자동화</li>
<li><blockquote>
<p>지속적 통합 (Continuous Integration)을 도와주는 도구를 활용하면 개발자가 만드는 코드가 어떤 검증 절차를 자동으로 거치도록 할 수 있어 문제를 쉽게 감지</p>
</blockquote>
</li>
<li><blockquote>
<p>빌드, 테스트, 배포 등의 절차를 자동화할 수 있어서 개발 생산성 향상</p>
</blockquote>
<h2 id="데이터베이스의-규모확장">데이터베이스의 규모확장</h2>
<h3 id="수직적-확장">수직적 확장</h3>
</li>
<li>기존 서버에 고성능 자원 증설<h4 id="문제점">문제점</h4>
</li>
<li>데이터베이스 서버 하드웨어에는 한계가 있다.</li>
<li>SPOF(Single Poing Of Failure)로 인한 위험성</li>
<li>비용이 많이 든다.</li>
</ul>
<h3 id="수평적-확장">수평적 확장</h3>
<h4 id="샤딩">샤딩</h4>
<ul>
<li>대규모 데이터베이스를 <strong>shard</strong> 라고 부르는 작은 단위로 분할하는 기술</li>
<li>모든 샤드는 같은 스키마를 쓰지만 샤드에 보관되는 데이터 사이에는 중복이 없다.</li>
</ul>
<h3 id="고려사항-2">고려사항</h3>
<ul>
<li>데이터의 재샤딩해야하는 경우</li>
<li><blockquote>
<p>데이터가 너무 많아져서 하나의 샤드로는 더이상 감당하기 어려울때</p>
</blockquote>
</li>
<li><blockquote>
<p>샤드 간 데이터 분포가 균등하지 못해서 어떤 샤드에 할당된 공간소모가 다른 샤들에 비해 빨리 진행될때 (샤드 소진). 샤드 키 변경하고 데이터 재배치 해야됨</p>
</blockquote>
</li>
<li>유명인사 문제</li>
<li><blockquote>
<p>특정 샤드에 질의가 집중되어 서버에 과부하가 걸리는 문제</p>
</blockquote>
</li>
<li><blockquote>
<p>케이티페리, 저스틴비버와 같은 유명인사가 전부 같은 샤드에 저장되면 과부하가 될 수 있음</p>
</blockquote>
</li>
<li><blockquote>
<p>유명인사 각각에 샤드 할당 / 더 잘게 쪼개기</p>
</blockquote>
</li>
<li>조인과 비정규화</li>
<li><blockquote>
<p>하나의 데이터베이스를 여러 샤드 서버로 쪼개면, 조인하기 어려움.</p>
</blockquote>
</li>
<li><blockquote>
<p>데이터베이스를 비정규화. 하나의 테이블에서 질의가 수행되도록 한다.</p>
</blockquote>
</li>
</ul>
<h2 id="요약">요약</h2>
<ul>
<li>웹 계층은 무상태 계층으로</li>
<li>모든 계층에 다중화 도입</li>
<li>가능한 한 많은 데이터를 캐시할 것</li>
<li>여러 데이터 센터를 지원할 것</li>
<li>정적 콘텐츠는 CDN을 통해 서비스 할 것</li>
<li>데이터 계층은 샤딩을 통해 그 규모를 확장할 것</li>
<li>각 계층은 독립적 서비스로 분할할 것</li>
<li>시스템을 지속적으로 모니터링하고, 자동화 도구들을 활용할 것</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[python] Defaulting to user installation because normal site-packages is not writeable 에러해결]]></title>
            <link>https://velog.io/@mar_f/python-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%84%A4%EC%B9%98%EC%8B%9C-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@mar_f/python-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%84%A4%EC%B9%98%EC%8B%9C-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Tue, 27 Sep 2022 18:15:42 GMT</pubDate>
            <description><![CDATA[<p>pip install을 이용해서 python 라이브러리를 설치할때 </p>
<blockquote>
<p>Defaulting to user installation because normal site-packages is not writeable</p>
</blockquote>
<p>이러한 에러가 발생할 때가 있다.
일반 사이트패키지를 쓸 수 없다는 말인데 이것의 원인은 두가지가 있다.</p>
<ol>
<li>서버 환경에 여러개의 python이 설치된 경우</li>
<li>접근 권한이 없는 경우</li>
</ol>
<p>1번의 경우에는 인터프리터를 정확히 명시해서 install을 진행하면 된다. 
나는 Python3의 버전이 여러개여서 다음과 같이 표기하였다.</p>
<blockquote>
<p>python3.9 -m pip install &lt;패키지명&gt;</p>
</blockquote>
<p>python3 버전이 하나라면 다음과 같이 표기하면 된다.</p>
<blockquote>
<p>python3 -m pip install &lt;패키지명&gt;</p>
</blockquote>
<p><a href="https://itsmycode.com/solved-defaulting-to-user-installation-because-normal-site-packages-is-not-writeable/">참고</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] 소스트리를 이용해 병합 충돌 해결하기]]></title>
            <link>https://velog.io/@mar_f/Git-%EC%86%8C%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EB%B3%91%ED%95%A9-%EC%B6%A9%EB%8F%8C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mar_f/Git-%EC%86%8C%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EB%B3%91%ED%95%A9-%EC%B6%A9%EB%8F%8C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 27 Jul 2022 16:48:08 GMT</pubDate>
            <description><![CDATA[<p>git pull 문제를 다음과 같이 해결해보니, 이제는 소스트리에서 병합충돌이 났다고 뜬다.
<a href="https://velog.io/@mar_f/Git-git-pull-%EC%95%88%EB%90%A8-Not-possible-to-fast-foward-aborting">git pull 문제 해결</a></p>
<p><img src="https://velog.velcdn.com/images/mar_f/post/dea0466a-be66-4b99-9b92-fa8790910aff/image.png" alt="소스트리 내 충돌병합"></p>
<p>과연 <em>충돌해결 밑의 메뉴</em> 는 어디에 있을까</p>
<p>워크스페이스 &gt; 파일상태 &gt; 충돌난 파일 오른쪽 클릭 &gt; 충돌 해결하기</p>
<p>여기에서 </p>
<ul>
<li>&#39;내것&#39;을 이용해 해결</li>
<li>&#39;저장소&#39;것을 사용하여 해결</li>
</ul>
<p>두가지가 뜰텐데, 어느것으로 병합하고 싶은지 선택하면 된다. 나는 저장소것을 선택했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] git pull 안됨 & Not possible to fast-foward, aborting]]></title>
            <link>https://velog.io/@mar_f/Git-git-pull-%EC%95%88%EB%90%A8-Not-possible-to-fast-foward-aborting</link>
            <guid>https://velog.io/@mar_f/Git-git-pull-%EC%95%88%EB%90%A8-Not-possible-to-fast-foward-aborting</guid>
            <pubDate>Wed, 27 Jul 2022 16:41:08 GMT</pubDate>
            <description><![CDATA[<h2 id="문제발생">문제발생</h2>
<p>local branch가 remote branch 보다 커밋이 앞서 있어서 발생</p>
<p>아래와 같은 에러메세지가 출력이 된다.
<img src="https://velog.velcdn.com/images/mar_f/post/0cd8b12e-572e-45dc-bc3a-7e76db3ee725/image.png" alt="에러메세지"></p>
<h2 id="git-pull-안되는-문제-해결">git pull 안되는 문제 해결</h2>
<p>에러메세지가 알려준 힌트를 따른다.</p>
<p><strong>git config pull.rebase false</strong> 
: pull 할때 rebase 하지 않고 merge 한다.
<strong>git config pull.rebase true</strong>
: pull 할때 rebase 한다.
<strong>git config pull.ff only</strong>
: fast-foward일때만 pull을 허용한다.</p>
<p>하지만, _Fatal: Not possible to fast-forward, aborting / fatal: 정방향이 불가능하므로, 중지합니다. _ 이러한 에러가 떠버렸다. </p>
<h2 id="not-possible-to-fast-foward-aborting-해결">Not possible to fast-foward, aborting 해결</h2>
<p>1) git pull --rebase로 해결한다.
2) 근본적인 해결
git pull 문제 해결에서 세번째 명령(git config pull.ff only)은 fast-forward만 하겠다는 것이다. 
이 경우 merge가 불가능하고, merge가 필요한 경우에는 정방향으로 진행하는게 불가능하다는 에러 메세지가 뜨면서 진행을 하지 않는다.
따라서 근본적으로 해결하려면 fast-forward only 옵션을 아래 명령을 이용해 끄면된다.</p>
<pre><code>git config --unset pull.ff</code></pre><p>참고 : <a href="https://sanghye.tistory.com/43">https://sanghye.tistory.com/43</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 level2] 순위 검색 (c++)]]></title>
            <link>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%88%9C%EC%9C%84%EA%B2%80%EC%83%89</link>
            <guid>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%88%9C%EC%9C%84%EA%B2%80%EC%83%89</guid>
            <pubDate>Thu, 07 Apr 2022 09:04:47 GMT</pubDate>
            <description><![CDATA[<p>프로그래머스 level2 수준인 순위검색 문제이다.</p>
<p>효율성 검사가 있어서 그런가
체감상 level2보다 어렵게 느껴졌다.</p>
<p>다시한번 문자열에 약하다는 걸 느꼈고 덕분에 새로운 구현 방식도 알게되었다!!</p>
<h2 id="1차시도">1차시도</h2>
<ol>
<li>query를 띄어쓰기 단위로 끊어 벡터에 저장</li>
<li>info를 띄어쓰기 단위로 끊어 벡터에 저장</li>
<li>해당 query를 모든 info를 돌면서 만족하는 info가 발생할때마다 카운트</li>
</ol>
<p>-&gt; 시간복잡도 <strong>O(N^2)</strong> 발생</p>
<pre><code class="language-c">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;string.h&gt;
#include &lt;iostream&gt;

using namespace std;

vector&lt;int&gt; solution(vector&lt;string&gt; info, vector&lt;string&gt; query) {
    vector&lt;int&gt; answer;

    for(int i=0; i&lt;query.size(); i++)
    {
        char ch[query[i].size()];
        strcpy(ch, query[i].c_str());
        char *ptr = strtok(ch, &quot; &quot;);
        vector &lt;string&gt; v;
        v.clear();
        while(ptr != NULL)
        {
            v.push_back(string(ptr));
            ptr = strtok(NULL, &quot; &quot;);
        }

        int cnt = 0;
        for(int j=0; j&lt;info.size(); j++)
        {
            char c[info[j].size()];
            strcpy(c, info[j].c_str());
            char *pt = strtok(c, &quot; &quot;);
            vector &lt;string&gt; i;
            i.clear();

            while(pt != NULL)
            {
                i.push_back(string(pt));
                pt = strtok(NULL, &quot; &quot;);
            }

            int l = 0;
            for(int k=0; k&lt;i.size(); k++)
            {
                if(k==4 &amp;&amp; stoi(i[k]) &gt;= stoi(v[v.size()-1])) {
                    cnt++; 
                }
                else {
                    if(v[k*2]==&quot;-&quot;) {continue;}
                    if(i[k] == v[k*2]) continue;
                    else break;
                }
            }
        }
        answer.push_back(cnt);
    }
    return answer;
}</code></pre>
<p>이렇게 했는데 segmentation fault가 겁나 많이 떠버림..
이 방법을 고쳐볼까 했지만 어차피 효율성이 꽝일거라 예상 되어서 다른 방법을 찾았다. </p>
<h2 id="2차시도">2차시도</h2>
<p>효율성을 줄이기 위해서는 score 정렬이 필요하다고 생각되었다.
이것외에는 방법이 떠오르지 않아 구글링을 하였다.</p>
<p><a href="https://codingwell.tistory.com/51">참고코드</a></p>
<h3 id="구현">구현</h3>
<ol>
<li>info 파싱</li>
</ol>
<p>-를 포함한 모든 경우의 수 map에 넣어주기
2. 이분탐색을 위해 score 기준으로 각각의 map 정렬
3. query 파싱
띄어쓰기를 제외한 문자열을 모두 합해줌
4. query 문자열로 info map에서 조건의 만족하는 경우의 수를 찾음 
<strong>lower_bound()</strong> 사용</p>
<h3 id="코드">코드</h3>
<pre><code class="language-c">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;unordered_map&gt;
#include &lt;sstream&gt;
#include &lt;algorithm&gt;

using namespace std;
unordered_map &lt;string,vector&lt;int&gt;&gt; um;

void addCases(string *s, int score)
{
    for(int i=0; i&lt;16; i++)
    {
        string str=&quot;&quot;;
        int num = i;
        for(int j=3; j&gt;=0; j--)
        {
            if(num &lt;= 0 || num%2 == 0)
            {
                str = &quot;-&quot; + str;
            }
            else str = s[j] + str;
            num /= 2;
        }
        um[str].push_back(score);
    }
}
vector&lt;int&gt; solution(vector&lt;string&gt; info, vector&lt;string&gt; query) {
    vector&lt;int&gt; answer;
    string s[4], str=&quot;&quot;;

    for(int i=0; i&lt;info.size(); i++)
    {
        istringstream stt(info[i]);
        stt &gt;&gt; s[0] &gt;&gt; s[1] &gt;&gt; s[2] &gt;&gt; s[3] &gt;&gt; str;
        addCases(s, (int)stoi(str));
    }

    for(auto itr = um.begin(); itr!=um.end(); itr++)
    {
        sort(itr-&gt;second.begin(), itr-&gt;second.end());
    }

    for(int i=0; i&lt;query.size(); i++)
    {
        istringstream stt(query[i]);
        stt &gt;&gt; s[0] &gt;&gt; str &gt;&gt; s[1] &gt;&gt; str &gt;&gt; s[2] &gt;&gt; str &gt;&gt; s[3] &gt;&gt; str;
        int score = (int)stoi(str);

        vector &lt;int&gt; v = um[s[0]+s[1]+s[2]+s[3]];
        if(v.size()!=0)
        {
            int idx = lower_bound(v.begin(), v.end(), score) - v.begin();
            answer.push_back(v.size() - idx);
        }
        else answer.push_back(0);
    }
    return answer;
}</code></pre>
<h2 id="c-문법">C++ 문법</h2>
<h3 id="1-문자열-나누기">1. 문자열 나누기</h3>
<p>크게 두가지 방식으로 나눌 수 있다.
<a href="https://inmagicisland.tistory.com/4">문자열 나누는 2가지 방법</a></p>
<p>이 중 나는 무조건 istringstream 방식을 사용하기로 했다.
(예외 : 문자열 구분자 2개 이상이면 strtok 사용)</p>
<p><a href="https://codingwell.tistory.com/41">istringstream 사용 방법</a></p>
<p>위의 블로그에서도 알 수 있듯이 stringstream은 공백과 &#39;\n&#39;을 제외하고 문자열에서 맞는 자료형의 정보를 빼낸다.
따라서 다음과 같이 아주 간편하게 문자열을 분리할 수 있다.
꼭 기억해놔야하는 문법이다.</p>
<pre><code class="language-c">istringstream stt(query[i]);
stt &gt;&gt; s[0] &gt;&gt; str &gt;&gt; s[1] &gt;&gt; str &gt;&gt; s[2] &gt;&gt; str &gt;&gt; s[3] &gt;&gt; str;</code></pre>
<h3 id="2-map-사용법">2. map 사용법</h3>
<p>카카오 문제를 풀기 전까지는 Map을 그다지 많이 사용하지 않았는데 이제는 거의 매번 사용하는 것 같다. </p>
<pre><code class="language-c">unordered_map &lt;string,vector&lt;int&gt;&gt; um;
vector &lt;int&gt; v = um[s[0]+s[1]+s[2]+s[3]];</code></pre>
<h4 id="이번에-알게된-방법-위-코드-참고">이번에 알게된 방법 (위 코드 참고)</h4>
<p>1) 동일한 string에 대해 int값을 여러개 삽입하는데 아주 유용하다.
2) 값이 아주 많거나 효율적으로 사용해야하는 경우 unordered_map을 사용할 수 있다.
<a href="https://math-coding.tistory.com/31">unordered_map 사용법</a>
3) map의 second 자료형이 vector인 경우에 vector에 할당가능 (이건 당연한 소리임. 근데 이걸 여지껏 안 이용했다는게 좀 충격)</p>
<h3 id="그러면-왜-unordered_map이-효율적인가">그러면 왜 unordered_map이 효율적인가?</h3>
<p>unordered_map은 해쉬테이블로 구현한 자료구조로 탐색시간복잡도는 O(1)이 된다.
반면 map은 Binary Search Tree로 탐색 시간 복잡도는 O(logn n)이다.
따라서 unordered_map은 중복된 데이터를 허용하지 않고 map에 비해 데이터가 많을시 월등히 좋은 성능을 보인다.
하지만, key가 유사한 데이터가 많을 시 해시 충돌로 인해 성능이 떨어질 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 level2] 단체사진 찍기 (C++)]]></title>
            <link>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8B%A8%EC%B2%B4%EC%82%AC%EC%A7%84%EC%B0%8D%EA%B8%B0</link>
            <guid>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%8B%A8%EC%B2%B4%EC%82%AC%EC%A7%84%EC%B0%8D%EA%B8%B0</guid>
            <pubDate>Wed, 30 Mar 2022 14:48:06 GMT</pubDate>
            <description><![CDATA[<p>조합을 통해 모든 경우의 수를 찾고 조건에 맞는지 찾는 문제이다. (프로그래머스 level2)</p>
<p>문제는 다음과 같다.
<a href="https://programmers.co.kr/learn/courses/30/lessons/1835">단체사진 찍기</a></p>
<p>처음에 봤을땐 확률과 통계 풀듯이 뭐 N과 F사이에 0을 넣어줘야되나? 뭐 이런 생각이 들었다.</p>
<p>하지만 이건 사람이나 할수있는 일이고 
컴퓨터로는 <em>모든 경우의 수에 대해서 조건만 맞는지</em> 확인해주면 된다.</p>
<h3 id="구현">구현</h3>
<ol>
<li>입력받은 data를 따로 저장</li>
<li>조합으로 얻은 string 과 data의 조건이 일치한지 확인</li>
</ol>
<h3 id="c-문법">C++ 문법</h3>
<ol>
<li>모든 조건을 찾는건 <strong>next_permutation()</strong> 을 사용하였다. 
next_permutation는 string에서도 잘 적용됨을 확인할 수 있다.</li>
<li>string으로 입력될때 숫자도 문자임을 주의하자. 
0의 아스키코드는 48이다.
int diff = nowStr[4]-48; </li>
</ol>
<h3 id="코드">코드</h3>
<pre><code class="language-c">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
#include &lt;cmath&gt;

using namespace std;

bool isRight(int diff, int real, char sign)
{
    if(sign == &#39;=&#39;) return diff == real;
    else if(sign == &#39;&lt;&#39;) return real &lt; diff;
    else if(sign == &#39;&gt;&#39;) return real &gt; diff;
}
int solution(int n, vector&lt;string&gt; data) {
    int answer = 0;
    string friends = &quot;ACFJMNRT&quot;;
    do{
        bool flag = true;
        for(int i=0; i&lt;n; i++)
        {
            string nowStr = data[i];
            char f = nowStr[0];
            char s = nowStr[2];
            char sign = nowStr[3];
            int diff = nowStr[4]-48;

            int fIdx = -1, sIdx = -1;
            for(int j=0; j&lt;8; j++)
            {
                if(friends[j] == f) fIdx = j;
                else if(friends[j] == s) sIdx = j;
            }
            int tmpDiff = abs(fIdx-sIdx)-1;
            if(!isRight(diff, tmpDiff, sign)) {
                flag=false;
                break;
            }
        }
        if(flag) answer++;
    }while(next_permutation(friends.begin(), friends.end()));
    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 level2] 메뉴 리뉴얼 (C++)]]></title>
            <link>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%A9%94%EB%89%B4%EB%A6%AC%EB%89%B4%EC%96%BC</link>
            <guid>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%A9%94%EB%89%B4%EB%A6%AC%EB%89%B4%EC%96%BC</guid>
            <pubDate>Wed, 30 Mar 2022 14:34:23 GMT</pubDate>
            <description><![CDATA[<p>조합과 map을 사용해서 해결할 수 있는 문제이다. (프로그래머스 level2)</p>
<p>문제는 다음과 같다.
<a href="https://programmers.co.kr/learn/courses/30/lessons/72411">메뉴 리뉴얼</a></p>
<h3 id="어떻게-풀었는가">어떻게 풀었는가?</h3>
<ol>
<li>next_permutation()으로 조합구함</li>
<li>map에 해당 문자열을 추가하고 문자열 등장 횟수 확인 </li>
<li>가장 많이 나온 문자열을 출력</li>
</ol>
<h3 id="조건">조건</h3>
<ol>
<li>최소 2명 이상의 손님으로부터 주문된 단품메뉴 조합에 대해서만 코스요리 메뉴 후보에 포함한다.</li>
<li>2명 이상의 코스요리가 없을 경우에는 해당 개수의 코스요리는 출력하지 않는다.</li>
<li>가장 많이 주문된 메뉴 구성이 여러개라면, 모두 배열에 담아 return 한다.</li>
<li>오름차순으로 정렬해서 return 한다.</li>
</ol>
<h3 id="구현">구현</h3>
<ol>
<li>해당 손님이 시킨 단품메뉴의 개수만큼 vector를 할당한다. (len)</li>
<li>구해야하는 코스요리의 개수(cnt)만큼 vector에 true를 할당한다.</li>
<li>이 vector에 대해서 next_permutation을 반복한다. -&gt; 조합구하기</li>
<li>조합을 구해 true인 문자를 모아 문자열로 만들고 map 사용<ul>
<li>이미 있는 문자열 -&gt; m[tmp]++;</li>
<li>없는 문자열 -&gt; m.insert({tmp,1});</li>
</ul>
</li>
<li>가장 많이 나온 문자열을 answer에 추가한다.</li>
</ol>
<p>1~5 반복하면됨</p>
<h3 id="코드">코드</h3>
<pre><code class="language-c">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;map&gt;
#include &lt;algorithm&gt;

using namespace std;
map &lt;string,int&gt; m;

vector&lt;string&gt; solution(vector&lt;string&gt; orders, vector&lt;int&gt; course) {
    vector&lt;string&gt; answer;
    for(int i=0; i&lt;course.size(); i++)
    {
        int cnt = course[i];
        for(int j=0; j&lt;orders.size(); j++)
        {
            int len = orders[j].length();
            if(len &lt; cnt) continue;
            sort(orders[j].begin(), orders[j].end());
            vector &lt;bool&gt; v(len-cnt, false);
            v.insert(v.end(), cnt, true);

            do{
                string tmp = &quot;&quot;;
                for(int k=0; k&lt;len; k++)
                {
                    if(v[k]){
                        tmp += orders[j][k];
                    }
                }
                if(m.find(tmp) == m.end()){
                    m.insert({tmp,1});
                }
                else{
                    m[tmp]++;
                }
            }while(next_permutation(v.begin(), v.end()));
        }
        int maxCnt = 0;
        for(auto itr=m.begin(); itr!=m.end(); itr++)
        {
            if(maxCnt &lt; itr-&gt;second) maxCnt = itr-&gt;second;
        }
        if(maxCnt==1) continue;
        for(auto itr=m.begin(); itr!=m.end(); itr++)
        {
            if(maxCnt == itr-&gt;second)
            {
                answer.push_back(itr-&gt;first);
            }
        }
        m.clear();
    }
    sort(answer.begin(), answer.end());
    return answer;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 level3] 자물쇠와 열쇠 (C++)]]></title>
            <link>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%9E%90%EB%AC%BC%EC%87%A0%EC%99%80%EC%97%B4%EC%87%A0</link>
            <guid>https://velog.io/@mar_f/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%9E%90%EB%AC%BC%EC%87%A0%EC%99%80%EC%97%B4%EC%87%A0</guid>
            <pubDate>Wed, 30 Mar 2022 14:10:41 GMT</pubDate>
            <description><![CDATA[<p>2020 kakao blind recruitment에서 나왔던 문제로 복잡한 구현문제입니다. (프로그래머스 level3)</p>
<p>문제는 다음과 같습니다.
<a href="https://programmers.co.kr/learn/courses/30/lessons/60059">자물쇠와 열쇠</a></p>
<h3 id="조건">조건</h3>
<ol>
<li>key의 크기 M은 lock의 크기 N 이하이다.</li>
<li>key는 이동과 회전이 가능하다. (90,180,270도 모두 가능)</li>
<li>key의 돌기부분(1)과 자물쇠의 홈 부분(0)이 일치해야 한다.</li>
<li>자물쇠의 모든 홈을 채워 비어있는 곳이 없어야 자물쇠를 열 수 있다.</li>
</ol>
<p>조건이 참 많은 구현문제입니다.
key의 이동과 회전에 대해서 어떻게 짜야할지 감이 안 잡혀 다음의 티스토리를 참고했습니다.
<a href="https://yabmoons.tistory.com/678">참고</a></p>
<h3 id="구현과정">구현과정</h3>
<ol>
<li>배열을 N+2<em>(M-1)로 만듭니다.
key가 이동이 가능하기 때문에 lock에 일부만 걸쳐있을 수 있습니다. 따라서 열쇠가 이동가능한 영역은 N+2</em>(M-1) X N+2<em>(M-1) 가 됩니다.
=&gt; *</em>solution() 참고**</li>
<li>1에서 구한 배열에 lock 부분 할당하기
확장된 배열의 중앙에 lock을 할당합니다.
lock이 아닌부분 -&gt; 2
lock인 부분 -&gt; 0/1
lock의 시작좌표  : (0,0) -&gt; (M-1, M-1)
lock의 종료좌표 : (N,N) -&gt; (배열크기-M, 배열크기-M)
=&gt; <strong>make_MAP() 참고</strong></li>
<li>key, lock을 비교<ul>
<li>key (0), lock (0) -&gt; 틀림</li>
<li>key (1), lock (1) -&gt; 틀림</li>
<li>key (1), lock (0) -&gt; 맞음
=&gt; <strong>isUnlock() 참고</strong></li>
</ul>
</li>
<li>key의 이동
key는 N+M-1 만큼 오른쪽, 아래로 움직일 수 있음
=&gt; <strong>move_key() 참고</strong></li>
<li>key의 회전
시계방향으로 90도 회전하면 
(y,x) &lt;- (M-1-x,y)
=&gt; <strong>rotate_key() 참고</strong></li>
</ol>
<h3 id="코드">코드</h3>
<pre><code class="language-c">#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;

using namespace std;

vector&lt;vector&lt;int&gt;&gt; MAP;
int N, M, Size, sum;

void make_MAP(vector&lt;vector&lt;int&gt;&gt; lock)
{
    int y = 0, x = 0;
    for(int i=M-1; i&lt;Size-M+1; i++, y++)
    {
        for(int j=M-1; j&lt;Size-M+1; j++, x++)
        {
            if(lock[y][x]==0) {MAP[i][j] = 0; sum++;}
            else MAP[i][j] = 1;
        }
        x=0;
    }
}
int isUnlock(int y, int x, vector&lt;vector&lt;int&gt;&gt; key)
{
    int idx_x = 0, idx_y = 0;
    int cnt = 0;
    for(int i=y; i&lt;y+M; i++, idx_y++)
    {
        for(int j=x; j&lt;x+M; j++, idx_x++)
        {
            if(key[idx_y][idx_x]==0 &amp;&amp; MAP[i][j]==0) return -1;
            if(key[idx_y][idx_x]==1 &amp;&amp; MAP[i][j]==1) return -1;
            if(key[idx_y][idx_x]==1 &amp;&amp; MAP[i][j]==0) cnt++;
        }
        idx_x=0;
    }

    return cnt;
}
void rotate_key(vector&lt;vector&lt;int&gt;&gt; &amp;key)
{
    vector&lt;vector&lt;int&gt;&gt; tmp = key;
    for(int i=0; i&lt;M; i++)
    {
        for(int j=0; j&lt;M; j++)
        {
            tmp[i][j] = key[M-1-j][i];
        }
    }
    key = tmp;
}
bool move_key(vector&lt;vector&lt;int&gt;&gt; key)
{
    for(int i=0; i&lt;4; i++)
    {
        //시작칸수
        for(int j=0; j&lt;M+N-1; j++)
        {
            for(int k=0; k&lt;M+N-1; k++)
            {
                if(isUnlock(j,k,key)==sum)
                {
                    return true;
                }
            }
        }
        rotate_key(key);
    }
    return false;
}
bool solution(vector&lt;vector&lt;int&gt;&gt; key, vector&lt;vector&lt;int&gt;&gt; lock) {
    bool answer = true;
    M = key.size();
    N = lock.size();
    Size = N+(M-1)*2;
    MAP.resize(Size, vector&lt;int&gt;(Size,2));

    make_MAP(lock);
    if(!move_key(key)) answer = false;
    return answer;
}</code></pre>
<h3 id="c-문법">c++ 문법</h3>
<ul>
<li>2차원 배열 -&gt; vector &lt;vector&lt;<em>int</em>&gt;&gt; v 
(크기를 모를때 int arr[][] 보다 좋은 듯)</li>
<li>vector 크기 지정 및 값 할당</li>
</ul>
<ol>
<li>선언시 할당
vector&lt;<em>int</em>&gt; vec(5,1)</li>
<li>재할당 or 선언 이후 할당
vec.resize(10,2)</li>
</ol>
<blockquote>
<p>[resize 주의할점]
resize하며 더 커지는 경우에만 값이 들어간다.
더 작아지는 경우에는 크기만 작아지고 값이 할당되지는 않는다.</p>
</blockquote>
<p>  이 코드에서는 </p>
<pre><code>  MAP.resize(Size, vector&lt;int&gt;(Size,2));</code></pre><p>  이렇게 사용하였다.
  2차원 vector를 size만큼 지정하고 vector<int> (size,2)의 값을 할당한다는 의미
  즉 모든 값을 2로 할당</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[BOJ 3020 개똥벌레]]></title>
            <link>https://velog.io/@mar_f/BOJ-3020-%EA%B0%9C%EB%98%A5%EB%B2%8C%EB%A0%88</link>
            <guid>https://velog.io/@mar_f/BOJ-3020-%EA%B0%9C%EB%98%A5%EB%B2%8C%EB%A0%88</guid>
            <pubDate>Tue, 04 Jan 2022 09:17:37 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/3020">BOJ 3020</a>
이분탐색 문제로 처음 이 문제를 접하였다.
하지만 계속 고민을 해봐도 이분탐색으로는 생각이 나지 않았다.</p>
<p>스터디원에게 누적합이라는 힌트를 얻고
<a href="acmicpc.net/problem/21318">BOJ 21318</a> 
위 문제를 통해 누적합 감을 잡고
다시 개똥벌레를 풀어보았지만,,,,,
모든 높이를 점검해보는 방법(결국에 이방법으로 풀음)밖에 
생각이 안나서 구글링을 해보았다...🤓</p>
<p><a href="https://velog.io/@lacram/C-%EB%B0%B1%EC%A4%80-3020%EB%B2%88-%EA%B0%9C%EB%98%A5%EB%B2%8C%EB%A0%88">참고코드</a>
upper_bound / lower_bound를 사용해서 해결했다!!</p>
<h2 id="c의-이분탐색">C++의 이분탐색</h2>
<p>c++에서는 이진탐색으로 원소를 탐색하는 <strong>lower_bound / upper_bound</strong>를 사용한다.</p>
<blockquote>
<p><em>배열 또는 리스트가 정렬되어있어야한다</em></p>
</blockquote>
<p>이 조건이 성립되어야 사용가능하다.</p>
<p>이진탐색을 사용하기 위한 조건과 같다는 점을 알 수 있다.</p>
<p>또한 이진탐색의 원리를 갖고있기 때문에 O(logN) 시간복잡도를 갖습니다.</p>
<h3 id="lower_bound">lower_bound</h3>
<ul>
<li>이 함수는 찾고자 하는 key값과 크거나 같은 원소의 위치를 구하는 것 입니다.</li>
<li>같은 원소가 여러개 있어도 유일한 해를 찾을 수 있습니다.</li>
<li>사용방법<pre><code>template &lt;class ForwardIterator, class T&gt;
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T&amp; val);
</code></pre></li>
</ul>
<pre><code>lower_bound(v.first(), v.end(), 4);
이런식으로 사용합니다.



### upper_bound
- key값을 초과하는 가장 첫 번째 원소의 위치를 구하는 것 입니다.
- 같은 원소가 여러개 있어도 유일한 해를 찾을 수 있습니다.
- 사용방법</code></pre><p>template &lt;class ForwardIterator, class T&gt;
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T&amp; val);</p>
<pre><code>upper_bound(v.first(), v.end(), 4);
이런식으로 사용합니다.


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[이분탐색]]></title>
            <link>https://velog.io/@mar_f/%EC%9D%B4%EB%B6%84%ED%83%90%EC%83%89</link>
            <guid>https://velog.io/@mar_f/%EC%9D%B4%EB%B6%84%ED%83%90%EC%83%89</guid>
            <pubDate>Tue, 04 Jan 2022 08:46:00 GMT</pubDate>
            <description><![CDATA[<h2 id="범위를-반씩-좁혀가는-탐색">범위를 반씩 좁혀가는 탐색</h2>
<h3 id="1-순차탐색">1. 순차탐색</h3>
<p>리스트 안에 있는 특정한 데이터를 찾기 위해 앞에서부터 데이터를 하나씩 차례대로 확인하는 방법</p>
<pre><code class="language-c">#include &lt;bits/stdc++.h&gt;

using namespace std;

// 순차 탐색 소스코드 구현
int sequantialSearch(int n, string target, vector&lt;string&gt; arr) {
    // 각 원소를 하나씩 확인하며
    for (int i = 0; i &lt; n; i++) {
        // 현재의 원소가 찾고자 하는 원소와 동일한 경우
        if (arr[i] == target) {
            return i + 1; // 현재의 위치 반환 (인덱스는 0부터 시작하므로 1 더하기)
        }
    }
    return -1; // 원소를 찾지 못한 경우 -1 반환
}

int n; // 원소의 개수
string target; // 찾고자 하는 문자열
vector&lt;string&gt; arr;

int main(void) {
    cout &lt;&lt; &quot;생성할 원소 개수를 입력한 다음 한 칸 띄고 찾을 문자열을 입력하세요.&quot; &lt;&lt; &#39;\n&#39;;
    cin &gt;&gt; n &gt;&gt; target;

    cout &lt;&lt; &quot;앞서 적은 원소 개수만큼 문자열을 입력하세요. 구분은 띄어쓰기 한 칸으로 합니다.&quot; &lt;&lt; &#39;\n&#39;;
    for (int i = 0; i &lt; n; i++) {
        string x;
        cin &gt;&gt; x;
        arr.push_back(x);
    }

    // 순차 탐색 수행 결과 출력
    cout &lt;&lt; sequantialSearch(n, target, arr) &lt;&lt; &#39;\n&#39;;
}
</code></pre>
<p>순차탐색은 데이터 정렬 여부와 상관없이 가장 앞에 있는 원소부터 하나씩 확인해야 한다는 점이 특징이다.</p>
<p>따라서 데이터의 개수가 N개일 때 최대 N번의 비교 연산이 필요하므로 순차탐색의 최악의 경우 시간 복잡도는 <strong>O(N)</strong>이다.</p>
<h3 id="2-이진탐색">2. 이진탐색</h3>
<p>이진탐색(Binary Search)은 배열 내부의 데이터가 정렬되어 있어야만 사용할 수 있는 알고리즘</p>
<ul>
<li><p>데이터가 무작위일 때는 사용할 수 없지만, 이미 정렬되어 있다면 매우 빠르게 데이터를 찾을 수 있다는 특징이 있다.</p>
</li>
<li><p>탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 특징이 있다.</p>
</li>
<li><p>위치를 나타내는 변수 3개 : 시작점, 끝점, 중간점</p>
</li>
</ul>
<p>찾으려는 데이터와 중간점 위치에 있는 데이터를 반복적으로 비교해서 원하는 데이터를 찾는다</p>
<p><img src="https://images.velog.io/images/mar_f/post/f06ef32e-3ebd-4bd1-b009-967dd1361090/image-20211116010533971.png" alt=""></p>
<p>전체 데이터의 개수는 16개지만, 이진 탐색을 이용해 총 4번의 탐색으로 원소를 찾을 수 있었다.</p>
<p>이진탐색은 한 번 확인할 때마다 확인하는 원소의 개수가 절반씩 줄어든다는 점에서 시간복잡도가 O(logN)이다.</p>
<p>절반씩 데이터를 줄어들도록 만든다는 점은 다른 퀵정렬과 공통점이 있다.</p>
<h4 id="재귀함수-이용">재귀함수 이용</h4>
<pre><code class="language-c">#include &lt;bits/stdc++.h&gt;

using namespace std;

// 이진 탐색 소스코드 구현(재귀 함수)
int binarySearch(vector&lt;int&gt;&amp; arr, int target, int start, int end) {
    if (start &gt; end) return -1;
    int mid = (start + end) / 2;
    // 찾은 경우 중간점 인덱스 반환
    if (arr[mid] == target) return mid;
    // 중간점의 값보다 찾고자 하는 값이 작은 경우 왼쪽 확인
    else if (arr[mid] &gt; target) return binarySearch(arr, target, start, mid - 1);
    // 중간점의 값보다 찾고자 하는 값이 큰 경우 오른쪽 확인
    else return binarySearch(arr, target, mid + 1, end);
}

int n, target;
vector&lt;int&gt; arr;

int main(void) {
    // n(원소의 개수)와 target(찾고자 하는 값)을 입력받기 
    cin &gt;&gt; n &gt;&gt; target;
    // 전체 원소 입력받기 
    for (int i = 0; i &lt; n; i++) {
        int x;
        cin &gt;&gt; x;
        arr.push_back(x);
    }
    // 이진 탐색 수행 결과 출력 
    int result = binarySearch(arr, target, 0, n - 1);
    if (result == -1) {
        cout &lt;&lt; &quot;원소가 존재하지 않습니다.&quot; &lt;&lt; &#39;\n&#39;;
    }
    else {
        cout &lt;&lt; result + 1 &lt;&lt; &#39;\n&#39;;
    }
}</code></pre>
<h4 id="반복문-이용">반복문 이용</h4>
<pre><code class="language-c">#include &lt;bits/stdc++.h&gt;

using namespace std;

// 이진 탐색 소스코드 구현(반복문)
int binarySearch(vector&lt;int&gt;&amp; arr, int target, int start, int end) {
    while (start &lt;= end) {
        int mid = (start + end) / 2;
        // 찾은 경우 중간점 인덱스 반환
        if (arr[mid] == target) return mid;
        // 중간점의 값보다 찾고자 하는 값이 작은 경우 왼쪽 확인
        else if (arr[mid] &gt; target) end = mid - 1;
        // 중간점의 값보다 찾고자 하는 값이 큰 경우 오른쪽 확인
        else start = mid + 1; 
    }
    return -1;
}

int n, target;
vector&lt;int&gt; arr;

int main(void) {
    // n(원소의 개수)와 target(찾고자 하는 값)을 입력 받기 
    cin &gt;&gt; n &gt;&gt; target;
    // 전체 원소 입력 받기 
    for (int i = 0; i &lt; n; i++) {
        int x;
        cin &gt;&gt; x;
        arr.push_back(x);
    }
    // 이진 탐색 수행 결과 출력 
    int result = binarySearch(arr, target, 0, n - 1);
    if (result == -1) {
        cout &lt;&lt; &quot;원소가 존재하지 않습니다.&quot; &lt;&lt; &#39;\n&#39;;
    }
    else {
        cout &lt;&lt; result + 1 &lt;&lt; &#39;\n&#39;;
    }
}</code></pre>
<h2 id="코딩-테스트에서의-이진탐색">코딩 테스트에서의 이진탐색</h2>
<p>이진탐색 코드는 가급적이면 외우는 걸 권장한다.</p>
<p>이진탐색의 원리는 다른 알고리즘에서도 폭넓게 적용되는 원리와 유사하기 때문에 매우 중요하다.</p>
<p>또, 높은 난이도의 문제에서는 이진 탐색 알고리즘이 다른 알고리즘과 함께 사용되기도 한다.</p>
<p>더불어 코딩테스트의 이진탐색문제는 탐색 범위가 큰 상황에서의 탐색을 가정하는 문제가 많다.</p>
<p>따라서 <strong>2000만</strong>을 넘어가면 이진 탐색으로 문제에 접근해보길 권한다.</p>
<p>처리해야 할 데이터의 개수나 값이 <strong>1000만 단위 이상</strong>으로 넘어가면 이진탐색과 같이 <strong>O(logN)</strong>의 속도를 내야하는 알고리즘을 떠올려야 문제가 풀린다!!</p>
<h3 id="트리-자료구조">트리 자료구조</h3>
<p>이진 탐색은 전제 조건이 데이터 정렬이다.</p>
<p>데이터베이스는 내부적으로 대용량 데이터 처리에 적합한 트리 자료구조를 이용하여 항상 데이터가 정렬되어 있다.</p>
<p>따라서 데이터베이스에서의 탐색은 이진 탐색과는 조금 다르지만, 이진 탐색과 유사한 방법을 이용해 항상 빠르게 수행하도록 설계되어 있어서 데이터가 많아도 탐색하는 속도가 빠르다.</p>
<h4 id="특징">특징</h4>
<ul>
<li>트리는 부모노드와 자식노드의 관계로 표현한다.</li>
<li>트리의 최상단 노드를 루트 노드라고 한다.</li>
<li>트리의 최하단 노드를 단말 노드라고 한다.</li>
<li>트리에서 일부를 떼어내도 트리 구조이며 이를 서브 트리라 한다.</li>
<li>트리는 파일 시스템과 같이 계층적이고 정렬된 데이터를 다루기에 적합하다.</li>
</ul>
<p>큰 데이터를 처리하는 소프트웨어는 대부분 데이터를 트리 자료구조로 저장해서 이진 탐색과 같은 탐색 기법을 이용해 빠르게 탐색이 가능하다.</p>
<p>그렇다면 이런 트리 구조를 이용하면 정확히 어떤 방식으로 항상 이진 탐색이 가능할 걸까?</p>
<h3 id="이진-탐색-트리">이진 탐색 트리</h3>
<p>이진탐색이 동작할 수 있도록 고안된, 효율적인 탐색이 가능한 자료구조이다.</p>
<h4 id="특징-1">특징</h4>
<ul>
<li><p>부모 노드보다 왼쪽 자식 노드가 작다.</p>
</li>
<li><p>부모 노드보다 오른쪽 자식 노드가 크다.</p>
</li>
</ul>
<p><strong>왼쪽 자식 노드 &lt; 부모 노드 &lt; 오른쪽 자식 노드</strong></p>
<p><img src="https://images.velog.io/images/mar_f/post/d7f701bf-b83d-4d38-aa30-452ab096cb2d/image-20211116014349005.png" alt=""></p>
<p><em>참고자료 : 이것이 코딩테스트다 (저자 : 나동빈)</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] 자료구조란 ?]]></title>
            <link>https://velog.io/@mar_f/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EB%9E%80</link>
            <guid>https://velog.io/@mar_f/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EB%9E%80</guid>
            <pubDate>Sun, 17 Jan 2021 10:31:00 GMT</pubDate>
            <description><![CDATA[<h3 id="1-자료구조-data-structure">1. 자료구조 (data structure)</h3>
<blockquote>
<p>자료구조는 컴퓨터 과학에서 자료의 효율적인 접근 및 수정을 할 수 있도록 컴퓨터에 자료를 조직, 관리, 저장하는 방법이다. 더 정확히 말해, 자료구조는 데이터 값의 모임, 또 데이터 간의 관계, 그리고 데이터에 적용할 수 있는 함수나 명령을 의미한다. 신중히 선택한 자료구조는 보다 효율적인 알고리즘을 사용할 수 있게 한다.</p>
<p><a href="%EC%B6%9C%EC%B2%98">https://ko.wikipedia.org/wiki/%EC%9E%90%EB%A3%8C_%EA%B5%AC%EC%A1%B0</a></p>
</blockquote>
<h3 id="2-분류">2. 분류</h3>
<p><img src="https://images.velog.io/images/mar_f/post/5a1591f9-b2a6-4ee9-a710-f18ef102a891/image-20210117185326497.png" alt=""></p>
<ul>
<li><h4 id="단순구조simple-structure">단순구조(Simple Structure)</h4>
<p>자료값을 사용하기 위해서 True/False, 정수, 실수, 문자 및 문자열과 같이 컴퓨터가 기본적으로 제공하는 자료형</p>
</li>
<li><h4 id="선형구조linear-structure">선형구조(Linear Structure)</h4>
<p>자료를 구성하는 데이터를 순차적으로 나열시킨 형태</p>
<p>자료들간의 관계가 1:1인 자료</p>
</li>
<li><h4 id="비선형구조nonlinear-structure">비선형구조(Nonlinear Structure)</h4>
<p>하나의 자료 뒤에 여러개의 자료가 존재할 수 있는 것을 의미</p>
<p>계층구조나 망구조를 갖는 자료구조로서 트리(Tree)와 그래프(Graph)가 있다.</p>
</li>
<li><h4 id="파일구조file-structure">파일구조(File Structure)</h4>
<p>서로 관련있는 필드(Field)로 구성된 레코드(record) 집합인 파일에 대한 자료구조로 보조 기억장치에 데이터가 실제로 기록되는 형태</p>
<p>메모리에 한번에 올릴 수 없는 대용량을 다룬다.</p>
<p>순차적 파일구조(sequential file structure), 색인 파일구조(indexed sequential file structure), 직접파일(direct file) 등이 있다.</p>
</li>
</ul>
<h3 id="3-추가">3. 추가</h3>
<ul>
<li><h4 id="추상적-자료형">추상적 자료형</h4>
<p>자료 자체의 형태, 그 자료의 연산을 수학적으로만 정의한 것.</p>
<p>Ex ) 스택 -&gt; 추상적 자료형에서는 pop, push, empty, size 연산 정도를 정의할 수 있다. 하지만 스택이 내부적으로 배열인지 연결리스트로 구현되는지와 같은 세부적인 형태는 추상적 자료형에서 다루지 않음</p>
<ul>
<li><p>예) 집합, 리스트, 스택, 큐, 트리</p>
</li>
<li><p>자료구조와 차이점 </p>
<p>조금이라도 구현방법이 있다면 자료구조 !!</p>
<p>스택, 큐 -&gt; 추상적 자료형</p>
<p>콜 스택, 배열, 연결리스트 -&gt; 자료구조</p>
<p>추상적 자료형과 자료구조가 같은 이름을 갖는 경우가 많아서 헷갈릴수도 ...</p>
</li>
</ul>
<p>따라서 자료구조는 <strong>추상적 자료형이 정의한 연산들을 구현한 구현체</strong>이다.</p>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>