<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jr_necki.log</title>
        <link>https://velog.io/</link>
        <description>슉슉슉</description>
        <lastBuildDate>Mon, 29 Aug 2022 02:21:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jr_necki.log</title>
            <url>https://velog.velcdn.com/images/jr_necki/profile/7c2c3127-3f17-445e-9e84-e912c87b1865/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jr_necki.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jr_necki" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[알고리즘 문제풀이]Dynamic Programming]]></title>
            <link>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4Dynamic-Programming</link>
            <guid>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4Dynamic-Programming</guid>
            <pubDate>Mon, 29 Aug 2022 02:21:01 GMT</pubDate>
            <description><![CDATA[<h2 id="1-계단-오르기">1. 계단 오르기</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/3eb39bc9-1ca9-4107-93b8-6e4f2209aaee/image.png" alt=""></p>
<h4 id="🚩-내-코드">🚩 내 코드</h4>
<pre><code>import java.util.Scanner;

public class 계단오르기 {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] dy = new int[n+1];
        dy[1] = 1;
        dy[2] = 2;

        for(int i=3; i&lt;=n; i++){
            dy[i] = dy[i-2]+dy[i-1];
        }
        System.out.println(dy[n]);
    }
}</code></pre><h4 id="💡-푼-방식">💡 푼 방식</h4>
<p>그 이전꺼를 이용하는 방식.</p>
<h4 id="📚-알게-된-정보">📚 알게 된 정보</h4>
<p>피보나치 같당</p>
<h2 id="2-돌다리-건너기">2. 돌다리 건너기</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/f0bb05f0-c70e-4000-bfe3-bd65f92f41b6/image.png" alt=""></p>
<h4 id="🚩-내-코드-1">🚩 내 코드</h4>
<pre><code>import java.util.Scanner;

public class 돌다리건너기 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int dy[] = new int[n+1];
        dy[0] = 1;
        dy[1] = 2;
        for(int i=2; i&lt;=n; i++){
            dy[i] = dy[i-2]+dy[i-1];
        }
        System.out.println(dy[n]);
    }
}</code></pre><h4 id="💡-푼-방식-1">💡 푼 방식</h4>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/cd5ce250-b464-4d0b-9b75-73ef4151eca4/image.png" alt="">
위의 문제와 방식은 같다.
그치만 땅으로 가려면 마지막 돌다리에서 한번 더 건너야한다는 것을 주의하자~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘 문제풀이] greedy]]></title>
            <link>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EA%B7%B8%EB%A6%AC%EB%94%94</link>
            <guid>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EA%B7%B8%EB%A6%AC%EB%94%94</guid>
            <pubDate>Mon, 29 Aug 2022 02:04:57 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디">그리디</h1>
<blockquote>
<p>이 순간에 현재에서 최선의 선택을 함 --&gt; 전체의 최적해가 됨.</p>
</blockquote>
<h2 id="1-씨름선수">1. 씨름선수</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/27abee57-ee78-4e8a-af1a-3cc1828d7446/image.png" alt=""></p>
<h4 id="🚩-내-코드">🚩 내 코드</h4>
<pre><code>import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class 씨름선수 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        ArrayList&lt;Person&gt; al = new ArrayList&lt;&gt;();
        for(int i=0; i&lt;n; i++){
            int h = scanner.nextInt();
            int w = scanner.nextInt();
            al.add(new Person(h,w));
        }
        Collections.sort(al);
        int answer=0;
        int max =Integer.MIN_VALUE;
        for(Person p : al){
            if(p.w &gt; max){
                max = p.w;
                answer++;
            }
        }
        System.out.println(answer);
    }
    public static class Person implements Comparable&lt;Person&gt;{
        int h;
        int w;

        Person(int h, int w){
            this.h = h;
            this.w = w;
        }
        // 키로 내림차순 정렬
        @Override
        public int compareTo(Person o) {
            return o.h-this.h;
        }
    }
}
</code></pre><h4 id="💡-푼-방식">💡 푼 방식</h4>
<p>일단은 사람이라는 객체를 만든 후 키,몸무게를 필드로 갖게 한다.
그리고 사람을 키로 정렬해놓고, 몸무게 비교를한다.  -&gt; o(n)
첨부터 2중 for문 돌면 시간 초과됨.. -&gt; o(n^2)</p>
<p>내림 정렬 후 첫번째 사람은 일단 키가 제일 크기때문에 뽑힌다.
이제 첫번째 사람의 몸무게(=max)를 기준으로 비교해나가면 된다.
max보다 큰거 나오면 +1하고 그 값을 max로 업뎃.</p>
<h4 id="📚-알게-된-내용">📚 알게 된 내용</h4>
<p>객체 비교하는거 </p>
<pre><code>  // 키로 내림차순 정렬
        @Override
        public int compareTo(Person o) {
            return o.h-this.h;
        }</code></pre><br/>
<br/>
## 2. 회의실 배정

<p><img src="https://velog.velcdn.com/images/jr_necki/post/3b161ff3-0ab4-4fa6-8567-aef08a1a180d/image.png" alt=""></p>
<h4 id="🚩-내-코드-1">🚩 내 코드</h4>
<pre><code>import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class 회의실배정 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        ArrayList&lt;Meeting&gt; al = new ArrayList&lt;&gt;();

        for(int i=0; i&lt;n; i++){
            int s = scanner.nextInt();
            int e = scanner.nextInt();
            al.add(new Meeting(s,e));
        }
        Collections.sort(al);
        int answer = 0;
        int end = 0;
        for(Meeting m : al){
            if(m.s &gt;= end){ // 이전에 끝난시간보다 같거나 늦게 시작해야함
                answer++;
                end = m.e;
            }
        }
        System.out.println(answer);
    }
    public static class Meeting implements Comparable&lt;Meeting&gt;{
        int s;
        int e;
        Meeting(int s, int e){
            this.s = s;
            this.e = e;
        }
        @Override
        public int compareTo(Meeting o) {
            if(this.e == o.e){
                return this.s-o.s;
            }else{
                return this.e - o.e;
            }
        }
    }
}
</code></pre><h4 id="💡-푼-방식-1">💡 푼 방식</h4>
<p>기준을 회의가 빨리 끝나는 것으로 해야한다.
먼저 시작하는것을 기준으로 한다면,, 빨리 끝나지만 엄청 늦게 끝나는 경우가 있어서 안된다.</p>
<h4 id="📚-알게-된-내용-1">📚 알게 된 내용</h4>
<h2 id="3-결혼식">3. 결혼식</h2>
<h4 id="🚩-내-코드-2">🚩 내 코드</h4>
<pre><code>import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class 결혼식 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        ArrayList&lt;Person&gt; al = new ArrayList&lt;&gt;();
        for(int i=0; i&lt;n; i++){
            int s = scanner.nextInt();
            al.add(new Person(s,&#39;s&#39;));
            int e = scanner.nextInt();
            al.add(new Person(e,&#39;e&#39;));
        }
        int cnt=0;
        int answer = 0;
        Collections.sort(al);
        for(Person p : al){
            if(p.state == &#39;s&#39;){
                cnt++;
            }else{
                cnt--;
            }
            if(cnt&gt;answer){
                answer=cnt;
            }
        }
        System.out.println(answer);
    }

    private static class Person implements Comparable&lt;Person&gt;{
        int time;
        char state;
        Person(int time, char state){
            this.time = time;
            this.state = state;
        }

        @Override
        public int compareTo(Person o) {
            if(this.time == o.time){
                return this.state - o.state;
            }else{
                return this.time - o.time;
            }
        }
    }
}</code></pre><h4 id="💡-푼-방식-2">💡 푼 방식</h4>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/5baf980c-3810-4d24-b8c9-a8f52b17857d/image.png" alt="">
이렇게 시간순으로 정렬해서,
cnt에는 현재있는 사람수, answer에는 지금껏 최고수를 해보도록했다.
answer는 cnt보다 클 때만 바꿔주도록..
그러기 위해서는 e 끝점에서 사람이 먼저 빠지는걸 체크해줘야한다. (s에서 사람 들어오는걸 먼저하면 answer가 갱신될 수도 있으니까.)
따라서 Person이라는 객체에 시간과 상태(s,e)를 넣어주고
시간을 오름차순으로 정렬 -&gt; 시간이 같다면 상태를 오름차순으로 정렬하면 된다.</p>
<h2 id="4-최대-수입-스케줄">4. 최대 수입 스케줄</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/c3e28558-1b0f-4767-a7d3-9a73278fd6a1/image.png" alt=""></p>
<h4 id="🚩-내-코드-3">🚩 내 코드</h4>
<pre><code>import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class 결혼식 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        ArrayList&lt;Person&gt; al = new ArrayList&lt;&gt;();
        for(int i=0; i&lt;n; i++){
            int s = scanner.nextInt();
            al.add(new Person(s,&#39;s&#39;));
            int e = scanner.nextInt();
            al.add(new Person(e,&#39;e&#39;));
        }
        int cnt=0;
        int answer = 0;
        Collections.sort(al);
        for(Person p : al){
            if(p.state == &#39;s&#39;){
                cnt++;
            }else{
                cnt--;
            }
            if(cnt&gt;answer){
                answer=cnt;
            }
        }
        System.out.println(answer);
    }

    private static class Person implements Comparable&lt;Person&gt;{
        int time;
        char state;
        Person(int time, char state){
            this.time = time;
            this.state = state;
        }

        @Override
        public int compareTo(Person o) {
            if(this.time == o.time){
                return this.state - o.state;
            }else{
                return this.time - o.time;
            }
        }
    }
}</code></pre><h4 id="💡-푼-방식-3">💡 푼 방식</h4>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/5baf980c-3810-4d24-b8c9-a8f52b17857d/image.png" alt="">
이렇게 시간순으로 정렬해서,
cnt에는 현재있는 사람수, answer에는 지금껏 최고수를 해보도록했다.
answer는 cnt보다 클 때만 바꿔주도록..
그러기 위해서는 e 끝점에서 사람이 먼저 빠지는걸 체크해줘야한다. (s에서 사람 들어오는걸 먼저하면 answer가 갱신될 수도 있으니까.)
따라서 Person이라는 객체에 시간과 상태(s,e)를 넣어주고
시간을 오름차순으로 정렬 -&gt; 시간이 같다면 상태를 오름차순으로 정렬하면 된다.</p>
<br/>
<br/>

<h2 id="4-최대-수입-스케줄-1">4. 최대 수입 스케줄</h2>
<h4 id="🚩-내-코드-4">🚩 내 코드</h4>
<pre><code>public class 최대수입스케줄 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        // 큰 값을 우선순위
        PriorityQueue&lt;Integer&gt; queue = new PriorityQueue&lt;&gt;(Collections.reverseOrder());
        ArrayList&lt;Schedule&gt; al = new ArrayList&lt;&gt;();
        int max = 0;
        for(int i=0; i&lt;n; i++){
            int m = scanner.nextInt();
            int d = scanner.nextInt();
            al.add(new Schedule(m,d));
            if (d&gt; max){
                max=d;
            }
        }
        int answer = 0;
        // 날짜가 큰 것부터 정렬됨.
        Collections.sort(al);
        int j=0;
        for(int i=max; i&gt;=1; i--){
            for(;j&lt;n;j++){
                if(al.get(j).d&lt;i) break;
                queue.offer(al.get(j).m);
            }
            if(!queue.isEmpty()) answer+=queue.poll();
        }

    }
    public static class Schedule implements Comparable&lt;Schedule&gt;{
        int d;
        int m;
        Schedule(int d, int m){
            this.d = d;
            this.m = m;
        }

        @Override
        public int compareTo(Schedule o) {
            return o.d - this.d;
        }
    }
}
</code></pre><h4 id="💡-푼-방식-4">💡 푼 방식</h4>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/908aac4b-17e9-49bf-9d99-0cb5328e7a37/image.png" alt="">
날짜가 클 수록, 선택지가 많아지므로 날짜 내림차순으로 강의를 정렬한다.
(강의는 날짜와 시간이라는 필드를 가짐)
그리고 돈이 많은 것부터 queue에 넣어준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript]Interface]]></title>
            <link>https://velog.io/@jr_necki/TypeScriptInterface</link>
            <guid>https://velog.io/@jr_necki/TypeScriptInterface</guid>
            <pubDate>Tue, 23 Aug 2022 09:34:34 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-interface">✔ Interface</h2>
<p>인터페이스는 객체의 모양을 특정해주는 역할을 한다.</p>
<p>Team 이라는 콜을 만들때, 그냥 string이 아닌 구체적인 단어로 설정하면, (또는 Health를 구체적인 숫자로 설정하면)</p>
<pre><code>type Team = &quot;read&quot; | &quot;blue&quot; | &quot;yellow&quot;
type Health = 1 | 5 | 10


interface Player{
    nickname:string,
    team:Team,
    health:Health
}</code></pre><p><img src="https://velog.velcdn.com/images/jr_necki/post/e371b5c1-99c8-4b12-b3e4-6908cf7be4da/image.png" alt="">
그 외의 것은 받을 수 없다.</p>
<p>타입으로 해도 상관은 없다.</p>
<pre><code>type Player = {
    nickname:string,
    team:Team,
    health:Health
}</code></pre><h2 id="✔-interface의-상속">✔ interface의 상속</h2>
<pre><code>interface User{
    name:string
}

interface Player extends User{

}

const necki : Player = {
    name:&quot;necki&quot;
}</code></pre><p>상속도 가능하다.</p>
<h2 id="✔-abstract-쓰는거-보다-interface가-더-좋은듯">✔ abstract 쓰는거 보다 interface가 더 좋은듯..</h2>
<p>인터페이스는 가볍다. 인터페이스는 컴파일하면 js로 바뀌는것이 아니라 사라진다.
여러개 implements 받을 수 도 있고~
<img src="https://velog.velcdn.com/images/jr_necki/post/cd2fcf92-86bb-41c1-b4d1-6d7432242f6e/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] Class]]></title>
            <link>https://velog.io/@jr_necki/TypeScript-class</link>
            <guid>https://velog.io/@jr_necki/TypeScript-class</guid>
            <pubDate>Tue, 23 Aug 2022 05:14:55 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-class">✔ Class</h2>
<p>타입 스크립트로 클래스를 만들어보자.</p>
<pre><code>class Player{
    constructor(
        private firstName:string,
        private lastName:string,
        public nickname:string
    ){}
}

const nekci = new Player(&quot;necki&quot;,&quot;hong&quot;,&quot;네키&quot;);</code></pre><p>클래스 생성자에 properties와 타입을 지정해주면된다.</p>
<p>자바스크립트로는 이렇게 코드가 쓰여진다.</p>
<pre><code>class Player {
    constructor(firstName, lastName, nickname) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.nickname = nickname;
    }
}</code></pre><p>자바스크립트처럼 this.firstName이런식으로 하지 않아서 비교적 간편하다.
또한 private이나 public은 타입스크립트에서만 쓰이는것을 볼 수 있다.</p>
<pre><code>necki.firstName // 에러남!
nekci.nickname // 괜찮음.</code></pre><p>따라서, 타입스크립트는 private인 firstName에 접근할 수 없도록 조치를 취해준다.</p>
<h2 id="✔-abstract">✔ Abstract</h2>
<p>추상클래스는 다른 클래스가 상속받을 수 있는 클래스이다. 그러나 직접 새로운 인스턴스를 만들 수는 없다.</p>
<p>User 추상 클래스와, 이를 상속받는 Player클래스를 만들어보자.
<img src="https://velog.velcdn.com/images/jr_necki/post/677af6bc-3bb3-40d1-a627-121f72154a1d/image.png" alt="">
User로 새로운 클래스를 만드는 것은 불가능한 것을 볼 수 있다.</p>
<h2 id="✔-method">✔ Method</h2>
<p>추상 클래스 안에 메서드를 넣는 것도 가능하다.
풀네임을 반환하는 getFullName메서드를 만들어보자.</p>
<pre><code>abstract class User {
    constructor(
        private firstName:string,
        private lastName:string,
        public nickname:string
    ){}
    getFullName(){
        return `${this.firstName} ${this.lastName}`;
    }
}</code></pre><p>아까 만들었던 necki객체에서 접근가능하다.</p>
<pre><code>nekci.getFullName();</code></pre><p>그러나 getFullName이 private이라면 접근 불가하다.</p>
<h2 id="✔-abstract-method">✔ Abstract Method</h2>
<p>추상메서드는, 메서드를 직접 넣어서는 안되고 콜만 적어두어야한다.</p>
<pre><code> abstract getNickName():void</code></pre><p>그렇게 되면, 추상 메서드를 상속한 클래스에서는 해당 추상메서드를 
implement 즉 구현해주어야한다.
<img src="https://velog.velcdn.com/images/jr_necki/post/df5f6334-9aac-4cdd-95e5-a2f1c00560c4/image.png" alt="">
그러나 상속 받았다고 하더라도 private property는 여전히 접근할 수 없다.
외부 접근을 막고 자식클래스에서는 사용하고 싶다면 private이 아닌 <strong>protected</strong>를 사용하자</p>
<h2 id="✔-위에-것들을-응용하여-사전-만들기">✔ 위에 것들을 응용하여 사전 만들기</h2>
<p>word 라는 콜과
Dict, Word 라는 클래스를 생성하고,
Dict 클래스에는 사전에 단어를 추가 할 수 있는 메서드를 만들어 보자.</p>
<pre><code>//call
type Words = {
    [key:string] : string
}

// class
class Dict{
    private words:Words
    constructor(){
        this.words = {}
    }
    add(word:Word){ // 클래스를 타입처럼
        if(this.words[word.term]===undefined){ // 단어만 넣어놓고 단어 뜻이 없을때
            this.words[word.term] = word.def // 뜻을 추가해준다.
        }
    }
    def(term:string){ // 단어를 넣으면
        return this.words[term] // 뜻을 반환
    }
}

//class
class Word {
    constructor(
        public term:string,
        public def : string
    ){

    }
}

const naruto = new Word(&quot;naruto&quot;,&quot;닌자가 나오는 만화&quot;)
const dict = new Dict();
dict.add(naruto);
dict.def(&quot;naruto&quot;)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript]Polymorphism]]></title>
            <link>https://velog.io/@jr_necki/TypeScriptPolymorphism</link>
            <guid>https://velog.io/@jr_necki/TypeScriptPolymorphism</guid>
            <pubDate>Mon, 22 Aug 2022 12:04:46 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-polymorphism">✔ Polymorphism</h2>
<p>다형성 즉 다른 구조를 가진다고 보면된다.</p>
<pre><code>type SuperPrint = {
    (arr: number[]):void
    (arr: boolean[]):void
}

const superPrint:SuperPrint = (arr)=&gt;{
    arr.forEach(i =&gt; console.log(i))
}

superPrint([1,2,3,4])
superPrint([true,false,true])
superPrint([&quot;hi&quot;,&quot;a&quot;,&quot;b&quot;]);</code></pre><p>call signatures에서 number,boolean 배열은 있지만, string배열은 없어서, 마지막 함수는 에러가 난다.
이를 해결하기 위해 call signatures(이하 콜)에 string 배열을 추가해줄 수도 있지만 더 좋은 방법이 있다.</p>
<h2 id="✔-generic">✔ Generic</h2>
<p>타입의 placeholder같은 것이다.
concrete type을 사용하는 것 대신 쓸 수 있다.
콜을 작성할 때, 여기에 들어올 확실한 타입을 모른다면 generic을 사용해보자.</p>
<h2 id="✔-사용법">✔ 사용법.</h2>
<p>일단 콜에게 제네릭타입을 쓴다고 알려준다.</p>
<pre><code>type SuperPrint = {
    &lt;T&gt;(arr: T[]):void 
}</code></pre><p>타입스크립트는 자신이 발견한 타입으로 추론해서 바꿔준다.</p>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/fd046532-edbd-46ef-b074-12efad25da28/image.png" alt=""></p>
<p>모두 가능한것을 확인할 수 있다.</p>
<h4 id="리턴-타입도-제네릭으로-가능">리턴 타입도 제네릭으로 가능</h4>
<pre><code>type SuperPrint = {
    &lt;T&gt;(arr: T[]):T 
}

const superPrint:SuperPrint = (arr)=&gt;{
    return arr[0];
}</code></pre><h4 id="제네릭-추가">제네릭 추가</h4>
<pre><code>type SuperPrint = {
    &lt;T,M&gt;(arr: T[],b:M):T 
}

const superPrint:SuperPrint = (arr)=&gt;{
    return arr[0];
}
superPrint([1,2,3,4],1)
superPrint([true,false,true],&quot;hi&quot;)</code></pre><p>또다른 제네릭 타입을 추가 하고 싶다면, 저렇게 해주면 된다!!</p>
<h4 id="그냥-함수로도">그냥 함수로도...</h4>
<pre><code>function superPrint&lt;T&gt;(a: T[]){
    return a[0]
}</code></pre><p>콜 없이 바로 함수로도 적용하는게 더 간단해 보이는듯..</p>
<p><br/><br/>
자바 제네릭 할 땐,, 뭔가 어려워보여서 제대로 공부를 안했었는데
생각보다 쉽고 간편해서 좋다. 둥둥둥~🥁</p>
<h2 id="✔-로컬스토리지-구현해보기">✔ 로컬스토리지 구현해보기</h2>
<pre><code>interface SStorage&lt;T&gt;{
    [key:string]:T
}

class LocalStorage&lt;T&gt;{
    private storage:SStorage&lt;T&gt;={}
    set(key:string,value:T){
        this.storage[key] = value;
    }
    remove(key:string){
        delete this.storage[key];
    }
    get(key:string):T{
        return this.storage[key];
    }
    clear(){
        this.storage = {}
    }
}

const stringStorage = new LocalStorage&lt;string&gt;()
stringStorage.get(&quot;key&quot;);
stringStorage.set(&quot;hello&quot;,&quot;say hi~&quot;)

const booleanStorage = new LocalStorage&lt;boolean&gt;();
booleanStorage.get(&quot;xxx&quot;);
booleanStorage.set(&quot;hello&quot;,true);</code></pre><p>LocalStorage클래스와, SStorage타입을 제네릭으로 받아준다.
string이든 boolean이든 타입을 지정해주어서, 해당 객체일 땐 특정 타입으로만 추론되게 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] Overloading]]></title>
            <link>https://velog.io/@jr_necki/TypeScript-Overloading</link>
            <guid>https://velog.io/@jr_necki/TypeScript-Overloading</guid>
            <pubDate>Mon, 22 Aug 2022 11:14:02 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-overloading-">✔ Overloading ??</h2>
<p>오버로딩은 함수가 서로 다른 여러개의 <a href="https://velog.io/@jr_necki/TypeScript-%ED%95%A8%EC%88%98">call signatures</a>를 가지고 있을 때 발생한다.</p>
<h4 id="파라미터-타입이-다를-경우">파라미터 타입이 다를 경우</h4>
<p>파라미터 타입이 다를 경우에, if문으로 나누어서 처리 할 수 있다.</p>
<pre><code>type Config = {
    path:string,
    state:object
}

type Push={
    (path:string): void
    (config:Config):void
}

const push:Push = (config)=&gt;{ 
    if(typeof config === &#39;string&#39;) console.log(config)
    else {
        console.log(config.path)
    }
}</code></pre><p>push함수의 config 파라미터 타입은 string | Config이 될 수 있고,
이는 if문으로 나눌 수 있다.</p>
<h4 id="파라미터-개수가-다를-경우">파라미터 개수가 다를 경우</h4>
<pre><code>type Add = {
    (a:number, b:number):number,
    (a:number, b:number, c:number):number,
}</code></pre><p>c파라미터는 있는것과 없는 것이 있으므로</p>
<pre><code>const add:Add=(a,b,c?:number)=&gt;{
    return a+b
}</code></pre><p>optional로 정해주면 된다.
<br/><br/></p>
<p>물론 이렇게 해도 된다.^^ </p>
<pre><code>type Add = {
    (a:number, b:number, c?:number):number,
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] Call Signatures]]></title>
            <link>https://velog.io/@jr_necki/TypeScript-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@jr_necki/TypeScript-%ED%95%A8%EC%88%98</guid>
            <pubDate>Mon, 22 Aug 2022 10:13:03 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-call-signatures">✔ Call Signatures</h2>
<p><strong>Call Signatures</strong>란 함수 위에 마우스를 댔을때 뜨는 것을 말한다.
즉, 인자의 타입과 리턴 타입을 보여준다.</p>
<p><strong>Call Signatures 선언하는 방법.</strong></p>
<p>만약에 아래 함수를 </p>
<pre><code>const add=(a:number, b: number)=&gt;a+b;</code></pre><p>call signatures를 적용하여 본다고 하면,,</p>
<pre><code>type Add = (a:number, b: number) =&gt; number;

const add : Add = (a,b) =&gt; a+b</code></pre><p>로 표현할 수 있다. 그렇게 되면 함수에 따로 타입을 지정해주지 않아도 되는 이점이 있다.
alias와 좀 비슷한거 같다.</p>
<h2 id="✔-void-함수-일-때">✔ void 함수 일 때</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/5a88d230-8619-4a8d-b722-12ab2ce26c69/image.png" alt="">
number타입 반환이라고 미리 지정해주었지만 add함수에서는 리턴 값이 없으므로, 빨간줄이 뜬다.</p>
<h3 id="내가-헷갈려서-정리하는😌-화살표-함수에서-의-유무">내가 헷갈려서 정리하는😌 화살표 함수에서 {}의 유무</h3>
<h5 id="없을-때">{}없을 때</h5>
<pre><code>const add : Add =(a,b) =&gt; a+b
// 이를 풀어서 표현해보면
function add(a,b){
    return a+b;
}</code></pre><h5 id="있을-때">{}있을 때</h5>
<pre><code>const add: Add=(a,b)=&gt;{a+b}
// 이를 풀어서 표현해보면
function add(a,b){
    a+b;
}</code></pre><p>따라서 {}가 있으면 리턴이 아닌 함수내용으로 처리되므로 void함수이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입]]></title>
            <link>https://velog.io/@jr_necki/TypeScript-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@jr_necki/TypeScript-%ED%83%80%EC%9E%85</guid>
            <pubDate>Mon, 22 Aug 2022 06:01:22 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-object-타입">✔ Object 타입</h2>
<p>playerHong 객체에 이름과 나이 변수를 넣어보자. type을 지정해주어야하므로 name,age 각각 타입을 써주어야 한다.</p>
<pre><code>const playerHong:{
    name:string,
    age:number
}={
    name:&quot;hong&quot;,
    age:12
}</code></pre><p>여기서 <strong>optional</strong> 이라는 특징을 설정할 수 있는데, 만약 age를 optional로 설정하면 playerHong 객체는 age가 없을 수도 있다는 것을 뜻한다.</p>
<pre><code>const playerHong:{
    name:string,
    age?:number
}={
    name:&quot;hong&quot;
}</code></pre><p>optional을 하고 싶은 변수에 <strong>?</strong>만 붙여주면 된다!</p>
<h2 id="✔-alias">✔ alias</h2>
<p>그런데 player마다 저렇게 타입을 지정한다면 매우 번거로울것이다.</p>
<p>Player 타입을 지정해주고, 원하는 객체를 만들때 player타입을 넣어주면 훨씬 간편하다. 이렇게 별칭해주는 것을 <strong>alias</strong>라고 한다.</p>
<pre><code>type Player = {
    name:string,
    age?:number
}

const hong:Player = {
    name:&quot;hong&quot;
}
const kim:Player = {
    name:&quot;kim&quot;
}</code></pre><p>재사용성이 증가한것을 볼 수 있다.</p>
<h2 id="✔-함수">✔ 함수</h2>
<p>함수에 필요한 인자가 있으면, 타입을 지정해주고, 리턴 타입 또한 지정해주면 된다.</p>
<pre><code>function playerMaker(name:string) : Player{
    return {
        name
    }
}
const necki = playerMaker(&quot;necki&quot;);
necki.age = 10;</code></pre><p>playerMaker함수의 리턴 타입이 Player이므로 necki는 age도 설정할 수 있게 되는것이다.</p>
<h4 id="화살표-함수일-땐">화살표 함수일 땐??</h4>
<pre><code>const playerMaker=(name:string) : Player =&gt;({name})</code></pre><p>같은 맥락 ㅎㅎ
<br/></p>
<h2 id="✔-튜플">✔ 튜플</h2>
<p>배열안에 특정 위치에 특정 타입을 지정하고 싶을경우!</p>
<pre><code>const player:[string,number,boolean]=[&quot;nico&quot;,12,true]
</code></pre><h2 id="✔-기타">✔ 기타</h2>
<pre><code>let a : unknown; // 변수 타입을 미리 얻지 못할 때 사용.

if(typeof a === &#39;string&#39;){
    let b = a.toUpperCase();
}

// 아무것도 리턴하지 않는 함수 :void
function hello(){
    console.log(&#39;x&#39;);
}

// 절대 리턴하지 않는 경우,또는 리턴타입이 2개일때 :never
function hello2(name:string | number){
   if(typeof name === &#39;string&#39;){
       name // string
   }else if(typeof name === &#39;number&#39;){
       name // number
   }else{
       name // never
   }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입스크립트란??]]></title>
            <link>https://velog.io/@jr_necki/TypeScript</link>
            <guid>https://velog.io/@jr_necki/TypeScript</guid>
            <pubDate>Mon, 22 Aug 2022 05:10:20 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-typescript">✔ TypeScript</h2>
<p>타입스크립트는 자바스크립트 기반의 언어이다.
<img src="https://velog.velcdn.com/images/jr_necki/post/83676ceb-dd67-4f72-8b38-20bb16db84e9/image.png" alt=""></p>
<li> 자바스크립트 상위 집합이라서 자스의 모든 기능이 포함되어 있다.
<li> typescript 컴파일러 사용하여 ts -> js로 변환한다.
<li> 클래스 객체 만들기 가능
<li>클래스 기반으로  객체 지향 프로그래밍 언어 (자바같아서 넘 좋당ㅎㅎ)


<h2 id="✔-작동-방식">✔ 작동 방식</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/61d69a4e-5366-4b61-9c30-8a40d63c2e84/image.png" alt=""></p>
<h4 id="explicit">Explicit</h4>
<p>자바나 c,c++은 타입을 명시적으로 정해주어야한다.
타입스크립트 또한 명시적으로 정해줄 수 있지만, (타입이 틀리면 말해준다)
<img src="https://velog.velcdn.com/images/jr_necki/post/707e4dd2-6f71-423f-9d6c-2a13c175b343/image.png" alt=""></p>
<h4 id="implicit">Implicit</h4>
<p>생략해도 괜찮다.
let a 변수가 &quot;hello&quot;라고 할 때 타입스크립트는 string 타입으로 추론할 수 있기 때문이다.
따라서 a=1라고 했을 때, 틀렸다고 알려준다.
<img src="https://velog.velcdn.com/images/jr_necki/post/9bf523f5-2e98-4677-958a-e0a92515cc88/image.png" alt=""></p>
<p>시간이나 가독성 면에서, 명시적 표현은 최소화하여 typeScript가 추론하게 하는게 낫다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 공통 컴포넌트 세팅]]></title>
            <link>https://velog.io/@jr_necki/React-%EA%B3%B5%ED%86%B5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%84%B8%ED%8C%85</link>
            <guid>https://velog.io/@jr_necki/React-%EA%B3%B5%ED%86%B5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%84%B8%ED%8C%85</guid>
            <pubDate>Sat, 20 Aug 2022 05:00:02 GMT</pubDate>
            <description><![CDATA[<h2 id="✔-공통-컴포넌트">✔ 공통 컴포넌트</h2>
<p>버튼을 만들려고 하는데, 삭제버튼,수정버튼,완료버튼 모두 버튼이라는 하나의 공통점이 있다. 따라서 버튼 하나 하나 만들지 말고, props를 이용하여 만들어보자
<img src="https://velog.velcdn.com/images/jr_necki/post/67ca3d0f-6593-4a58-bd7e-1cc0df16d648/image.png" alt=""></p>
<p>필요한 props와 함께 버튼 컴포넌트를 생성해준다.</p>
<pre><code>const MyButton = ({text,type,onClick}) =&gt; {
    return (
        &lt;button className=&quot;{&#39;MyButton}&quot; onClick={onClick}&gt;
            {text}
        &lt;/button&gt;
    )
}

export default MyButton;</code></pre><p>원하는 버튼 설정</p>
<pre><code> &lt;MyButton
          text={&#39;버튼&#39;}
          onClick={() =&gt; alert(&#39;그냥 버튼&#39;)}
          type={&quot;positive&quot;}
        /&gt;</code></pre><p>잘 나오는것을 볼 수 있다.
<img src="https://velog.velcdn.com/images/jr_necki/post/0f52c426-bf96-43b5-abb4-c9608ab33c7f/image.png" alt=""></p>
<h2 id="✔-스타일">✔ 스타일</h2>
<p>버튼 타입에 따라서 3가지 스타일을 만들어보도록 하자</p>
<p>그러기 위해서는 버튼 타입마다 className이 달라져야한다.</p>
<pre><code>  &lt;button className={[&quot;MyButton&quot;,`MyButton_${type}`].join(&quot; &quot;)} onClick={onClick}&gt;</code></pre><p>className은 문자열로 되어야하므로, 배열로 있던 요소들을 띄어쓰기와 함께 문자열로 만들면 완료.
이렇게 되면 MyButton이라는 className은 공통으로 들어가지만 MyButton_타입에 따라 달라지게 되므로 개별적으로 css를 추가해 줄 수 있다.</p>
<pre><code>MyButton.defaultProps = {
    type:&quot;default&quot;,
}</code></pre><p>만약 type이 없으면 default로 잡아준다.
그런데 만약 type이 sSDFASDFASDASF이런 말같지도 않은걸로 전달되면 어떻게 처리해야할까?</p>
<pre><code>const btnType = [&#39;positive&#39;, &#39;negative&#39;].includes(type) ? type : &#39;defualt&#39;;</code></pre><p>positive나 negative에 속하지 않는다면 default타입으로 정해주면 된다!!</p>
<h2 id="✔-props에-컴포넌트-넣기">✔ props에 컴포넌트 넣기</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/c9de01fc-fed0-4891-bb8b-22f2f42b6d61/image.png" alt="">
이렇게 헤더를 만들건데, MyHeader.js라는 컴포넌트를 만들고 props를 통해서 버튼을 넣어 줄 수 있다. (신기행)
<br/>
<br/>
먼저 헤더를 만들어주고 필요한 props를 담아온다.</p>
<pre><code>const MyHeader = ({headText,leftChild,rightChild}) =&gt; {
    return &lt;header&gt;
        &lt;div className=&quot;head_btn_left&quot;&gt;
            {leftChild}
        &lt;/div&gt;
        &lt;div className=&quot;head_text&quot;&gt;
            {headText}
        &lt;/div&gt;
        &lt;div className=&quot;head_btn_right&quot;&gt;
            {rightChild}
        &lt;/div&gt;
    &lt;/header&gt;
}

export default MyHeader;</code></pre><pre><code>&lt;MyHeader
          headText={&#39;header&#39;}
          leftChild={&lt;MyButton text={ &#39;왼쪽 버튼&#39;} onClick={()=&gt;alert(&quot;왼쪽 클릭!&quot;)} /&gt;}
          rightChild={&lt;MyButton text={ &#39;오른쪽 버튼&#39;} onClick={()=&gt;alert(&quot;오른쪽 클릭!&quot;)} /&gt;}
          /&gt;</code></pre><p>이렇게 넣어주면 완성!
<img src="https://velog.velcdn.com/images/jr_necki/post/5c77ecdd-d741-4f49-9d6f-9540404d8dcd/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React hooks] useContext]]></title>
            <link>https://velog.io/@jr_necki/React-hooks-useContext</link>
            <guid>https://velog.io/@jr_necki/React-hooks-useContext</guid>
            <pubDate>Thu, 18 Aug 2022 07:20:06 GMT</pubDate>
            <description><![CDATA[<h3 id="✔-context의-필요성">✔ Context의 필요성</h3>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/42392a4b-05e2-4099-9efe-d96a5a339330/image.png" alt="">
만약에 onRemove를 onDelte라고 이름을 바꾸고 싶다면 매우 번거로울 것이다.
props가 땅을 파고 드는것 같다고 해서 이 현상을 <strong>props drilling</strong> 이라고 한다!</p>
<p>여튼 이를 방지하기 위해서는 최상위 props를 하위 컴포넌트에서도 접근가능하게 하면 될것이다.
<strong>Provider</strong> 컴포넌트를 이용하면 props를 직통으로 공급해주어 props drilling이 사라진다.
<img src="https://velog.velcdn.com/images/jr_necki/post/c5837d0a-cb28-4492-91b0-c38ee13c14cf/image.png" alt="">
해당 provider가 공급하는 데이터에 접근할 수 있는 컴포넌트들의 영역을 <strong>Context</strong>라고 한다.</p>
<h3 id="✔-usecontext">✔ useContext</h3>
<pre><code>const MyContext = React.createContext(defaultValue); // Context 생성

&lt;MyContext.Provider value={전역으로 전달하고자하는 값}&gt;
{/*이 context안에 위치할 자식 컴포넌트들*/}
&lt;/MyContext.Provider&gt;</code></pre><p>App.js에서 최상단으로 자식컴포넌트들을 감싸주고 data 값을 공급해준다.
data값이 있으니 DiaryList의 dairylist props는 지워주면 됨. ㅎㅎ</p>
<pre><code> &lt;DiaryStateContext.Provider value={data}&gt;
    &lt;div className=&quot;App&quot;&gt;
      &lt;DiaryEditor onCreate={ onCreate } /&gt;
       &lt;div&gt;전체 일기 : {data.length}&lt;/div&gt;
      &lt;div&gt; 기분 좋은 일기 개수 : {goodCount}&lt;/div&gt;
      &lt;div&gt;기분 나쁜 일기 개수:{badCount}&lt;/div&gt;
      &lt;div&gt;기분 좋은 일기 비율:{ goodRatio }%&lt;/div&gt;
      &lt;DiaryList  onDelete={onDelete} onEdit={onEdit}/&gt;
    &lt;/div&gt;
    &lt;/DiaryStateContext.Provider&gt;</code></pre><p>DairyList 에서는 data를 받아야 하니까, </p>
<pre><code>const diaryList = useContext(DiaryStateContext);</code></pre><p>props drilling을 일으켰던, onEdit,onRemove를 해결해보자..
value에다가 data를 넣은듯이 두개를 넣으면 안된다! 
왜냐하면,, provider도 컴포넌트이므로 data값이 바뀔때마다 계속 리렌더링 되어서, 최적화 시켰던 코드가 무용지물이 되기 때문이다!</p>
<h3 id="✔-이중-context">✔ 이중 context</h3>
<p>이를 해결하기 위해 context를 안에 더 넣어주면된다.
onCreate,onEdit,onRemove 함수들을 재생성되지 않게 메모제이션 해주면 된다.</p>
<pre><code>  const memoizedDispatches = useMemo(()=&gt;{
    return {onCreate,onDelete,onEdit}
  },[])</code></pre><p>✨완성✨</p>
<pre><code> &lt;DiaryStateContext.Provider value={data}&gt;
    &lt;DiaryDispatchContext.Provider value={memoizedDispatches}&gt;
    &lt;div className=&quot;App&quot;&gt;
      &lt;DiaryEditor onCreate={ onCreate } /&gt;
       &lt;div&gt;전체 일기 : {data.length}&lt;/div&gt;
      &lt;div&gt; 기분 좋은 일기 개수 : {goodCount}&lt;/div&gt;
      &lt;div&gt;기분 나쁜 일기 개수:{badCount}&lt;/div&gt;
      &lt;div&gt;기분 좋은 일기 비율:{ goodRatio }%&lt;/div&gt;
      &lt;DiaryList  onDelete={onDelete} onEdit={onEdit}/&gt;
    &lt;/div&gt;
    &lt;/DiaryDispatchContext.Provider&gt;
    &lt;/DiaryStateContext.Provider&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[React hooks] useReducer]]></title>
            <link>https://velog.io/@jr_necki/React-hooks-useReducer</link>
            <guid>https://velog.io/@jr_necki/React-hooks-useReducer</guid>
            <pubDate>Thu, 18 Aug 2022 06:25:40 GMT</pubDate>
            <description><![CDATA[<h3 id="✔-현재-appjs의-상태">✔ 현재 App.js의 상태..</h3>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/d71f78ed-c301-43c4-8dd7-d020a355a57f/image.png" alt=""></p>
<p>data를 참조해야하기 때문에 App.js안에서만 상태관리가 이루어질 수 밖에 없다.
현재 app.js 코드가 길어서 넘 무거움..!!</p>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/3a9f64b2-99d9-43c2-827a-b10ad56e270d/image.png" alt="">
목표: 상태변화 로직들을 컴포넌트에서 분리하여 좀 더 가볍게 만들기.</p>
<h3 id="✔-usereducer">✔ useReducer</h3>
<pre><code>const [&lt;상태 객체&gt;, &lt;dispatch 함수&gt;] = useReducer(&lt;reducer 함수&gt;, &lt;초기 상태&gt;, &lt;초기 함수&gt;)</code></pre><p>reducer 함수는 현재 state 객체,action 객체를 인자로 받아서 새로운 state를 리턴하는 함수이다.
행동객체는 reducer에서 어떤 행동을 할지 알려주는 type과, 그외에 필요한 데이터가 있으면 담을 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/b3e921c6-70fc-4afb-9d27-a265149f6af5/image.png" alt="">
dispatch가 필요한 데이터들을 싣고 reducer 상태 창고까지 가면, 거기서 가공을 해서 새로운 state를 배송하는 그런 느낌이다 ㅎㅎ dispatch가 버스같은 느낌~~</p>
<h3 id="✔-적용">✔ 적용</h3>
<pre><code>const [data,dispatch] = useReducer(reducer,[]);</code></pre><p>useState대신 useReducer를 넣어주었고, 초기값은 역시 빈배열이다!
처음에 getData() 함수에서 얻어낸 initData를 data 로 설정해주어야한다.</p>
<pre><code> dispatch({type:&#39;INIT&#39;,data:initData})</code></pre><p>getData 함수 안에 dispatch 버스를 initData를 태워서 보내주면 된다~🚙</p>
<pre><code> case &#39;INIT&#39; :{
      return action.data;
    }</code></pre><p>그러면 이제 data라는 상태는 initData로 변경이 된 것이다.</p>
<pre><code>const reducer=(state,action)=&gt;{
  switch(action.type){
    case &#39;INIT&#39; :{
      return action.data;
    }
    case &#39;CREATE&#39;:{
      const created_date = new Date().getTime();
      const newItem = {
        ...action.data,
        created_date
      }
      return [newItem,...state]; // 새로운 값 + 원래 있던 배열
    }
    case &#39;REMOVE&#39;:{
      return state.filter((it)=&gt; it.id !== action.targetId)
    }
    case &#39;EDIT&#39;:{
      return state.map((it)=&gt; it.id === action.targetId? {...it,content:action.newContent} : it )
    }
    default: 
    return state;
  }
}</code></pre><p>onCreate,onRemove,onEdit도 마찬가지로 type.action을 지정해 주어서 원하는 행동을 넣으면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React hooks] React.memo & useCallback]]></title>
            <link>https://velog.io/@jr_necki/React-hooks-React.memo-useCallback</link>
            <guid>https://velog.io/@jr_necki/React-hooks-React.memo-useCallback</guid>
            <pubDate>Wed, 17 Aug 2022 04:48:40 GMT</pubDate>
            <description><![CDATA[<h3 id="✔-컴포넌트가-리렌더링-되는-경우">✔ 컴포넌트가 리렌더링 되는 경우</h3>
<ol>
<li>본인이 가진 state 가 변경될 때</li>
<li>부모 컴포넌트가 리렌더링 될 떄</li>
<li>props가 변경될 때</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/158645fc-1273-4fed-917f-9d14724441aa/image.png" alt="">
일기를 수정하는데 네모칸이 리렌더링 될 필요는 없다.</p>
<h3 id="✔-reactmemo">✔ React.memo</h3>
<p>React는 먼저 컴퍼넌트를 렌더링(rendering) 한 뒤, 이전 렌더된 결과와 비교하여 DOM 업데이트를 결정한다. 만약 렌더 결과가 이전과 다르다면, React는 DOM을 업데이트한다.</p>
<p>컴퍼넌트가 React.memo()로 래핑 될 때, React는 컴퍼넌트를 렌더링하고 결과를 메모이징(Memoizing)한다. 그리고 다음 렌더링이 일어날 때 props가 같다면, React는 메모이징(Memoizing)된 내용을 재사용한다.</p>
<p>즉,<strong>React.memo</strong>를 사용하면  일기 수정을 해도 네모 칸 부분인 DiaryEditor.js 의 props는 동일하므로 리렌더링을 방지 할 수 있다.</p>
<h3 id="✔-사용법">✔ 사용법</h3>
<p>컴포넌트를 감싸서 React.memo를 해주거나</p>
<pre><code>export default React.memo(DiaryEditor);</code></pre><p>이렇게 해주면 완료~</p>
<h3 id="✔-더-확실히">✔ 더 확실히...</h3>
<pre><code>const DiaryEditor = ({ onCreate }) =&gt; {
    useEffect(() =&gt; {
        console.log(&quot;DiaryEditor 렌더&quot;);
    });</code></pre><p>App.js에서 보낸 props인 onCreate 함수가 계속 변하기 때문에  DiaryEditor가 리렌더링 되는것이다. 왜냐하면 일기를 삭제하거나 새로 쓰면, 리렌더링이 되고 onCreate함수또한 새로 만들어지므로, 얕은 비교를 하기 때문에 onCreate이라는 props가 다르다고 판별되어 리렌더링 되는것이다.</p>
<p><strong>결론은 onCreate 재생성을 막아서 최적화를 시키자!!!</strong></p>
<h3 id="✔-usecallback">✔ useCallback</h3>
<p>위에서 한대로 useMemo를 이용하고 싶지만,, useMemo는 함수가 아닌 값을 리턴하는 것이므로 불가능하다. 따라서 useCallback을 사용해야한다.</p>
<pre><code>const memoizedCallback = useCallback(
  () =&gt; {
    doSomething(a, b);
  },
  [a, b],
);</code></pre><p>a,b가 바뀌지 않는다면 첫번째 인자로 받은 콜백함수를 재사용하는 훅이다. </p>
<p>여튼 이거를 onCreate함수에 적용시켜보았다.</p>
<pre><code>  const onCreate = useCallback((author, content, emotion) =&gt; {
    const created_date = new Date().getTime();
    const newItem = {
      author,
      content,
      emotion,
      created_date,
      // id가 필요한데 이거는 변수처럼 이용해야함.
      id: dataId.current,
    };
    dataId.current += 1;

  },[]);</code></pre><p>그러나 이렇게 하면 초기값이 []빈 배열인거로 기억하기 때문에 일기를 추가하면 전에 있던것이 빈배열 + 새로 추가한것 해서 1개만 생성이 된다.
이를 해결하기 위해서는 
setData()를 이용해야한다.
저 안에  </p>
<pre><code>setData((data)=&gt;[newItem,...data])</code></pre><p>이걸 넣어주면 setData로 데이터를 불러와서 해결가능하다!</p>
<h3 id="✔-결과">✔ 결과</h3>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/d430c1cc-1fb1-428b-b91f-d46679cbff9c/image.png" alt="">
일기를 삭제해도 리렌더링 되지 않는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React hooks]useMemo]]></title>
            <link>https://velog.io/@jr_necki/React-hooksuseMemo</link>
            <guid>https://velog.io/@jr_necki/React-hooksuseMemo</guid>
            <pubDate>Wed, 17 Aug 2022 02:28:36 GMT</pubDate>
            <description><![CDATA[<h3 id="✔-memoization">✔ Memoization</h3>
<blockquote>
<p>이미 계산 해 본 연산 결과를 기억해 두었다가, 동일한 계산을 시키면
다시 연산하지 않고 기억해 두었던 데이터를 반환</p>
</blockquote>
<h3 id="✔-usememo">✔ useMemo</h3>
<pre><code>const getDiaryAnalysis =()=&gt;{
    console.log(&quot;일기 분석 시작&quot;);

    const goodCount = data.filter((it) =&gt; it.emotion &gt;= 3).length;
    const badCount = data.length - goodCount;
    const goodRatio = (goodCount / data.length) * 100;
    return { goodCount, badCount, goodRatio };
    }</code></pre><p>맨 처음에 getDiaryAnalysis함수는 2번실행된다.
왜냐하면 처음 마운트가 될때 (data가 빈배열이었을 때), 한 번 호출.</p>
<p>setData가 되면서 data가 한번 바뀐다. =&gt; app컴포넌트가 리렌더링 되면서 모든 함수가 재호출이 된다</p>
<h4 id="❓-그렇다면-일기를-수정할-때는-어떻게-될까">❓ 그렇다면 일기를 수정할 때는 어떻게 될까?</h4>
<p>data값이 바뀌므로 getDiaryAnalysis함수는 또 실행이 된다.</p>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/37da9ef0-2d8b-44ba-aa99-b70f960b8f53/image.png" alt="">
그러나 일기를 수정해도, 저 네모안의 값들은 바뀌지 않으므로, getDiaryAnalysis함수가 실행되는 것은 불필요하다. 따라서 <strong>useMemo</strong>를 사용해 보았다.</p>
<h3 id="✔-사용법">✔ 사용법</h3>
<p>메모이제이션 하고 싶은 함수에 useMemo로 감싸준다.
첫번째 파라미터는 함수, 두번째 파라미터는 조건을 넣어준다.
즉 data.length가 일정할때 메모이제이션을 해주는 것이다.</p>
<pre><code>  const getDiaryAnalysis = useMemo(
    () =&gt; { // 콜백함수
    console.log(&quot;일기 분석 시작&quot;);

    const goodCount = data.filter((it) =&gt; it.emotion &gt;= 3).length;
    const badCount = data.length - goodCount;
    const goodRatio = (goodCount / data.length) * 100;
    return { goodCount, badCount, goodRatio };
    },[data.length]);

  const { goodCount, badCount, goodRatio } = getDiaryAnalysis;
</code></pre><p>리턴 값은 함수가 아닌 값을 리턴해준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React hooks]useState]]></title>
            <link>https://velog.io/@jr_necki/React-hooksuseState</link>
            <guid>https://velog.io/@jr_necki/React-hooksuseState</guid>
            <pubDate>Sun, 14 Aug 2022 10:19:23 GMT</pubDate>
            <description><![CDATA[<h3 id="✅-usestate">✅ useState</h3>
<blockquote>
</blockquote>
<p>상태값을 바로바로 업데이트 할 수 있다.
const [&lt;상태 값 저장 변수&gt;, &lt;상태 값 갱신 함수&gt;] = useState(&lt;상태 초기 값&gt;);</p>
<pre><code>import React, { useState } from &#39;react&#39;;

function Example() {
  // &quot;count&quot;라는 새로운 상태 값을 정의합니다.
  const [count, setCount] = useState(0);

  return (
    &lt;div&gt;
      &lt;p&gt;You clicked {count} times&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
        Click me
      &lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><h3 id="✅-응용">✅ 응용</h3>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/abc10c40-ddd4-4b11-9593-e3dc7f79ab06/image.png" alt="">
여기서 작성자, 내용, 기분옵션은 onChange 함수에 setState()를 줘서 바뀐값을 설정하는 방식이다. 따라서 하나하나 useState 변수를 주지 않고 </p>
<pre><code> const [state, setState] = useState({
        author: &quot;&quot;,
        content: &quot;&quot;,
        emotion:1
    })</code></pre><pre><code>   const handleChangeState = (e) =&gt; {
        console.log(e.target.name);
        console.log(e.target.value);

        setState({
            ...state,
            [e.target.name]: e.target.value
        })
    }</code></pre><p>로 해주어서, 스프레드연산 뒤 name과 키보드입력값(value)를 짝지어준다.
onChange에 handleChangeState함수를 넣어주면 완성이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘 문제풀이] 그래프]]></title>
            <link>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EA%B7%B8%EB%9E%98%ED%94%84</link>
            <guid>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-%EA%B7%B8%EB%9E%98%ED%94%84</guid>
            <pubDate>Wed, 10 Aug 2022 06:29:57 GMT</pubDate>
            <description><![CDATA[<h2 id="12-경로탐색dfs">12-경로탐색(DFS)</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/1923a56e-7cea-40cd-8575-c1436f06d5a3/image.png" alt=""></p>
<h4 id="🚩-내-코드">🚩 내 코드</h4>
<pre><code>public class 경로탐색_dfs {
    static  int n;
    static  int m;
    static  int [][] graph;
    static  int [] ch;
    static  int answer;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = Integer.parseInt(scanner.next()); // 정점 수
        m = Integer.parseInt(scanner.next()); // 간선 수
        graph = new int[n+1][n+1];
        ch = new int[n+1];
        answer = 0;

        for(int i=0; i&lt;m; i++){
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            graph[a][b] = 1;
        }
        ch[1] = 1;
        dfs(1);
        System.out.println(answer);
    }
    private static void dfs(int v) {
        if(v==n){
            answer++;
        }else{
            for(int i=1; i&lt;=n; i++){
                if(graph[v][i]==1 &amp;&amp; ch[i]==0){
                    ch[i] = 1;
                    dfs(i);
                    ch[i] = 0; // 방문체크 풀어주기
                }
            }
        }
    }
}
</code></pre><h4 id="💡-푼-방식">💡 푼 방식</h4>
<p>노드+1 만큼의 이차원배열을 만든 후, 연결되는 곳에 1을 넣는것으로 처음 설정을 해준다. (1과 3이 연결이라면 graph[1][3] = 1이렇게) 방향성이 있으므로, 꼭 첫번째꺼에서 두번째꺼 순서를 따져줘야함. (graph[3][1] = 1 이러면 방향이 반대라 안된다는 거임;;) 
숫자 1부터 시작. ch[1]에 1을 넣어주어서 방문체크.(글랜체크 아님 ㅎ~)</p>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/8eab405c-cd69-4236-a248-40bbe6cec870/image.png" alt="">
이렇게 for문으로 각 노드와 연결된 노드를 찾아주고, 또 그 노드에서 다른 노드로 연결된걸 찾아주고,, 그게 5까지 가는지 확인해야하므로 dfs를 사용하였다.</p>
<h4 id="📚-알게-된-정보">📚 알게 된 정보</h4>
<p>해당 노드를 방문체크를 하고 그 노드를 dfs넣은 후, 방문체크를 풀어줘야한다. </p>
<h2 id="12-경로탐색인접리스트">12-경로탐색(인접리스트)</h2>
<p>위와 같은 문제지만, 노드가 10000개 이렇게 들어와버리면, 행렬로 풀기에는 너무 비효율적이다. 이번엔 다른방법..으로</p>
<h4 id="🚩-내-코드-1">🚩 내 코드</h4>
<pre><code>public class 경로탐색_인접리스트 {
    static  int n;
    static  int m;
    static ArrayList&lt;ArrayList&lt;Integer&gt;&gt; graph;
    static  int [] ch;
    static  int answer;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = Integer.parseInt(scanner.next()); // 정점 수
        m = Integer.parseInt(scanner.next()); // 간선 수
        graph = new ArrayList&lt;&gt;();
        ch = new int[n+1];
        answer = 0;
        for(int i=0; i&lt;=n; i++){ 
            graph.add(new ArrayList&lt;&gt;());// 정수를 저장할 수 있는 객체 생성.
        }
        for(int i=0; i&lt;m; i++){
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            graph.get(a).add(b);
        }
        ch[1]=1;
        dfs(1);
        System.out.println(answer);

    }
    private static void dfs(int v) {
        if(v==n){
            answer++;
        }else{
            for(int nv : graph.get(v)){ // v노드에 연결된 arraylist
                if(ch[nv]==0){
                    ch[nv] = 1;
                    dfs(nv);
                    ch[nv] = 0;
                }
            }
        }
    }
}
</code></pre><h4 id="💡-푼-방식-1">💡 푼 방식</h4>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/fe7ece8c-43f0-4bb5-b563-b102aa384f2b/image.png" alt=""></p>
<p>ArrayList에 노드를 넣어주고, 그 노드에 연결된 노드 또한 넣어줘야하므로</p>
<pre><code>ArrayList&lt;ArrayList&lt;Integer&gt;&gt; graph</code></pre><p>로 생성해주었다.
위 방식으로 for문 도는거 대신에 각 노드들의 arrayList만 돌면 된다.</p>
<h4 id="📚-알게-된-정보-1">📚 알게 된 정보</h4>
<pre><code>ArrayList&lt;ArrayList&lt;Integer&gt;&gt; graph</code></pre><h2 id="13-그래프-최단-거리">13-그래프 최단 거리</h2>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/cd790006-cdc3-4972-bad3-54b8f64d05cf/image.png" alt=""></p>
<h4 id="🚩-내-코드-2">🚩 내 코드</h4>
<pre><code>public class 그래프최단거리 {
    static int n,m;
    static int[] ch,dis;
    static ArrayList&lt;ArrayList&lt;Integer&gt;&gt; graph;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = Integer.parseInt(scanner.next()); // 정점 수
        m = Integer.parseInt(scanner.next()); // 간선 수
        graph = new ArrayList&lt;&gt;();
        ch = new int[n+1];

        for(int i =0; i&lt;=n; i++){
            graph.add(new ArrayList&lt;&gt;());
        }
        for(int i=0; i&lt;m; i++){
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            graph.get(a).add(b);
        }
        bfs(1);
        for(int i=1; i&lt;dis.length; i++){
            System.out.println(dis[i]);
        }
    }

    private static void bfs(int v) {
        Queue&lt;Integer&gt; queue = new LinkedList&lt;&gt;();
        ch[v] = 1;
        dis[v] = 0;
        queue.offer(v);
        while(!queue.isEmpty()){
            int cv = queue.poll();
            for(int nv : graph.get(cv)){
                if(ch[nv] == 0){
                    ch[nv]=1;
                    queue.offer(nv);
                    dis[nv] = dis[cv]+1;
                }
            }
        }
    }
}</code></pre><h4 id="💡-푼-방식-2">💡 푼 방식</h4>
<p>최단이니까 bfs로 풀었다.
각 노드로 가는 회수는 dis배열에 넣었고, </p>
<pre><code>dis[nextnode] = dis[currentnode]+1</code></pre><p>로 회수를 세주었다.</p>
<h4 id="📚-알게-된-정보-2">📚 알게 된 정보</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘 문제풀이] HashMap]]></title>
            <link>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-HashMap</link>
            <guid>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-HashMap</guid>
            <pubDate>Mon, 08 Aug 2022 18:20:51 GMT</pubDate>
            <description><![CDATA[<h2 id="4-1-학급회장">(4-1) 학급회장</h2>
<h4 id="🚩-내-코드">🚩 내 코드</h4>
<pre><code>  Scanner scanner = new Scanner(System.in);
        int N = Integer.parseInt(scanner.nextLine());
        String [] arr = scanner.nextLine().split(&quot;&quot;);

        HashMap&lt;String, Integer&gt; hm = new HashMap&lt;&gt;();
        for(String s : arr){
            hm.put(s,hm.getOrDefault(s,0)+1);
        }
        // ✔ 방법1.
        String answer=&quot;&quot;;
        int max = Integer.MIN_VALUE;
        for(String key : hm.keySet()){
            if(hm.get(key) &gt; max){
                max = hm.get(key);
                answer=key;
            }
        }
        System.out.println(answer);

        // ✔ 방법2.
        // Collections.sort()를 사용하기 위해 List 형태로 Map을 가져와야함.
        List&lt;Map.Entry&lt;String,Integer&gt;&gt; entryList = new LinkedList&lt;&gt;(hm.entrySet());
        // 정렬 내장 함수 사용
        entryList.sort(Map.Entry.comparingByValue());
        for(Map.Entry&lt;String, Integer&gt; entry : entryList){
            //System.out.println(&quot;key: &quot;+entry.getKey()+&quot; value: &quot;+entry.getValue());
        }
</code></pre><h4 id="💡-푼-방식">💡 푼 방식</h4>
<p><strong>HashMap</strong> 사용하여 알파벳과 개수를 짝지었다.
갯수는 <strong>map.getOrDefault</strong>함수를 사용하여, 찾는 키가 존재한다면 찾는 키의 값을 반환하고 없다면 기본 값을 반환한다. 따라서 내 코드에서는 찾는키가 없다면 0을 있다면 value를 반환하고 거기에 +1을 해줌으로써 개수를 세주는거다.</p>
<h4 id="📚-알게-된-정보">📚 알게 된 정보</h4>
<p>굳이 정렬함수를 쓰지 않아도, max라는 변수를 이용하여 제일 큰 값을 찾아낼 수 있다.
정렬함수를 쓰기 위해서는 hashmap을 list형태로 변환해주어야한다.
<a href="https://developer-talk.tistory.com/395">참고</a></p>
<br/>

<h2 id="4-2-아나그램">(4-2) 아나그램</h2>
<h4 id="🚩-내-코드-1">🚩 내 코드</h4>
<pre><code>          Scanner scanner = new Scanner(System.in);
        HashMap&lt;String,Integer&gt; map1 = new HashMap&lt;&gt;();
        HashMap&lt;String,Integer&gt; map2 = new HashMap&lt;&gt;();
        String[] arr1 = scanner.nextLine().split(&quot;&quot;);
        String[] arr2 = scanner.nextLine().split(&quot;&quot;);

        for(String s : arr1){
            map1.put(s,map1.getOrDefault(s,0)+1);
        }

        String answer = &quot;YES&quot;;
        // arr1과 비교하기
        for(String s : arr2){
            if(!map1.containsKey(s) || map1.get(s) == 0) { // 키가 없거나, value값이 다르다면
                answer=&quot;NO&quot;;
                break;
            }else{
                map1.put(s, map1.get(s)-1); // 키가 같은거에서는 1빼줌 (개수 세야되니까)
            }
        }
        System.out.println(answer);

</code></pre><h4 id="💡-푼-방식-1">💡 푼 방식</h4>
<p><strong>HashMap</strong> 사용하여 알파벳과 개수를 짝지었다.
갯수는 <strong>map.getOrDefault</strong>함수를 사용하여, 찾는 키가 존재한다면 찾는 키의 값을 반환하고 없다면 기본 값을 반환한다. 따라서 내 코드에서는 찾는키가 없다면 0을 있다면 value를 반환하고 거기에 +1을 해줌으로써 개수를 세주는거다.
그리고 다음 배열에서 있는 건 -1로 해서 개수를 맞춰본다.</p>
<h4 id="📚-알게-된-정보-1">📚 알게 된 정보</h4>
<h2 id="4-3-매출액의-종류">(4-3) 매출액의 종류</h2>
<h4 id="🚩-내-코드-2">🚩 내 코드</h4>
<pre><code>           Scanner scanner = new Scanner(System.in);
        int N = Integer.parseInt(scanner.next());
        int K = Integer.parseInt(scanner.next());

        int [] arr = new int[N];
        for(int i=0; i&lt;arr.length; i++){
            arr[i] = Integer.parseInt(scanner.next());
        }
        HashMap&lt;Integer,Integer&gt; map = new HashMap&lt;&gt;();
        for(int i=0; i&lt;K; i++){
            map.put(arr[i],map.getOrDefault(arr[i],0)+1);
        }

        int size = map.size();
        System.out.print(size+&quot; &quot;);

        for(int i=0; i&lt;N-K; i++){
            map.put(arr[i],map.getOrDefault(arr[i],0)-1);
            map.put(arr[i+K],map.getOrDefault(arr[i+K],0)+1);
            if(map.get(arr[i])==0){
                map.remove(arr[i]);
            }
            System.out.print(map.size()+&quot; &quot;);
        }</code></pre><h4 id="💡-푼-방식-2">💡 푼 방식</h4>
<p><strong>HashMap</strong> 사용하여 매출액과 개수를 짝지었다.
갯수는 <strong>map.getOrDefault</strong>함수를 사용하였고, <strong>two Pointers</strong> 방식으로 따져보았다.</p>
<h4 id="📚-알게-된-정보-2">📚 알게 된 정보</h4>
<p>hashmap + two pointers</p>
<h2 id="4-5-k번째-큰-수">(4-5) K번째 큰 수</h2>
<h4 id="🚩-내-코드-3">🚩 내 코드</h4>
<pre><code>           Scanner scanner = new Scanner(System.in);
        int N = Integer.parseInt(scanner.next());
        int K = Integer.parseInt(scanner .next());
        int [] nums = new int[N];
        for(int i=0; i&lt;N; i++){
            nums[i] = Integer.parseInt(scanner.next());
        }

        // 중복 피함
        TreeSet&lt;Integer&gt; tset = new TreeSet&lt;&gt;(Collections.reverseOrder());

        //3장을 뽑는 것이므로 3중 for문
        for(int i=0; i&lt;N; i++){
            for (int j=i+1; j&lt;N; j++){
                for(int l=j+1; l&lt;N; l++){
                    tset.add(nums[i]+nums[j]+nums[l]);
                }
            }
        }
        int cnt=0;
        for(int x : tset){
            cnt++;
            if(cnt == K){
                System.out.println(x);
            }
</code></pre><h4 id="💡-푼-방식-3">💡 푼 방식</h4>
<p> <strong>3중for문</strong>을 이용하여 숫자3개를 뽑았고 그 합을 <strong>TreeSet</strong>에 넣었다.</p>
<h4 id="📚-알게-된-정보-3">📚 알게 된 정보</h4>
<p>3개를 어떻게 뽑지라고 고민했는데 그냥 3중for문을 쓰면 되는거였다.
합이 같은것이 여러개 나올 수 있는데, 중복을 제거하는 TreeSet에 넣으면 해결되었다.</p>
<p><strong>treeset</strong>
Set 인터페이스를 구현한 클래스로써 객체를 중복해서 저장할 수 없고 저장 순서가 유지되지 않는다는 Set의 성질</p>
<pre><code>TreeSet&lt;Integer&gt; set1 = new TreeSet&lt;Integer&gt;();//TreeSet생성
TreeSet&lt;Integer&gt; set2 = new TreeSet&lt;&gt;();//new에서 타입 파라미터 생략가능
TreeSet&lt;Integer&gt; set3 = new TreeSet&lt;Integer&gt;(set1);//set1의 모든 값을 가진 TreeSet생성
TreeSet&lt;Integer&gt; set4 = new TreeSet&lt;Integer&gt;(Arrays.asList(1,2,3));//초기값 지정

TreeSet&lt;Integer&gt; tset = new TreeSet&lt;&gt;(Collections.reverseOrder());</code></pre><p><a href="https://coding-factory.tistory.com/555">TreeSet 참고1</a>
<a href="https://blog.naver.com/kimstcool01/220896128159">TreeSet 참고2</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 프린터]]></title>
            <link>https://velog.io/@jr_necki/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%94%84%EB%A6%B0%ED%84%B0</link>
            <guid>https://velog.io/@jr_necki/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%94%84%EB%A6%B0%ED%84%B0</guid>
            <pubDate>Mon, 01 Aug 2022 08:06:17 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42587">문제보기</a></p>
<h2 id="🚩-내-코드">🚩 내 코드</h2>
<pre><code>import java.util.LinkedList;
import java.util.Queue;

public class Solution {
    class Task{
        int location;
        int priority;
        public Task(int location, int priority) {
            this.location = location;
            this.priority = priority;
        }
    }
    public int solution(int[] priorities, int location) {
        int answer = 0;

        Queue&lt;Task&gt; queue = new LinkedList&lt;&gt;();

        for(int i=0; i&lt;priorities.length; i++){
            queue.add(new Task(i, priorities[i]));
        }

        int now=0;
        while(!queue.isEmpty()){
            Task cur = queue.poll();
            boolean flag = false;
            for(Task t : queue){
                if(t.priority&gt;cur.priority){
                    flag = true;
                }
            }
            if(flag) { // 우선순위 높은게 있으면 뒤로 보낸다
                queue.add(cur);
            }else{
                now++;
                if(cur.location == location) {
                    answer = now;
                    break;
                }

            }
        }
        return answer;
    }
}</code></pre><h2 id="💡-푼-방식">💡 푼 방식</h2>
<p>대기 목록을 task라는 클래스를 생성하여 큐에 넣었고, 클래스는 우선 순위와 위치 변수를 가졌다.
문제 그대로, 큐를 돌려서 해당 task가 큐안에 있는 task와 우선순위를 비교하여 우선순위가 높은 것이 있다면 뒤로 보냈다. 그렇지 않다면 위치를 확인하여 문제가 원하는 위치였던 task였으면 그것이 답이다.</p>
<h2 id="📚-알게-된-정보">📚 알게 된 정보</h2>
<h4 id="priorityqueue">PriorityQueue</h4>
<p>Queue 인터페이스의 구현체 중 하나, 저장 순서와 상관 없이 우선순위가 높은 것부터 꺼내진다.
<br/></p>
<pre><code>PriorityQueue&lt;Integer&gt; queue = new PriorityQueue&lt;&gt;(Collections.reverseOrder()); // 이건 반대로</code></pre><p><strong>우선순위가 높은 것부터 꺼낸다</strong> 지, 우선순위가 높은 순으로 보관한다는 뜻이 아니다.
따라서 PriorityQueue를 그대로 출력했을 때와 실제로 요소를 하나씩 출력했을 때 표시되는 순서에는 차이가 있을 수 있다.</p>
<pre><code>for(int priority:priorities){
    queue.offer(priority);
}

// 기존 배열에서 일치하는 문서 찾기
while(!queue.isEmpty()){
    for(int i=0; i&lt;priorities.length; i++){
        if(queue.peek() == priorities[i]){
            if(i==location){
                return answer;
            }
            answer++;
            queue.poll();
        }
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘 문제풀이] two pointers]]></title>
            <link>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-two-pointers</link>
            <guid>https://velog.io/@jr_necki/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B4-two-pointers</guid>
            <pubDate>Sun, 31 Jul 2022 07:26:56 GMT</pubDate>
            <description><![CDATA[<h3 id="1-2-공통원소-구하기">(1-2) 공통원소 구하기</h3>
<p><strong>🚩 내 코드</strong></p>
<pre><code>         Arrays.sort(a);
        Arrays.sort(b);

        int p1=0;
        int p2=0;
        ArrayList&lt;Integer&gt;al = new ArrayList&lt;&gt;();

        while (p1&lt;n &amp;&amp; p2&lt;m){
            int i1 = Integer.parseInt(a[p1]);
            int i2 = Integer.parseInt(b[p2]);

            if(i1 &gt; i2){
                p2++;
            }else if(i1 &lt; i2){
                p1++;
            }else{
                al.add(i1);
                p1++;
                p2++;
            }
        }
        for(int i : al){
            System.out.print(i+&quot; &quot;);
        }</code></pre><br/>

<p><strong>💡 푼 방식</strong>
두 배열을 오름차순으로 정렬
그리고 0인덱스부터 둘을 비교한다.
a배열 요소가 더 크다면 b배열 인덱스를 +1 (그래야 b가 커지므로)
b배열 요소가 더 크다면 a배열 인덱스를 +1
같다면 정답 배열에 추가 후 a,b배열 인덱스 모두 +1해준다.</p>
<br/>

<p><strong>📚 알게 된 정보</strong>
시간복잡도가 nlogn
그리고 공통원소를 찾는 과정을 O(n)</p>
<p>전체적으로는 시간복잡도는 O(nlogn)</p>
<p><br/><br/></p>
<h3 id="1-3-최대매출">(1-3) 최대매출</h3>
<p><strong>🚩 내 코드</strong></p>
<pre><code>          int N = Integer.parseInt(arr[0]);
        int K = Integer.parseInt(arr[1]);
        int [] days = new int[N];
        for(int i=0; i&lt;N; i++){
            int money = scanner.nextInt();
            days[i] = money;
        }

        ArrayList&lt;Integer&gt; al = new ArrayList&lt;&gt;();
        int sum=0;
        int i=0;
        for(i=0; i&lt;K; i++){
            sum+= days[i];
        }
        al.add(sum);
        for(int j=i; j&lt;N; j++){
            sum-= days[j-K];
            sum+=days[j];
            al.add(sum);
        }
        Collections.sort(al);
        System.out.println(al.get(al.size()-1));</code></pre><br/>

<p><strong>💡 푼 방식</strong>
<img src="https://velog.velcdn.com/images/jr_necki/post/208cacfc-f4ae-4106-a479-fd54bcafa6a1/image.png" alt=""></p>
<p>먼저 k만큼의 요소를 더해서 arraylist에 넣는다.
그 뒤로 k만큼의 요소를 다시 계산해서 나아가는게 아니라
이미 계산한 값 sum에서 1번을 빼고 2번을 더해준다.</p>
<br/>

<p><strong>📚 알게 된 정보</strong>
기존값에서 변화량만 적용시켜주면
같은 행위를 반복하지 않아도 된다.
<br/></p>
<h3 id="1-4-연속부분수열">(1-4) 연속부분수열</h3>
<p><strong>🚩 내 코드</strong></p>
<pre><code>package two_pointers_sliding_window;
import java.util.Scanner;
public class 연속부분수열 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] arr = scanner.nextLine().split(&quot; &quot;);
        int n = Integer.parseInt(arr[0]);
        int m = Integer.parseInt(arr[1]);
        int [] numbers = new int[n];

        for(int i=0; i&lt;n; i++){
            numbers[i] = scanner.nextInt();
        }

        int sum = 0;
        int lt = 0;
        int ans = 0;

        for(int rt=0; rt&lt;n; rt++){
            sum+=numbers[rt];
            if(sum == m){
                ans++;
            }
            while (sum &gt;= m ){
                sum-=numbers[lt++];
                if(sum == m){
                    ans++;
                }
            }
        }
        System.out.println(ans);
    }
}
</code></pre><br/>

<p><strong>💡 푼 방식</strong>
<img src="https://velog.velcdn.com/images/jr_necki/post/c73154a2-87f0-4ff8-ac5c-3c9e86c21f86/image.png" alt="">
for문으로 rt는 0부터해서 sum이 m이 될때까지 더한다.
만약 sum==m이면 answer++
그 후, while 문을 통해 lt가 가리키는 요소를 빼주고 lt는 한칸 오른쪽으로 가게 한다.
즉 rt는 for문으로 1씩 증가, 그 와중에 lt는 값을 비교하며 위치 변경</p>
<br/>

<p><strong>📚 알게 된 정보</strong>
two pointers알고리즘은 
O(n^2)을 O(n)으로 바꿔주는 역할을 한다.
따라서 입력값이 엄청 클 때 사용하면 좋을듯..?!</p>
<h3 id="1-5-연속된-자연수의-합">(1-5) 연속된 자연수의 합</h3>
<p><strong>🚩 내 코드</strong></p>
<pre><code>         Scanner scanner = new Scanner(System.in);
        int n = Integer.parseInt(scanner.nextLine());

        int lt = 0;
        int ans = 0;
        int sum = 0;
        int m = n/2+1;
        int[] arr = new int[m];

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

        for(int rt=0; rt&lt;m;  rt++){
            sum+=arr[rt];
            if(sum == n){
                ans++;
            }
            while(sum &gt;= n){
                sum-=arr[lt++];
                if(sum == n){
                    ans++;
                }
            }
        }
        System.out.println(ans);
</code></pre><br/>

<p><strong>💡 푼 방식</strong>
배열로 각 숫자를 넣어주고, lt rt를 활용한 위의 방법과 같다. </p>
<br/>

<p><strong>📚 알게 된 정보</strong>
수학적으로 접근할 수도 있다.
<img src="https://velog.velcdn.com/images/jr_necki/post/4ce2f637-049a-4568-a101-5f5104e24138/image.png" alt=""></p>
<pre><code>           Scanner scanner = new Scanner(System.in);
        int n = Integer.parseInt(scanner.nextLine());
        int ans = 0;
        int cnt = 1;
        n--; // 여기서 1 뺐고
        while(n&gt;0){
            cnt++; //2돼서
            n=n-cnt; // 1과 2를 n에서 뺌.
            if(n%cnt == 0) ans++;
        }// cnt가 증가되고 빼지는 수도 계속 누적 됨.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘 문제풀이]-String]]></title>
            <link>https://velog.io/@jr_necki/Alogorithm-String</link>
            <guid>https://velog.io/@jr_necki/Alogorithm-String</guid>
            <pubDate>Mon, 25 Jul 2022 14:39:07 GMT</pubDate>
            <description><![CDATA[<h2 id="1-5-특정문자-뒤집기">(1-5) 특정문자 뒤집기</h2>
<p>(푸는중임)</p>
<h4 id="🚩-내-코드">🚩 내 코드</h4>
<h4 id="💡-푼-방식">💡 푼 방식</h4>
<p><img src="https://velog.velcdn.com/images/jr_necki/post/a388101c-d6bd-4b2f-aed8-27961c7a1412/image.png" alt="">
rt lt 둘다 알파벳일때 서로 위치를 바꿀 수 있다.
만약 rt가 가르키는 곳이 알파벳이 아니라면 한칸 이동 (lt일 경우에도)
rt가 lt보다 크지 않을 때까지 반복한다.</p>
<h4 id="📚-알게-된-정보">📚 알게 된 정보</h4>
<h2 id="1-8-유효한-팰린드롬">(1-8) 유효한 팰린드롬</h2>
<h4 id="🚩-내-코드-1">🚩 내 코드</h4>
<pre><code>Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        // 대소문자 구분 없으므로 모두 대문자로 변환
        // 정규식 사용 (replaceAll만 정규식 사용가능)
        // 대문자 A-Z까지가 아니면
        str = str.toUpperCase().replaceAll(&quot;[^A-Z]&quot;,&quot;&quot;);

        String tmp = new StringBuilder(str).reverse().toString();
        if(str.equals(tmp)){
            System.out.println(&quot;YES&quot;);
        }else{
            System.out.println(&quot;NO&quot;);
        }</code></pre><h4 id="💡-푼-방식-1">💡 푼 방식</h4>
<p>오로지 알파벳만,대소문자 구분x 라는 규칙이 있으므로, 주어진 문자열을 모두 대문자로 전환했다.
<strong>replaceAll</strong>과 <strong>정규식</strong>을 사용해 알파벳이외의 문자는 &quot;&quot;이거로 처리했다.
<strong>stringBuilder</strong>로 거꾸로 해서 기존 문자열과 비교했다.</p>
<h4 id="📚-알게-된-정보-1">📚 알게 된 정보</h4>
<li>replaceAll<br/>
replaceAll을 사용할때 '알파벳이 아닌것'을 어떻게 표현하지? 했는데
정규식을 이용하면 됐었다.<br/>
정규식은 따로 정리해야지.....헤헤
<li> StringBuilder <br/>
일단 StringBuilder를 쓰는 이유는 상대적으로 빠른 속도와 적은 부하이다.<br/>
String 객체와 String객체를 더하는것은 새로운 String 객체를 생성하므로 메모리 할당과 해제가 발생한다.<br/>
StringBuilder는 문자열을 더할 때 기존의 것에다가 더하는 방식이기 때문에 위의 장점이 있다.


<pre><code>StringBuilder sb = new StringBuilder(&quot;abc&quot;);
sb.append(&quot;def&quot;);
System.out.print(sb.toString()); // 출력하기 위해선 string으로 해준다.
System.out.print(sb.reverse.toString())); // 거꾸로</code></pre><h2 id="1-12-암호">(1-12) 암호</h2>
<h4 id="🚩-내-코드-2">🚩 내 코드</h4>
<pre><code>for(int i=0; i&lt;arr.length; i++){
            if(arr[i].equals(&quot;#&quot;)){
                binary += &quot;1&quot;;
            }else{
                binary+=&quot;0&quot;;
            }
        }
        String ans=&quot;&quot;;
        for(int i=0; i&lt;n; i++){
            String ascii = binary.substring(i*7,(i*7)+7);
            System.out.print((char)Integer.parseInt(ascii,2));
        }</code></pre><h4 id="💡-푼-방식-2">💡 푼 방식</h4>
<p>암호를 문자배열로 받고 0과1로 바꿔준다. 
(<strong>replaceAll</strong>로 하려 했지만, *&lt;-이거에서 좀 이상해져서 일일이 바꿔줬다..)</p>
<p><strong>substring</strong>을 사용하여 7개씩 n번 나눠주고 
Integer.parseInt()로 2진수를 10진수로 바꾸어준다.
숫자를 해당 아스키코드로 출력해준다.</p>
<h4 id="📚-알게-된-정보-2">📚 알게 된 정보</h4>
<li> substring(n) : 0~n-1번쨰까지 잘라준다.
<li> Integer.parseInt("문자열",n) : n진법을 10진법으로 전환 ]]></description>
        </item>
    </channel>
</rss>