<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yj-leee.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 13 Aug 2022 07:57:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yj-leee.log</title>
            <url>https://images.velog.io/images/yj-leee/profile/5efd69b5-f0cd-444d-92e1-f8b3de7c1f8e/cat.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yj-leee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yj-leee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[한읽컴구프 - (1)]]></title>
            <link>https://velog.io/@yj-leee/%ED%95%9C%EA%B6%8C%EC%9C%BC%EB%A1%9C-%EC%9D%BD%EB%8A%94-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EC%99%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@yj-leee/%ED%95%9C%EA%B6%8C%EC%9C%BC%EB%A1%9C-%EC%9D%BD%EB%8A%94-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EC%99%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Sat, 13 Aug 2022 07:57:35 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>컴퓨터에 대해 모르고 컴퓨터 프로그래밍을 하는것이 왜 문제인지?</p>
</blockquote>
<p>앞으로는 컴퓨터가 들어있지 않은 물건을 찾기가 어려운 시대가 올 것이다. 수많은 하는 일을 컴퓨터가 수없이 많고 수없이 많은 컴퓨터 프로그램이 있으며 컴퓨터가 온갖 곳에 쓰이기 때문에 애니메이션,웹 페이지, 모바일 폰 앱, 공장 제어, 의료 기기등 많은 분야에 영향을 주게 될 것이다. 그리고 각 분야의 프로그래밍 전문가가 되는 것은 의학에 대한 전문가와는 달리 컴퓨터에 대한 기본 지식 없이도 전문가가 될 수 있다는 것은 보안 취약점 보고서나 제품 리콜 등에서 볼 수 있다. 또한 엄청난 데이터를 다루는데에 이 데이터를 전혀 이해하지 못한다면 어떤 일이 벌어질까? 사람의 생명에 영향이 있는 경우라면 더더욱 문제는 커질것이다. </p>
<blockquote>
<p>간단한 코딩으로 그저 돌아가기만한 프로그램은 좋은 프로그램이거나 신뢰 할만한 프로그램인 것이 아니기 때문에 &#39;컴퓨팅 사고&#39;를 갖춰야 한다.</p>
</blockquote>
<p>누구나 코딩을 배우는것은 이론적으로 멋진 이야기지만, 실제로 모두가 좋은 프로그래머가 되기에 적합한 태도를 갖추게 되는것은 아니다.이것은 훌륭한 프로그래머를 낳는게 아니라 질 낮은 프로그래머를 회사에 많이 공급함으로써 프로그래머의 급여 수준을 낮추고 이를 통해 소프트웨어 회사의 이익을 증가시키는 것이다. 이것을 추구하는 사람들은 코드 품질에는 그다지 신경쓰지 않는다. </p>
<p>매스매티카와 울프람 언어를 만든 스티븐 울프람의 &#39;어떻게 컴퓨팅 사고를 가르칠까?&#39;라는 글에서 울프람은 컴퓨팅 사고를 &#39;컴퓨터가 할 일을 지시하기 위해 충분히 명확하게 시스템적으로 사물을 수식화하는 방법&#39; 정의했다. </p>
<p>C 언어는 메모리 자동 관리가 없었고, 메모리 관련 오류는 당시 프로그래머에게 자주 두통을 일으키게 하는 오류였다. 자바는 언어 설계를 통해 이런 오류를 없앴다. 자바는 메모리 관리를 프로그래머가 볼 수 없게 감췄다. 하부 기술을 잘 이해하면 무엇이 잘못되고 있는지 알아채는 능력을 계발할 수 있다. </p>
<blockquote>
<p>발전하려면 역사를 배워야 한다.</p>
</blockquote>
<p>역사의 분량은 많다. 이로 인해 수많은 사람이 이미 누군가 저지른 실수를 똑같이 반복한다. 역사를 알면 최소한 과거의 실수를 반복하지 않고 더 나은 실수를 할 수 있다. 오늘날 자신이 사용하고 있는 인기있는 기술이 금방 과거의 기술이 된다는 사실을 기억하라.</p>
<p>흥미진진한 기술과 그것을 발견한 사람들에 대해 배우기 위해 시간을 보내라. 흥미로운 문제를 최소한 한가지 이상 해결한 사람들이 세계를 어떻게 인식했고 문제를 해결하기 위해 어떤 접근을 했는지 배울만한 가치가 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nullish coalescing operator]]></title>
            <link>https://velog.io/@yj-leee/Nullish-coalescing-operator</link>
            <guid>https://velog.io/@yj-leee/Nullish-coalescing-operator</guid>
            <pubDate>Sat, 13 Aug 2022 07:10:29 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>null 병합 연산자 </p>
</blockquote>
<p>왼편의 값이 <code>null</code>이나 <code>undefined</code>인지 확인하고 연산자 오른편의 값이 리턴됨</p>
<pre><code class="language-javascript">const example1 = null ?? &#39;A&#39;; // A
const example2 = undefined ?? &#39;B&#39;; // B
const example3 = &#39;C&#39; ?? &#39;D&#39;; // C

console.log(example1, example2, example3); // ABC</code></pre>
<blockquote>
<p>OR 연산자와의 차이점</p>
</blockquote>
<p><code>OR</code> 연산자<code>(||)</code>는 왼편의 값이 <code>falsy</code>인지를 확인</p>
<pre><code class="language-javascript">const example1 = 0 || A;
const example1 = 0 ?? B;

console.log(example1); // A
console.log(example1); // 0</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[boolean]]></title>
            <link>https://velog.io/@yj-leee/boolean</link>
            <guid>https://velog.io/@yj-leee/boolean</guid>
            <pubDate>Thu, 28 Jul 2022 13:19:44 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>javascript 에서 false 인 값</p>
</blockquote>
<p><code>false</code>
<code>null</code>
<code>undefined</code>
<code>naN</code>
<code>0</code></p>
<blockquote>
<p>javascript 에서 true 인 값</p>
</blockquote>
<p>빈 배열 <code>[]</code>
빈 객체 <code>{}</code></p>
<blockquote>
<p>오류 예시</p>
</blockquote>
<p><code>order</code>가 최대 순서값 이상 들어왔을 때 <code>exception</code> 처리를 해야 할 일이 있었다.
비즈니스 규칙으로 최대 수가 정해져 있다면 비즈니스 로직이 정의되어 있는 부분에서 규칙이 정의되어 있는게 바람직하다. 
현재는 예측할 수 있는 해당 메소드를 확인하는 경우는 최대 2가지 경우였다. 그런데 이 메소드를 호출해서 사용하는 경우가 더 있을 수 있다면 메소드를 호출해서 사용하는 모든 클라이언트에서 각각 처리해주는 것보다는
메소드 안에서 규칙을 정의하고 일괄적으로 처리해주는것이 효율적이기 때문에 
<code>validateOrder</code> 메소드를 통해 <code>order</code> 값이 최대 값인지 확인해야 했다.
<code>order</code> 가 0, 1, 2, 3 이런식이여서 0 일때 <code>false</code>가 되기 때문에 <code>null</code> 인지 확인하도록 변경했다.</p>
<p>변경 전</p>
<pre><code class="language-javascript">function validateOrder(): boolean {
    return Boolean(this.order);</code></pre>
<p>변경 후 </p>
<pre><code class="language-javascript">function validateOrder(): boolean {
    return this.order === null ? false : true;
  }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[typeof]]></title>
            <link>https://velog.io/@yj-leee/typeof</link>
            <guid>https://velog.io/@yj-leee/typeof</guid>
            <pubDate>Thu, 21 Jul 2022 13:21:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>javascript 의 type of </p>
</blockquote>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/typeof" title="typeof">typeof</a></p>
<blockquote>
<p>javascript의 type</p>
</blockquote>
<p><code>number</code>, <code>string</code>, <code>boolean</code>, <code>null</code>, <code>undefined</code>, <code>object</code>, <code>symbol</code>, <code>bigint</code></p>
<blockquote>
<p>typeof null 은?? </p>
</blockquote>
<p>[typeof null]
(<a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/typeof#null">https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/typeof#null</a> &quot;typeof#null&quot;)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[modern javascript]]></title>
            <link>https://velog.io/@yj-leee/modern-javascript</link>
            <guid>https://velog.io/@yj-leee/modern-javascript</guid>
            <pubDate>Thu, 14 Jul 2022 04:49:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>모던 자바 스크립트란?</p>
</blockquote>
<p>현 시점에 사용하기 적합한 범위 내에서 
최신 버전의 표준을 준수하는 자바스크립트</p>
<ul>
<li>자바스크립트의 기본 개념을 더 견고히 다지기</li>
<li>새로운 문법들 중 유용한 문법을을 알아보기</li>
</ul>
<blockquote>
<p>ES6+</p>
</blockquote>
<p><a href="https://www.ecma-international.org/publications-and-standards/standards/ecma-262/" title="ECMA-International 공식 ECMA-262문서">ECMA-International 공식 ECMA-262문서</a>
<a href="http://kangax.github.io/compat-table/es6/" title="한눈에 확인하는 호환성 테이블">한눈에 확인하는 호환성 테이블</a>
<a href="https://caniuse.com/" title="문법 검색으로 확인하는 호환성 테이블">문법 검색으로 확인하는 호환성 테이블</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[도메인 주도 설계 핵심] -DDD 알아보기]]></title>
            <link>https://velog.io/@yj-leee/%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%A3%BC%EB%8F%84-%EC%84%A4%EA%B3%84-%ED%95%B5%EC%8B%AC-DDD-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@yj-leee/%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%A3%BC%EB%8F%84-%EC%84%A4%EA%B3%84-%ED%95%B5%EC%8B%AC-DDD-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Thu, 31 Mar 2022 13:00:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>책에 나오는 keyword</p>
</blockquote>
<p>여기 읽어도 무슨말인지 절대 알수가 없는 키워드들이 있다.
1.전략적 설계
2.전술적 설계
3.보편언어
4.컨텍스트
5.컨텍스트 매핑
6.바운디드 컨텍스트
7.도메인 이벤트
8.에그리게잇
9.이벤트스토밍</p>
<blockquote>
<p>고통을 줄이기 위해서</p>
</blockquote>
<p>이 책의 저자가 영업을 잘한다.</p>
<ol>
<li>개발자는 이미 프로젝트의 복잡성을 경험하고 있을 것이다.</li>
<li>비즈니스 문제부터 기술적인 내용까지 다양한 프로젝트의 문제성은
곧 나쁜 설계로 이어진다.</li>
<li>효과적인 설계, DDD가 도와준다.</li>
</ol>
<blockquote>
<p>전략적 설계란</p>
</blockquote>
<p>비즈니스상 전략적으로 중요한것, 중요도에 따라 일을 분리/통합하는 방법</p>
<p><strong>바운디드 컨텍스트</strong>라는 전략적 설계 패턴을 사용해서 도메인을 분리한다.
<strong>보편언어</strong>를 개발한다.
<strong>서브도메인</strong>으로 복잡성을 다룰 수 있게 도와준다.
<strong>컨텍스트 매핑</strong>으로 <strong>바운디드 컨텍스트</strong>를 통합한다.</p>
<blockquote>
<p>전술적 설계란</p>
</blockquote>
<p><strong>엔터티</strong>와 값 <strong>객체</strong>를 통합하는 <strong>에그리게잇 패턴</strong>을 사용한다.
<strong>도메인 이벤트</strong>의 사용으로 명확하게 모델링한다.
바운디드 컨텍스트를 공유한다.</p>
<blockquote>
<p>전략적 설계에서 나온 용어 풀이</p>
</blockquote>
<p><strong>바운디드 컨텍스트</strong>
그 범주 내에서 소프트웨어 모델의 각 컴포넌트가 특정한 의미를 갖고, 
특정한 일을 수행한다는 뜻이다.
바운디드 컨텍스트는 단일 팀에만 할당 되어야 하고,
각 바운디드 컨텍스트마다 독립적인 코드 레파지토리가 있어야 한다.</p>
<p><strong>보편언어</strong>
바운디드 컨텍스트 안에서 일하는 팀이
생성하고, 그 안에서 기능하는 소프트웨어 모델을 만드는 모든 팀 구성원이 사용하는 언어를 반영한다.
팀 구성원들이 이야기 할 때 사용된다.
다수의 팀이 하나의 바운디드 컨텍스트를 수행할 수는 없으므로 보편언어는 팀 내에서만 사용되는 것이다.</p>
<p><strong>핵심도메인과 서브도메인</strong>
조직이 모든것에 뛰어날 수는 없고 그렇게 만들려고 해서도 안된다.
기업의 올바른 전략적 결정을 위해 무엇이 핵심 도메인이어야 하고,
어떤것을 제외해야 하는지 현명하게 선택해야 한다.</p>
<p><strong>진흙 덩어리</strong>
결국 전략적 설계는 새로운 소프트웨어 제품이 큰 진흙덩어리가 되는것을 막아준다.
이 덩어리는 시스템의 명확한 경계 없이 여러개의 뒤엉킨 모델들을 담고 있고 다수의 팀이 이 모델을 활용해 일을 하게 된다면 큰 문제가 될 수 있다.
서로 관련이 없는 다양한 개념이 수많은 모듈로 확장되거나 어울리지 않는 모듈을 상호 연계시킬 수도 있다.
이런 경우에 프로젝트에서 테스트를 수행하는데 오랜 시간이 걸릴 것이다.
진흙덩어리를 피해 바운디드 컨텍스트를 만들고나서 여전히 외부의 큰 진흙덩어리와 통합해야 하는 상황이라면 , 각 레거시 시스템에 대응한 반부패 계층을 만들어서 보호해야한다.</p>
<blockquote>
<p>컨텍스트 매핑부터 좀 어려워지는것 같다. 그만 알아보자~</p>
</blockquote>
<p><strong>반부패계층</strong>
가장 방어적인 컨텍스트 매핑 관계이다.
어떻게 하류 모델과 외부(상류 통합 모델) 사이에서 독립성을 지킬까?
상류 모델로부터 하류 모델을 독립시키고 둘 사이를 번역한다.</p>
<p><strong>컨텍스트 매핑</strong>
파트너십, 고객-공급자, 반부패계층 등 다양한 매핑의 종류가 있다.
RPC, 레스트풀 HTTP, 메시징을 사용</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터 모델]]></title>
            <link>https://velog.io/@yj-leee/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8</link>
            <guid>https://velog.io/@yj-leee/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8</guid>
            <pubDate>Sun, 06 Feb 2022 10:00:00 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>데이터 모델</p>
</blockquote>
<p>데이터 모델이란, 다양한 데이터 요소들을 이해하고 사용하기 편한 형태로 정리해놓은 모형을 의미한다.</p>
<p>우리가 데이터를 저장하려고 하는 대상: Entity(개체)
Entity에 대해서 저장하려고 하는 특징: Attribute(속성)
Entity들 사이 생기는 연결점: Relationship(관계)
여러 데이터 요소들에 있는 규칙: Constraint(제약 조건)</p>
<blockquote>
<p>좋은 데이터베이스란?</p>
</blockquote>
<p>좋은 데이터베이스란 중복되거나 비어있는 데이터는 없고 사용자가 최대한 빠르게 데이터를 다룰 수 있게 해주어 성능이 좋은 데이터베이스를 말한다.
데이터베이스가 이곳저곳에 중복되어 저장되거나 null이 많아서 용량을 차지한다거나 특정 연산들을 실행하는데 너무 오래걸리거나 원하는 데이터를 찾기 어렵다면 나쁜 데이터베이스이다. 데이터베이스 모델링을 어떻게 했느냐에 따라 달라질 수 있다.</p>
<blockquote>
<p>모델링의 시작</p>
</blockquote>
<p>데이터 모델링의 시작은 특정 조직이 운영되기 위해 따라야 하는 정책, 절차, 원칙인 비즈니스 룰에 따라 저장하고 싶은 Entity, Attribute, Relationship 을 파악하는것이다.</p>
<blockquote>
<p>Entity, Relationship, Attribute 찾는법</p>
</blockquote>
<p>모든 명사 Entity 후보이다.
모든 동사는 Relationship 후보이다.
하나의 &quot;값&quot;으로 표현할 수 있는 명사는 attribute의 후보이다.</p>
<blockquote>
<p>이상현상이란?</p>
</blockquote>
<p>주어진 데이터베이스에서 삽입, 업데이트, 삭제를 제대로 할 수 없는 경우를 의미한다.</p>
<p>새로운 데이터를 자연스럽게 추가할 수 없는 경우</p>
<p>데이터를 업데이트 했을 때 정확성을 지키기 어려워지는 경우 </p>
<p>데이터를 삭제할 때 꼭 필요한 데이터까지 연쇄 삭제 해야하는 경우 </p>
<p>-&gt; 데이터 모델링을 제대로 하지 않았기 때문에 발생한다! </p>
<ol>
<li>테이블이 잘 모델링 되었는지 판단하는 방법</li>
<li>잘못 만들었다면 어떻게 고쳐야 할까?</li>
</ol>
<blockquote>
<p>정규화</p>
</blockquote>
<p>테이블이 잘 만들어졌는지 평가하고, 잘 만들지 못한 것을 고쳐나가는 과정
테이블 안에 있는 컬럼이 해당 테이블에 있는게 맞는지 판단해서 옮겨 이상현상을 없앨 수 있다.
새로운 종류의 데이터를 추가할 때 구조 수정을 많이 하지 않아도 된다.
데이터베이스 구조를 단순화해서 사용자가 더욱 쉽게 이해할 수 있다.
데이터베이스는 고치기 어렵기 때문에 반영하기 전에 고치는것이 좋다.</p>
<p>정규형
1NF, 2NF, 3NF </p>
<p>그외 등등
EKNF
BCNF
4NF
ETNF
5NF
DKNF
6NF</p>
<blockquote>
<p>제1정규형 1NF</p>
</blockquote>
<p>한 컬럼에 여러개의 값이 있으면 안된다.
모든 로우들이 나눌 수 없는 단일 값이어야 한다.
여러개의 값을 단일 값으로 넣으려면 컬럼을 여러개로 늘리면 된다고 생각하면 되지만 null이 많아지고 관리가 어려워짐</p>
<blockquote>
<p>제2정규형 2NF</p>
</blockquote>
<p>제1정규형에 부합한다.
하나의 테이블에는 그 목적에 맞는 데이터들이 들어가야 한다.</p>
<p>💡Candidate key
하나의 로우를 특정지을 수 있는 attribute 의 최소 집합을 말한다.
로우를 특정 짓는데 사용되지 않는 attribute는 캔디더트키가 아니게 되는것</p>
<p>💡 함수 종속성이란?
x의 값에 의해서 y의 값이 결정될 때 함수 종속성이 있다고 한다
하나이상의 attribute를 건너 함수 종속성이 있는 경우에 함수 종속성이 넘어갔다, 즉 이행되었다고 한다</p>
<blockquote>
<p>제3정규형 3NF</p>
</blockquote>
<p>제 2 정규형에 부합한다.
테이블 안에 있는 모든 attribute는 오직 프라이머리키에 대해서만 함수종속성이 있어야 한다. 그 외에 어트리뷰트에 대해서는 이행적 종속성이 없어야 한다.
좀 어렵게 들리지만 풀어서 설명하면 테이블의 모든 컬럼들은 직접적으로 테이블 엔티티에 대한 내용이어야만 한다는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 가사 검색]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%80%EC%82%AC-%EA%B2%80%EC%83%89</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%80%EC%82%AC-%EA%B2%80%EC%83%89</guid>
            <pubDate>Thu, 03 Feb 2022 11:48:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>📌 문제</p>
</blockquote>
<p><strong><a href="https://programmers.co.kr/learn/courses/30/lessons/60060,%22%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4%22">가사 검색</a></strong></p>
<blockquote>
<p>📌 문제 해결 hint</p>
</blockquote>
<ol>
<li>각 단어를 길이에 따라 나눈다.</li>
<li>리스트를 정렬한다.</li>
<li>이진탐색으로 시작되는 단어(&quot;fro??&quot; 보다 크거나 같은 단어)의 위치부터
마지막 단어(&quot;frozz&quot;보다 작거나 같은 단어)의 위치의 차이를 계산하여 개수를 구한다.</li>
<li>단어중에 ???로 시작하는 단어가 있어 뒤집은 단어를 담고 있는 리스트를 별도로 만든다.</li>
<li>뒤집힌 단어 리스트를 대상으로 위와 같은 이진 탐색을 수행하면 된다.</li>
</ol>
<blockquote>
<p>📌 bisect 함수란?</p>
</blockquote>
<pre><code class="language-python">from bisect import bisect_right, bisect_left

a = [1,2,3,4,4,8]
x = 4

print(bisect_left(a,x)) 
&gt;&gt; 3
print(bisect_right(a,x)) 
&gt;&gt; 5</code></pre>
<blockquote>
<p>📌 solution</p>
</blockquote>
<pre><code class="language-python">from bisect import bisect_left, bisect_right


def count_by_range(a, left_value, right_value):
    right_value = bisect_right(a, right_value)
    left_value = bisect_left(a, left_value)

    return right_value - left_value


def solution(words, queries):
    answer = []

    # 1. 각각의 리스트를 길이에 따라 나눈다.
    array = [[] for _ in range(10001)]
    reversed_array = [[] for _ in range(10001)]

    for word in words:
        array[len(word)].append(word)
        reversed_array[len(word)].append(word[::-1])

    # 2. 리스트를 정렬한다.

    for i in range(10001):
        array[i].sort()
        reversed_array.sort()

    # 3. 이진탐색으로 시작되는 단어부터 마지막 단어의 위치를 찾고 위치의 차이를 계산

    for query in queries:
        if query[0] != &#39;?&#39;:
            res = count_by_range(array[len(query)], query.replace(&#39;?&#39;, &#39;a&#39;), query.replace(&#39;?&#39;, &#39;z&#39;))
        else:
            res = count_by_range(reversed_array[len(query)], query.replace(&#39;?&#39;, &#39;a&#39;), query.replace(&#39;?&#39;, &#39;z&#39;))

        answer.append(res)

        return answer
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[jquery datatable에서 pagination 도입하기]]></title>
            <link>https://velog.io/@yj-leee/jquery-datatable%EC%97%90%EC%84%9C-pagination-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yj-leee/jquery-datatable%EC%97%90%EC%84%9C-pagination-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 30 Dec 2021 13:35:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>문제 상황</p>
</blockquote>
<ol>
<li>속도 (데이터의 개수가 늘어날수록 속도가 점점 느려지는 현상이 발생하고 있었다)</li>
<li>수정이나 삭제시 현재 페이지를 기억하지 못하고 1페이지로 간다.</li>
</ol>
<blockquote>
<p>원인</p>
</blockquote>
<ol>
<li><p>datatable로 코드가 짜여져 있었는데, 테이블에 있는 모든 데이터를 가져온 후 pageLength의 값을 토대로 나누어서 보여지는 방식이다. 
게다가 500으로 때려박아져 있어서, 한 페이지에 500개씩 보였었다^^;;</p>
</li>
<li><p>위와 같은 이유로 수정이나 삭제 시에도 현재 페이지가 아닌 전체 데이터를 가지고 오고 속도는 점점 더 거북이에 현재 페이지 기억도 못한다~!</p>
</li>
</ol>
<blockquote>
<p>수정 방안</p>
</blockquote>
<ol>
<li>ajax를 이용한 pagination을 구현한다.</li>
</ol>
<pre><code class="language-javascript">        pageLength: 50,
        serverSide: true,
        processing: true</code></pre>
<ol start="2">
<li>위처럼 ajax 요청을 보내면 query에 아래의 값들이 함께 보내진다.<pre><code class="language-javascript">// req.query
const draw = parseInt(req.query.draw)
const offset = parseInt(req.query.start)
const limit = parseInt(req.query.pageSize)</code></pre>
</li>
</ol>
<h3 id="response">response</h3>
<pre><code class="language-javascript">    // return json response
   return res.json({ draw, recordsTotal, recordsFiltered, data });
</code></pre>
<blockquote>
<p>새로고침을 막는 방법 </p>
</blockquote>
<p>-&gt; ajax의 reload 를 false 옵션으로 바꾼다!
<code>table.ajax.reload(null, false)</code></p>
<pre><code class="language-javascript">  if (actions.edit !== undefined) {
    modal.on(&#39;click&#39;, &#39;button#edit&#39;, () =&gt; {

      // 파라미터만 전송시
      if (actions.edit.serialize === &#39;Y&#39;) {
        const data = $(form).serializeArray()
        data.push({ name: &#39;admin_userid&#39;, value: user.userid })
        $.ajax({
          url: actions.edit.url.replace(&#39;:id&#39;, $(&#39;input[name=id]&#39;)[0].value),
          type: actions.edit.type,
          data: data,
          error: (error) =&gt; errorCodeAlert(list, error),
          success: () =&gt; {
            table.ajax.reload(null, false)
            modal.modal(&#39;hide&#39;)
          }
        })
      }</code></pre>
<p>Reference
<a href="https://miyakita.tistory.com/147">https://miyakita.tistory.com/147</a>
<a href="https://zamezzz.tistory.com/310">https://zamezzz.tistory.com/310</a>
<a href="https://programmerpsk.tistory.com/58">https://programmerpsk.tistory.com/58</a> <a href="https://velog.io/@alstjd8826/TIL-jQuery-Bootstrap-Ajax-dataTable-pagination-search-sort">https://velog.io/@alstjd8826/TIL-jQuery-Bootstrap-Ajax-dataTable-pagination-search-sort</a>
<a href="https://sir.kr/qa/370450">https://sir.kr/qa/370450</a>
<a href="https://joyhong.tistory.com/104">https://joyhong.tistory.com/104</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[회고록]]></title>
            <link>https://velog.io/@yj-leee/%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@yj-leee/%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Sun, 26 Dec 2021 04:04:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>2020.08 회고에 이어 취업 후 주니어 개발자로 6개월간의 경험을 회고 한다.</p>
</blockquote>
<h2 id="인턴-스타트업">인턴 (스타트업)</h2>
<p>2020.08 ~ 2020.11 (3개월) </p>
<p>2020년 상반기에 다녔던 회사에 이어 빡센 취업 준비 과정이 있었고 덕분에 좋은 회사에서 인턴을 할 수 있는 기회를 잡을 수 있었다. 스타트업 하면 생각했던 이미지를 전부 다 가지고 있는 회사였다. 빠르게 개발하고 빠르게 결정하고 모든것들이 정신없이 빠르게만 돌아갔다. 하루에도 수십번 방향성이 뒤바뀌기도 하고, 그만큼 회의의 연속이기도 했다. 다들 각자의 생각을 치열하게 주장하고 자신의 주장을 뒷받침하는 논리를 가지고 서로 기분나쁘지 않게 브레인스토밍 하는 모습들도 인상깊었다. 각자의 자리에서 모두 자신의 할일을 묵묵히 해나가는 멋진 사람들도 보면서 나도 의지를 다지곤 했다. </p>
<blockquote>
<p>업무 방식</p>
</blockquote>
<ol>
<li>Jira 티켓을 발급하고 매일 할일을 티켓을 통해 관리했다.</li>
<li>스프린트 기간동안 요구사항이 정리된 문서와 피그마를 통해 개발을 진행했다.</li>
<li>모든 코드에 테스트 코드를 작성했다.</li>
<li>배포 전 stage 서버에서 QA를 진행했다.</li>
</ol>
<blockquote>
<p>내가 얻어간 것</p>
</blockquote>
<p>✍ 테스트 코드 작성
✍ graphQL에 대한 이해
✍ 디자인, 기획, 마케팅과의 협업 경험
✍ 데이터 마이그레이션 경험</p>
<blockquote>
<p>아쉬웠던 점</p>
</blockquote>
<p>🚫 코드리뷰를 잘 하지 못했다.
🚫 동기, 비동기 방식을 어떤 때 적용해야 하는지 알지 못했다.
🚫 쿠버네티스를 경험해보지 못했다.</p>
<h2 id="인턴-스타트업-1">인턴 (스타트업)</h2>
<p>2020.11 ~ 2020.12 (1개월~ 진행중)</p>
<p>첫번째 회사에 대표님이 추천해주신 회사에서 2달동안 인턴 근무를 하게 되었다. python과 java로만 개발을 했었는데 node.js 로 되어있는 회사였지만 또 색다른 경험일것 같았다. 처음 배울때 늘 느끼는거지만 아무리 그래도 javascript는 어렵다.ㅜㅜ 뭔가 조잡스러운 느낌이 쪼금 든다. 하지만 spring 할 때처럼 이것도 하다보면 정들겠지. 아무래도 첫 스타트업을 겪고 스타트업에 대한 이해가 높아졌다고 스스로 생각하던 때라 자신감이 조금 있...었...는데 와엠아크라잉.... </p>
<blockquote>
<p>내가 얻어갈 것</p>
</blockquote>
<p>✍ 테스트 환경 적용
✍ 데이터 모델링, 마이그레이션
✍ javascript, node.js 에 대한 이해
✍ 빠른 기능 개발</p>
<blockquote>
<p>내년에 집중해야할 것</p>
</blockquote>
<ol>
<li>속도</li>
</ol>
<p>시니어 백엔드 개발자분이 새로 오셔서 앞으로 점차 체계적으로 변해갈 것 같다. 변화에 발맞춰 해야할 일을 묵묵히 해 나아가야겠다. 첫 회사에서 얻었던 많은 지식과 체계적인 업무 틀을 가지고 이곳에서는 허둥지둥 하기보다는 좀 더 능숙하게 일을 처리해나갈 수 있을거라고 믿는다.
늘 안정성 있는 코드가 무엇일까, 좋은 코드가 무엇일까 고민하다 보니 고민하는 시간이 너무 길다고 느껴질 때가 있다. 이번년도에는 무엇보다도 &#39;속도&#39;! &#39;빠른 속도&#39;!에 맞춰서 개발하기를 중점을 하기로 했다.</p>
<ol start="2">
<li>node.js 에 익숙해지기</li>
</ol>
<p>python, java를 공부할 때 느끼지 못했던 웹 전반적인 지식이 javascript를 통해서 조금씩 짜맞춰지는 기분이 든다. 첫 회사에서 부족하다고 느꼈던 동기, 비동기에 대한 지식도 보완할 수 있었다. python에서 조금씩 벗어나고 node.js 에 집중해보려고 한다!</p>
<ol start="3">
<li>Best Practices 에 집착하지 않기</li>
</ol>
<p>어떤 기업에서는 최고의 방법이 아닐 수 있다.
내가 작성한 코드의 양에 집중하기 보다는 비지니스 가치를 가질 수 있는 시스템을 만들자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 고정점 찾기]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B3%A0%EC%A0%95%EC%A0%90-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B3%A0%EC%A0%95%EC%A0%90-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Thu, 23 Dec 2021 12:37:28 GMT</pubDate>
            <description><![CDATA[<p><strong>📌 문제</strong>
고정점이란, 수열의 원소 중에서 그 값이 인덱스와 동일한 원소를 의미한다. 예를 들어 수열 a = {-15, -4, 2, 8, 13}이 있을 때 a[2] = 2이므로, 고정점은 2가 된다.</p>
<p>하나의 수열이 N개의 서로 다른 원소를 포함하고 있으며, 모든 원소가 오름차순으로 정렬되어 있다. 이때 이 수열에서 고정점이 있다면, 고정점을 출력하는 프로그램을 작성하라. 만약 고정점이 없다면 -1을 출력한다.</p>
<p>단, 이 문제는 시간 복잡도 O(logN) 으로 알고리즘을 설계하지 않으면 &#39;시간 초과&#39; 판정을 받는다.</p>
<hr>
<p><strong>📌입력 조건</strong>
첫째 줄에 N이 입력된다. (1 ≤ N ≤ 1,000,000)</p>
<p>둘째 줄에 N개의 원소가 정수 형태로 공백으로 구분되어 입력된다.
(-10^9≤각 원소의 값 ≤10^9)</p>
<hr>
<p><strong>📌출력 조건</strong>
고정점을 출력한다. 고정점이 없다면 -1을 출력한다.</p>
<blockquote>
<p>입력
5
-15 -6 1 3 7</p>
<p>출력
3</p>
</blockquote>
<blockquote>
<p>입력
7
-15 -4 2 8 9 13 15</p>
<p>출력
2</p>
</blockquote>
<hr>
<p><strong>📌문제 해결</strong></p>
<ol>
<li>시간 복잡도 O(logN)에 맞게 찾으려면 선형탐색으로 해결할 수 없으므로 이진 탐색으로 문제를 해결한다. </li>
<li>target은 중간지점 Index 와 동일하다 (start + end // 2)</li>
<li>target 보다 array[mid]의 값이 작은 경우 왼쪽 부분이 아닌 오른쪽 부분을 탐색하게 된다.</li>
<li>target보다 반대로 array[mid]의 값이 큰 경우 오른쪽 부분이 아닌 왼쪽 부분을 탐색하게 된다.</li>
</ol>
<pre><code class="language-python">n = int(input())
array = list(map(int, input().split()))


def binary_search(array, start, end):
    if start &gt; end:
        return None
    mid = (start + end) // 2
    # 고정점을 찾은 경우 인덱스 반환
    if array[mid] == mid:
        return mid
    # 중간점이 가리키는 위치의 값보다 작은 경우 왼쪽 확인
    elif array[mid] &gt; mid:
        return binary_search(array, start, mid - 1)
    # 중간점이 가리키는 위치의 값보다 중간점이 큰 경우 오른쪽 확인
    else:
        return binary_search(array, mid + 1, end)


index = binary_search(array, 0, n - 1)

if index == None:
    print(-1)
else:
    print(index)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 정렬된 배열에서 특정수의 개수 구하기]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A0%95%EB%A0%AC%EB%90%9C-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-%ED%8A%B9%EC%A0%95%EC%88%98%EC%9D%98-%EA%B0%9C%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A0%95%EB%A0%AC%EB%90%9C-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-%ED%8A%B9%EC%A0%95%EC%88%98%EC%9D%98-%EA%B0%9C%EC%88%98-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 18 Dec 2021 13:32:58 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p>N개의 원소를 포함하고 있는 수열이 오름차순으로 정렬되어 있습니다. 이때 이 수열에서 x가 등장하는 횟수를 계산하세요. 예를 들어 수열 {1, 1, 2, 2, 2, 2, 3}이 있을 때 x = 2라면, 현재 수열에서 값이 2인 원소가 4개이므로 4를 출력합니다.</p>
<p>단, 이 문제는 시간 복잡도 O(log N)으로 알고리즘을 설계하지 않으면 &#39;시간 초과&#39; 판정을 받습니다.</p>
<hr>
<h3 id="입력-조건">입력 조건</h3>
<ol>
<li><p>첫째 줄에 N과 x가 정수 형태로 공백으로 구분되어 입력됩니다.
(1 ≤ N ≤ 1,000,000), (-10⁹ ≤ x ≤ 10⁹)</p>
</li>
<li><p>둘째 줄에 N개의 원소가 정수 형태로 공백으로 구분되어 입력됩니다.
(-10⁹ ≤ 각 원소의 값 ≤ 10⁹)</p>
</li>
</ol>
<hr>
<h3 id="출력-조건">출력 조건</h3>
<p>수열의 원소 중에서 값이 x인 원소의 개수를 출력합니다. 단, 값이 x인 원소가 하나도 없다면 -1을 출력합니다.</p>
<blockquote>
<p><strong>입력</strong>
7 2
1 1 2 2 2 2 3</p>
<p><strong>출력</strong>
4</p>
</blockquote>
<blockquote>
<p><strong>입력</strong>
7 4
1 1 2 2 2 2 3</p>
<p><strong>출력</strong>
-1</p>
</blockquote>
<hr>
<h3 id="이진-탐색-반으로-쪼개면서-탐색하기">이진 탐색: 반으로 쪼개면서 탐색하기</h3>
<p>이진탐색은 배열 내부의 데이터가 정렬되어 있어야만 사용할 수 있는 알고리즘이다. 
3개의 변수(시작점, 중간점, 끝점)를 사용해 찾으려는 데이터와 중간점 위치에 있는 데이터를 비교해서 원하는 데이터를 찾는다.
시간복잡도는 확인하는 원소의 개수가 절반씩 줄어든다는 점에서 시간복잡도가 O(log N) 이다.</p>
<hr>
<h3 id="문제해결">문제해결</h3>
<p>처음 등장하는 인덱스와 마지막으로 등장하는 인덱스를 각각 계산한 뒤(이진 탐색 메소드를 이용), 인덱스 차이를 계산한다.</p>
<pre><code class="language-python">n, target = map(int, input().split())
array = list(map(int, input().split()))


def first_search(array, target, start, end):
    if start &gt; end:
        return None

    mid = (start + end) // 2

    if (array[mid] == target) and (mid == 0 or target &gt; array[mid - 1]):
        return mid
    elif array[mid] &gt;= target:
        return first_search(array, target, start, mid - 1)
    else:
        return first_search(array, target, mid + 1, end)


def last_search(array, target, start, end):
    if start &gt; end:
        return None

    mid = (start + end) // 2

    if (array[mid] == target) and (
        (mid == len(array) - 1) or (target &lt; array[mid + 1])
    ):
        return mid
    elif array[mid] &gt; target:
        return first_search(array, target, start, mid - 1)
    else:
        return first_search(array, target, mid + 1, end)


def count_by_value(array, x):
    n = len(array) - 1

    first_index = first_search(array, x, 0, n)

    if first_index == None:
        return 0

    last_index = last_search(array, x, 0, n)

    return last_index - first_index + 1


count = count_by_value(array, target)

if count == 0:
    print(-1)
else:
    print(count)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 카드 정렬하기]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%B9%B4%EB%93%9C-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%B9%B4%EB%93%9C-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 28 Nov 2021 12:01:50 GMT</pubDate>
            <description><![CDATA[<p>[문제] 카드 정렬하기
<a href="https://www.acmicpc.net/problem/1715">https://www.acmicpc.net/problem/1715</a></p>
<blockquote>
<p>heapq 자료구조</p>
</blockquote>
<p>우선순위 큐는 이진트리로 만들어진 자료구조이다.
우선순위 큐를 구현할 때는 내부적으로 최소 힙 혹은 최대 힙을 이용한다.
최소 힙을 이용하는 경우 값이 가장 낮은 데이터가 먼저 삭제되고,
최대 힙을 이용하는 경우 값이 큰 데이터가 먼저 삭제된다.
파이썬 라이브러리는 기본적으로 최소 힙 구조를 이용한다.</p>
<blockquote>
<p>시간 복잡도</p>
</blockquote>
<ol>
<li>리스트: 삽입 시간(O(1)) / 삭제 시간(O(N))</li>
<li>힙: 삽입 시간(O(logN)) / 삭제 시간(O(logN))</li>
</ol>
<blockquote>
<p>문제 해결 hint</p>
</blockquote>
<ol>
<li>항상 가장 작은 크기의 두 카드 묶음을 합쳤을 때가 최적의 해이다.</li>
<li>하나의 카드 묶음이 남을 때까지 가장 작은 두개의 카드 묶음을 계속해서 합쳐 나간다.</li>
<li>합쳐진 두개의 카드 묶음은 다시 삽입한다</li>
</ol>
<pre><code class="language-python">import heapq

n = int(input())

heap = []
for i in range(n):
    data = int(input())
    heapq.heappush(heap, data)

result = 0

while len(heap) != 1:
    one = heapq.heappop(heap)
    two = heapq.heappop(heap)

    sum_value = one + two
    result += sum_value
    heapq.heappush(heap, sum_value)

print(result)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 외벽 점검]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%99%B8%EB%B2%BD-%EC%A0%90%EA%B2%80</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%99%B8%EB%B2%BD-%EC%A0%90%EA%B2%80</guid>
            <pubDate>Sat, 09 Oct 2021 07:09:11 GMT</pubDate>
            <description><![CDATA[<p>[문제] 외벽 점검
<a href="https://programmers.co.kr/learn/courses/30/lessons/60062">https://programmers.co.kr/learn/courses/30/lessons/60062</a></p>
<blockquote>
<p>문제해결 hint</p>
</blockquote>
<ol>
<li>완전 탐색 문제로 모든 친구를 무작위로 나열하는 모든 순열 permutations 를 이용하여 친구를 나열하는 모든 경우의 수를 구한다.</li>
<li>문제에서 취약 지점이 &#39;원형&#39;으로 구성되어 있다고 설명하였다. 원형으로 나열된 데이터는 길이를 2배로 늘려서 원형을 일자 형태로 만들어주는 작업을 해준다.<pre><code class="language-python">weak = [1, 3, 4, 9, 10]    
</code></pre>
</li>
</ol>
<p>length = len(weak)
for i in range(length):
    weak.append(weak[i] + n)</p>
<p>result
weak = [1, 3, 4, 9, 10, 13, 15, 16, 21, 22]</p>
<pre><code>3. 각 친구를 나열하는 모든 경우의 수는 permutations 를 통해 구한다.

```python
for friends in list(permutations(dist, len(dist))):
    print(friends)

result
(3, 5, 7)
(3, 7, 5)
(5, 3, 7)
(5, 7, 3)
(7, 3, 5)
(7, 5, 3)</code></pre><ol start="4">
<li>시작 지점은 모든 취약 지점이 될 수 있으므로 최상위 for문의 횟수는 취약지점의 개수이다. </li>
<li>취약지점으로부터 나열된 친구들(ex (3,5,7))가 이동하는 수만큼 position(친구가 점검할 수 있는 마지막 위치)를 늘려나간다. 예를들어 취약지점이 1이라면 첫번째 친구의 position은 4가 된다.</li>
<li>다음 첫번째 친구의 position이 4라면, 4를 초과하는 취약지점에 도착할 경우 친구를 투입한다.</li>
<li>위 과정을 반복한 후에 투입된 친구를 answer에 저장한다.</li>
<li>나열된 친구들(3,5,7)의 시작 취약 지점을 늘리고 위 과정을 반복하여 투입된 친구를 계속해서 확인한다. </li>
<li>최소 투입 친구가 확인되면 다음으로 나열된 친구 목록을 변경하고 위 과정을 반복한다(ex) 3,7,5)</li>
<li>answer가 문제에서 투입된 친구보다 넘었을 때에는 -1 을 리턴한다.</li>
</ol>
<pre><code class="language-python">from itertools import permutations

n = 12
weak = [1, 3, 4, 9, 10]
dist = [3, 5, 7]


def solution(n, weak, dist):

    length = len(weak)
    for i in range(length):
        weak.append(weak[i] + n)

    # 투입할  친구  수  초기화
    answer = len(dist) + 1

    # 0부터 length - 1 까지의 위치(취약지점)를 각각 시작점으로 설정
    for start in range(length):
        for friends in list(permutations(dist, len(dist))):
            # 투입할 친구의 수
            count = 1
            position = weak[start] + friends[count - 1]
            # 시작지점부터 모든 취약지점을 확인
            for index in range(start, start + length):
                # 점검할 수 있는 위치를 벗어나는 경우
                if position &lt; weak[index]:
                    # 새로운 친구를 투입
                    count += 1
                # 더 투입이 불가능하다면 종료
                if count &gt; len(dist):
                    break
                position = weak[index] + friends[count - 1]
            # 최소값 계산
            answer = min(answer, count)
        if answer &gt; len(dist):
            return -1
        return answer


solution(n, weak, dist)
</code></pre>
<p>참고 [순열과 조합 - combinations, permutations]
<a href="https://programmers.co.kr/learn/courses/4008/lessons/12836">https://programmers.co.kr/learn/courses/4008/lessons/12836</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 치킨배달]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%B9%98%ED%82%A8%EB%B0%B0%EB%8B%AC</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%B9%98%ED%82%A8%EB%B0%B0%EB%8B%AC</guid>
            <pubDate>Sun, 03 Oct 2021 14:26:57 GMT</pubDate>
            <description><![CDATA[<p>[문제] 치킨배달
<a href="https://www.acmicpc.net/problem/15686">https://www.acmicpc.net/problem/15686</a></p>
<blockquote>
<p>문제해결 hint</p>
</blockquote>
<p>1)완전 탐색 문제로 파이썬 조합인 combinations을 사용하여 m개의 조합을 구한다.
2)치킨거리를 모두 계산하고 최소값을 구해 출력한다.</p>
<pre><code class="language-python">from itertools import combinations

n, m = 5, 3
chicken, house = [], []


for r in range(n):
    data = list(map(int, input().split()))
    for c in range(n):
        if data[c] == 1:
            house.append(r, c)
        if data[c] == 2:
            chicken.append(r, c)

# 모든 치킨집 중에서 m개의 치킨집을 뽑는 조합 계산
candidates = list(combinations(chicken, m))


# 치킨 거리의 합을 계산하는 함수
def get_sum(candidate):
    result = 0
    # 모든 집에 대하여
    for hx, hy in house:
        temp = 1e9
        for cx, cy in candidate:
            temp = min(temp, abs(hx - cx) + abs(hy - cy))
            # 가장 가까운 치킨집까지의 거리를 더하기
        result += temp
    return result


# 치킨거리의 합의 최소를 찾아 출력
result = 1e9
for candidate in candidates:
    result = min(result, get_sum(candidate))

print(result)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 기둥과 보 설치]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B8%B0%EB%91%A5%EA%B3%BC-%EB%B3%B4-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B8%B0%EB%91%A5%EA%B3%BC-%EB%B3%B4-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Sun, 26 Sep 2021 06:42:48 GMT</pubDate>
            <description><![CDATA[<p>[문제] 기둥과 보 설치
<a href="https://programmers.co.kr/learn/courses/30/lessons/60061?language=python3">https://programmers.co.kr/learn/courses/30/lessons/60061?language=python3</a></p>
<blockquote>
<p>문제해결 hint</p>
</blockquote>
<ol>
<li>기둥 또는 보를 설치할 때 가능한 구조물인지 확인하는 함수를 작성한다.</li>
<li>설치 후 설치된 것이 기둥인지 보인지 확인한다.</li>
<li>설치된 것이 기둥인 경우 기둥 설치가 가능한 모든 조건을 확인 후 설치가 가능한 조건이면 정상이다.</li>
<li>문제에 따르면 기둥이 설치될 수 있는 경우는 4가지 경우이다.
1) 맨 밑에 있는 경우
2) 설치 아래 지점에 기둥이 있는 경우
3) 설치 왼쪽 지점에 보가 있는 경우
4) 설치 지점에 보가 있는 경우</li>
<li>설치된 것이 보인 경우 보 설치가 가능한 모든 조건을 확인 후 설치가 가능한 조건이면 정상이다.
1) 설치 아래 지점에 기둥이 있는 경우
2) 설치 아래 오른쪽 지점에 기둥이 있는 경우
3) 양 옆에 보가 있는 경우</li>
<li>위의 조건들에 해당하지 않는 경우 기둥 또는 보가 설치될 수 없으므로 false를 반환한다.</li>
</ol>
<pre><code class="language-python"># 현재 설치된 구조물이 가능한 구조물인지 확인하는 함수
def possible(answer):
    &quot;&quot;&quot;
    x: 가로 좌표
    y: 세로 좌표
    stuff: 기둥 또는 보
    &quot;&quot;&quot;
    for x, y, stuff in answer:
        # 설치된 것이 기둥인 경우
        if stuff == 0:
            # 바닥 위, 설치 지점에 보가 있는 경우, 설치 왼쪽 지점에 보가 있는 경우, 설치 아래 지점에 기둥이 있는 경우
            if (y == 0) or ([x, y, 1] in answer) or [x - 1, y, 1] in answer or [x, y -1, 0] in answer:
                continue
            return False
        # 설치된 것이 보인 경우
        elif stuff == 1:
            # 한쪽 끝부분이 기둥 위인 경우, 양 옆에 보가 있는 경우
            if ([x, y - 1, 0] in answer) or ([x + 1, y, 0] in answer) or ([x - 1, y, 1] in answer):
                continue
            return False
        return True

def solution(n, build_frame):
    answer = []
    for frame in build_frame:
        x, y, stuff, operate = frame
        if operate == 0:
            answer.remove([x, y, stuff])
            if not possible(answer):
                answer.append([x, y, stuff])
        if operate == 1:
            answer.append([x, y, stuff])
            if not possible(answer):
                answer.remove([x, y, stuff])
    return sorted(answer)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 뱀]]></title>
            <link>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B1%80</link>
            <guid>https://velog.io/@yj-leee/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B1%80</guid>
            <pubDate>Sat, 25 Sep 2021 06:43:59 GMT</pubDate>
            <description><![CDATA[<p>[문제] 백준 뱀 
<a href="https://www.acmicpc.net/problem/3190">https://www.acmicpc.net/problem/3190</a></p>
<blockquote>
<p>문제해결 hint</p>
</blockquote>
<ol>
<li>2차원 배열을 만들고, 0으로 초기화 한다.</li>
<li>사과의 위치에 1을 저장한다.</li>
<li>(0,0)에서 뱀은 시작하고, 뱀이 지나가는 곳은 2로 바꾼다.</li>
<li>방향의 변화가 생겼는지 체크한다.</li>
<li>뱀의 머리가 사과가 없는 위치로 가면 꼬리의 값을 0으로 수정한다.</li>
<li>뱀의 머리가 사과가 있는 위치로 가면 꼬리의 값을 수정하지 않는다.</li>
<li>벽 또는 자기자신의 몸에 부딪힐 때까지 반복한다.</li>
</ol>
<pre><code class="language-python">n = int(input())
k = int(input())
# 맵 정보
data = [[0] * (n + 1) for _ in range(n + 1)]

# 사과가 있는곳은 1로 표시
for _ in range(k):
    a, b = map(int, input().splint())
    data[a][b] = 1

# 방향 정보
info = []

# 방향 회전 정보 입력
l = int(input())
for _ in range(l):
    x, c = input().split()
    info.append((int(x), c))


def turn(direction, c):
    &quot;&quot;&quot;
    방향 회전 함수
    &quot;&quot;&quot;
    if c == &quot;L&quot;:
        direction = (direction - 1) % 4
    else:
        direction = (direction + 1) % 4
    return direction


# 초기 뱀은 동쪽을 보고 있으므로, 동, 남, 서, 북 순서
dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]


def simulate():
    # 뱀의 머리 위치
    x, y = 1, 1
    # 뱀이 존재하는 위치는 2로 표시
    data[x][y] = 2
    # 처음 동쪽을 보고 있음
    direction = 0
    # 시작한 뒤에 지난 초
    time = 0
    # 다음에 회전할 정보
    index = 0
    # 뱀이 차지하고 있는 위치 정보(꼬리가 앞쪽)
    q = [(x, y)]

    while True:
        nx = x + dx[direction]
        ny = y + dy[direction]

        # x 가 범위 안에 있는지 and y가 범위 안에 있는지 and 뱀의 몸통이 없는 위치인지
        if (1 &lt;= nx and nx &lt;= n) and (1 &lt;= ny and ny &lt;= n) and (data[nx][ny] != 2):
            # 사과가 있는지 확인, 사과가 없으면 이동 후에 꼬리 제거
            if data[nx][ny] == 0:
                data[nx][ny] = 2
                q.append(nx, ny)
                px, py = q.pop(0)
                data[px][py] = 0
            # 사과가 있으면 이동 후에 꼬리 그대로 두기
            if data[nx][ny] == 1:
                data[nx][ny] = 2
                q.append((nx, ny))
        # 벽 또는 뱀의 몸통과 부딪혔다면
        else:
            time += 1
            break
        # 다음 위치로 머리를 이동
        x, y = nx, ny
        time += 1
        if index &lt; l and time == info[index][0]:  # 회전할 시간인 경우 회전
            direction = turn(direction, info[index][1])
            index += 1
        return time
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 무지의 먹방 라이브]]></title>
            <link>https://velog.io/@yj-leee/%EB%AC%B4%EC%A7%80%EC%9D%98-%EB%A8%B9%EB%B0%A9-%EB%9D%BC%EC%9D%B4%EB%B8%8C</link>
            <guid>https://velog.io/@yj-leee/%EB%AC%B4%EC%A7%80%EC%9D%98-%EB%A8%B9%EB%B0%A9-%EB%9D%BC%EC%9D%B4%EB%B8%8C</guid>
            <pubDate>Thu, 26 Aug 2021 14:30:59 GMT</pubDate>
            <description><![CDATA[<p>[문제] 프로그래머스 무지의 먹방 라이브
<a href="https://programmers.co.kr/learn/courses/30/lessons/42891">https://programmers.co.kr/learn/courses/30/lessons/42891</a></p>
<p>첫번째로 roop를 돌면서 하나씩 확인하는 방법이 먼저 떠오르지만, 
k는 2 x 10^13 이하의 자연수이므로 최대 2 x 10^13번 돌아야 한다.</p>
<blockquote>
<p>heapq 자료구조</p>
</blockquote>
<p>힙 자료구조는 우선순위 큐이다.
큐는 가장 먼저 삽입된 데이터가 추출되지만 힙은 가장 우선순위가 높은 데이터가 추출된다.
따라서 가장 적은 시간이 걸리는 음식을 먼저 먹기 위해서 힙 자료구조를 이용한다.</p>
<blockquote>
<p>문제  해결  hint</p>
</blockquote>
<ol>
<li><p>가장 시간이 작은 음식부터 (음식시간, 음식 번호) 형태로 우선순위 큐에 삽입
food_fime에서 k 만큼 이동하다보면 가장 시간이 작은 음식이 0이 된다. 따라서 가장 시간이 작은 음식만큼 다른 food_time 의 수를 빼준다면 roop를 돌리는 수를 줄일 수 있기 때문이다.</p>
</li>
<li><p>가장 시간이 작은 음식을 먹기 위한 시간을 구한다.
<code>min_time</code> 은 남은 음식의 개수 x 음식을 먹는 시간이다. </p>
</li>
<li><p>k를 min_time 만큼 빼준다. 그리고 남은 음식의 개수도 하나씩 줄여준다.</p>
</li>
<li><p>두번째로 시간이 작은 음식을 먹는 시간을 구한다. 마찬가지로 남은 음식의 개수 x 음식을 먹는 시간이다. 이때 다음 먹을 음식의 시간이 
현재 남은 전체 시간보다 크면 빼지 않는다.</p>
</li>
<li><p>그리고 남은 음식을 음식의 번호 기준으로 정렬하고, k 만큼 이동하여 출력한다.</p>
</li>
</ol>
<pre><code class="language-python">import heapq

def solution(food_times, k):
    if sum(food_times) &lt;= k:
        return -1

    # 시간이 작은 음식부터 빼야 하므로 (음식 시간, 음식 번호) 형태로 우선순위 큐에 삽입
    q = []
    for i in range(len(food_times)):
        heapq.heappush(q, (food_times[i], i + 1))

    # 가장 적은 시간이 걸리는 음식을 먹기 위한 시간
    min_t = 0
    # 직전까지 사용한 시간
    total_t = 0
    # 남은 음식의 개수
    length = len(food_times)

    # 남은 시간이 다음 먹을 음식의 시간보다 작은 경우 출력
    while min_t &lt;= k:
        # 가장 적은 시간이 걸리는 음식을 뺀다
        min_q = heapq.heappop(q)[0]

        # 가장 적은 시간이 걸리는 음식을 먹는 시간을 구한다
        min_t = length * min_q

        # 남은 시간, 음식의 개수
        k = k - min_t
        length -= 1

    # 남은 음식을 음식의 번호 기준으로 정렬한다
    result = sorted(q, key =lambda x: x[1])
    print(result[k % length][1])
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 첫 단추]]></title>
            <link>https://velog.io/@yj-leee/%ED%9A%8C%EA%B3%A0-%EC%B2%AB-%EB%8B%A8%EC%B6%94</link>
            <guid>https://velog.io/@yj-leee/%ED%9A%8C%EA%B3%A0-%EC%B2%AB-%EB%8B%A8%EC%B6%94</guid>
            <pubDate>Sat, 07 Aug 2021 01:19:58 GMT</pubDate>
            <description><![CDATA[<p>개발을 시작하고 첫 취업에 성공했다.
비전공자로서 취업이 힘들거라고 생각했는데 생각보다 면접 한번만에 붙게 되어서 다행이었다.
flask를 사용하기 때문에 브랜디에서의 경험이 아주 많이 도움이 될 것 같았다.
실제로 기존 위코드 출신이자 브랜디 경험도 있으신 분이 전직자인 관계로 
여러모로 공통 분모가 많은것 같아서 좋았다. 
비전공자로서 취업 후 휘몰아쳤던 3개월에 대해 무엇을 느끼고 배웠는지 소개해보려고 한다.
또 왜 퇴사했는지? 왜 함께 입사했던 동기와 함께 손에 손잡고 강<del>강</del>수월래 돌리며 나올 수밖에 없었는지!!
그리고 새로운 시작을 앞두고 나의 심정에 대해 써보고 싶다.</p>
<h2 id="🌝-소개">🌝 소개</h2>
<p>우선 SI 회사였지만 나름대로 큰 규모였으며, 제일 큰 계약으로는 코오롱에서 운영하는 아파트 입주민 전용 어플리케이션과 어드민 페이지를 담당하게 되었다.
또한 app은 spring boot 로 이루어져 있어서 국내 백엔드에서 가장 많이 쓰이는 &#39;자바&#39;를 배울 수 있는 크나큰 기회였다!
같이 입사한 위코드 동기는 java 개발자로 취업했다.
그래서 회사에서 슽허디 한다고 남아서 자바도 공부하고 그랬다.</p>
<h2 id="🌖-할-수-있게-된것들">🌖 할 수 있게 된것들</h2>
<p>사수가 없어 &#39;혼자서&#39; 해결해야만 했던 것들이 있다,
진짜 장난 아냐.. 이거 진짜 장난 아냐.. 얼마나 장난 아니냐면.. 진짜 장난 아냐... 아무튼 장난 아냐</p>
<p><img src="https://images.velog.io/images/yj-leee/post/14446130-8bf9-465a-aa23-708952ce7bb6/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-07%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%202.30.26.png" alt=""></p>
<blockquote>
<p>✍ <strong>AWS를 이용한 인프라 구성 및 운영  **
-nginx, elb 생성 후 대상 인스턴스 만들기, gunicorn, 도메인 적용, ssl 적용 등등 ec2 관련한 모든것들
✍ *<em>jenkins 를 통한 CI / 리눅스 배포 *</em>
-배포가 뭔지도 모르더니 이제 자동 배포 파이프라인을 구축할 줄 안다
✍ **spring boot를 통한 app 프로젝트 진행</strong>
-python 개발자로 들어왔는데 java까지!
✍ <strong>firebase 활용한 푸시 알림 기능(springboot, flask)</strong></p>
</blockquote>
<h2 id="🌗-아쉬웠던-점">🌗 아쉬웠던 점</h2>
<img src="https://images.velog.io/images/yj-leee/post/19e6fd8a-0e99-4695-b90e-70ca709f6757/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-07%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.18.27.png" width="50%" height=19>

<p>🚫모르는거 검색하는거 서버 세팅하는거 에러 빵빵 터지면 검색 또 검색... 뭐 어쨌든 해결은 됐다만 시니어 개발자가 있었더라면 길이라도 제시 받을 수 있었을텐데요ㅠ
🚫 협업이라고는 없는 업무체계
개발자는 함께 협업하는 것이라고 배웠는데 거의 혼자 독서실 느낌으로 돌파 해야 한단점이 아쉬웠다.
🚫 코드 올리기 전에 내 코드가 문제가 생기는지 안 생기는지 알 수 없다. si에선 테스트코드 그딴거 없다.</p>
<blockquote>
<p>🚫 결국 <strong>사대보험 체납</strong>으로 퇴사를 하게 되었다.__</p>
</blockquote>
<h2 id="🌘-퇴사요-여기서요">🌘 퇴사요?? 여기서요??</h2>
<h3 id="새로운-시작을-앞두고">새로운 시작을 앞두고</h3>
<img src="https://images.velog.io/images/yj-leee/post/eeeadb4d-025a-4422-bb5c-6b42d9928e07/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-07%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.09.40.png" width="50%" height="20%">



<p>근로계약서 서명하고 잉크도 안말랐을것 같은 &#39;4개월만에 퇴사&#39;였지만 사대보험 체납이라는 
아주 명확한 이유가 있었기에 취업하는데 지장은 없어 다행이었다.</p>
<p>이직한지 3일차, 
아직 배워야할 것도 적응 해야할 것도 많지만 위코드 첫 시작때와 같은 설레임을 경험하고 있다. 
벌써부터 만족스러운 점 중 하나는 이 회사에서는 위에 말했던 세가지 아쉬웠던 점을 모두 보완할 수 있다는 것이다!</p>
<blockquote>
<p>💡 <strong>제대로된 협업 체계</strong>
💡 <strong>모르는건 cto, 선배 백엔드 개발자분께 잘 정리해서 물어볼 수 있는 환경(배포는 cto님께서 담당하신다)</strong>
💡 <strong>업무 체계가 잘 짜여져있다.</strong></p>
</blockquote>
<p>이제 시작하는 graphql 공부 화이팅!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 어노테이션 ]]></title>
            <link>https://velog.io/@yj-leee/java-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@yj-leee/java-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Sat, 15 May 2021 07:18:15 GMT</pubDate>
            <description><![CDATA[<p>[ @Bean, @Configuration ]
개발자가 직접 제어가 불가능한 외부 라이브러리 또는 설정을 위한 클래스를 Bean으로 등록할 때 @Bean 어노테이션을 활용
1개 이상의 @Bean을 제공하는 클래스의 경우 반드시 @Configuration을 명시해 주어야 함
[ @Component ]</p>
<p>개발자가 직접 개발한 클래스를 Bean으로 등록하고자 하는 경우 @Component 어노테이션을 활용좋아요공</p>
<p>[ @Aspect ]</p>
<p>여러 객체에 공통으로 적용되는 공통 관심 사항을 클래스화해서 메소드를 호출하지만 여러곳중 하나에서 기능을 추가하여 
   *공통 관심 사항(AOP) 공통 기능으로 어플리케이션 전반에 걸쳐 필요한 기능으로 여러 객체가 사용하거나, 거쳐가는 기능인지</p>
<p>매개변수가 하나라도 늘어난다면 모든 클래스에서 에러가 나게 된다. 그렇기 때문에 분리시키는 작업을 한다.
자동으로 Bean으로 등록되는것이 아니므로 따로 component 등의 어노테이션을 이용한다.</p>
<p>[ @Around ]</p>
<p>속성값으로 pointcut 을 전달해주어야 한다.</p>
<p>[ @Pointcut ]</p>
<p>-실제로 advice가 적용되는 jointpoint의 부분집합
*advice : 언제 공통 기능을 핵심 로직에 적용할지 정의
                             *jointpoint : advice를 적용 가능한 지점
-excoution(접근 제어자(생략가능) 리턴타입명시 클래스이름(생략가능) 메소드이름 파라미터)
접근 제어자와 반환형 모두 상관하지 않겠다는 의미 -&gt; “ * “ 사용
메소드 파라미터가 몇개가 존재하던지 상관 없이 실행하는 경우 -&gt; “ (..) “ 사용</p>
]]></description>
        </item>
    </channel>
</rss>