<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>cologic.log</title>
        <link>https://velog.io/</link>
        <description> 알고리즘과 데이터 과학과 웹 개발을 공부하는 대학생</description>
        <lastBuildDate>Wed, 15 Feb 2023 05:33:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>cologic.log</title>
            <url>https://velog.velcdn.com/images/tino-kim/profile/5817507c-82ed-4990-b027-814d4916a17b/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. cologic.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/tino-kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[기술 블로그 이전] Velog에서 Tistory로]]></title>
            <link>https://velog.io/@tino-kim/%EA%B8%B0%EC%88%A0-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84-Velog%EC%97%90%EC%84%9C-Tistory%EB%A1%9C</link>
            <guid>https://velog.io/@tino-kim/%EA%B8%B0%EC%88%A0-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84-Velog%EC%97%90%EC%84%9C-Tistory%EB%A1%9C</guid>
            <pubDate>Wed, 15 Feb 2023 05:33:39 GMT</pubDate>
            <description><![CDATA[<p>velog에서 tistory로 기술 블로그를 이전하였다.</p>
<p>왜 갑자기 블로그를 이전하는가? 여러 가지 이유가 있다.</p>
<p>첫째, 데이터 분석가로서 커리어를 쌓고 싶은데 너무 블로그가 전문성 없어보이고 지저분하다. 처음 기술 블로그를 시작할 때 루틴을 만들고 싶었다. 그러다 보니 여러 가지에 대하여 블로그를 작성하게 되었고, 어느 순간 돌아보니 내가 어떤 것을 하고 싶은지에 대하여 제대로 알기 어려워졌다. 내가 쓴 블로그인데 어떤 것을 중점적으로 써내려간 것인지 알기가 힘들어져서 옮기게 되었다.</p>
<p>둘째, 잘못된 정보가 너무 많다. 유튜브와 medium을 통하여 알게된 사실인데 요즘 기술 블로그로 인하여 잘못된 정보가 남발되고 있다고 한다. 처음에는 그러려니 했는데, 계속 공부하고 머리에 든 게 늘어날 수록 나도 그 사람들 중에서 하나라는 사실을 깨닫게 되었다. 이번 블로그에서는 섣부르게 블로그를 작성하지 않고, 정확한 정보 위주로 작성할 계획이다.</p>
<p>셋째, 카테고리 별로 정리하고 싶어서 tistory로 들어왔다. velog는 태그 별로 정리를 하는데 내가 한 가지 게시물에 여러 가지 태그를 넣다 보니, 글이 어디에 있는지 알기 매우 힘들었다.</p>
<p>이러한 이유들로 기술 블로그를 이전하게 되었다. 남은 1년 간 데이터 분석과 + alpha 에 대하여 작성할 계획이다. </p>
<p>새로운 기술 블로그 주소 : <a href="https://tinokim.tistory.com/">데이터 분석을 배우세요</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[도전 4] 1차원 배열]]></title>
            <link>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-4-1%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-4-1%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Tue, 07 Feb 2023 07:27:05 GMT</pubDate>
            <description><![CDATA[<h1 id="도전-4-1차원-배열">[도전 4] 1차원 배열</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[[도전 3] 반복문]]></title>
            <link>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-3-%EB%B0%98%EB%B3%B5%EB%AC%B8</link>
            <guid>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-3-%EB%B0%98%EB%B3%B5%EB%AC%B8</guid>
            <pubDate>Sun, 29 Jan 2023 11:40:59 GMT</pubDate>
            <description><![CDATA[<h1 id="도전-3-반복문">[도전 3] 반복문</h1>
<h2 id="주의할-점-1-반복문에서-반드시-변수-이용-no">주의할 점 1. 반복문에서 반드시 변수 이용? No!</h2>
<p>필요하지 않으면 굳이 변수를 이용할 이유가 없다. <strong>그저 돌리는 횟수로 반복문을 이용 가능하다.</strong> 예를 들면, 입력하는 수 만큼 변수를 입력받을 수 있다.</p>
<pre><code>n=int(input())
for _ in range(n): # n회 만큼 변수 입력 받기. 
    price, count=map(int, input().split())</code></pre><h2 id="주의할-점-2-input-대신-데이터-입력-받기">주의할 점 2. input 대신 데이터 입력 받기.</h2>
<p>sys의 stdin은 <strong>대화형 입력</strong>에 사용된다. input와 같은 기능을 수행하기 때문에, 대신 이용 가능하다. </p>
<pre><code>import sys
a, b=map(int, sys.stdin.readline().split()) # 변수 2개 이상인 경우
c=int(sys.stdin.readline()) # 변수 1개인 경우</code></pre><h2 id="주의할-점-3-별찍기">주의할 점 3. 별찍기.</h2>
<p>오른쪽부터 시작하여 별 1개에서 5개까지 찍는 경우, 별의 개수 1부터 5를 맞추기 위하여 n을 지정하고, 조건에 맞게 띄어쓰기를 n을 이용하여 조정해주면 된다. 이 때, 출력 형식이 잘 맞는지 꼭 확인하기.</p>
<pre><code>n=int(input())
for _ in range(n):
    print(&quot; &quot;*(n-1-_) + &quot;*&quot;*(_+1))</code></pre><h2 id="주의할-점-4-예외-처리하기">주의할 점 4. 예외 처리하기.</h2>
<p>코드 실행 시 에러가 발생하는 경우에 코드 멈춰 주기. (무한 반복문에서 유용하게 쓰일 수 있다.)</p>
<pre><code>try:
    실행할 코드
except:
    예외가 발생했을 때 처리하는 코드</code></pre><pre><code>## 무한 반복문에서 사용하기

while True:
    try:
        실행할 코드
    except:
        예외가 발생했을 때 처리하는 코드</code></pre><h2 id="5-주의할-점-5-무한-반복문에서-데이터-계속-갱신하기">5. 주의할 점 5. 무한 반복문에서 데이터 계속 갱신하기.</h2>
<p>(예시) 1110번 : 더하기 사이클</p>
<p>위의 문제와 같이 조건이 많은 경우에는 <strong>수도코드로 조건을 나열한 뒤에</strong> 코드를 직접 짜보기.</p>
<pre><code># 0보다 작은 경우 앞에 0 붙여서 2자리 수 만들기
# 26 -&gt; 2+6=8, 68 -&gt; 6+8=14, 84 -&gt; 8+4=12, 42 -&gt; 4+2=6, 26 (4)
# num1+num2=(num1+num2), num2+(num1+num2)[-1]

# 55 -&gt; 5+5=10, 50 -&gt; 5+0=5, 05 -&gt; 0+5=5, 55 (3)
# 1 -&gt; 0+1=1, 11 -&gt; 1+1=2, 12 -&gt; 1+2=3, 13 -&gt; ... -&gt; 1 (60)
# 0 -&gt; 0+0=0, 0 (1)
# 71 -&gt; 7+1=8, 18 =&gt; 1+8=9, 89 =&gt; 8+9=17, 97 -&gt; ... -&gt; 71 (12)

# 1. 10 미만인 경우에는 앞에 0을 붙여주고 서로 더해주기, 새로운 숫자 등장
# 2. 새로운 숫자 등장</code></pre><p>위와 같이 수도코드를 짜고 어떤 값들이 계속적으로 갱신해야 하는지 확인하고, 변수로 만들어줘서 계속 갱신해주기.</p>
<p>num1, num2가 계속 갱신 되면서 이로 인해 새로운 n이 생성된다. 새로운 n은 num2+(num1+num2)[-1] 값을 가지고 있다. 원래의 n은 나중의 새로운 n과 비교해야 하기 때문에, 값이 없어지지 않게 주의해야 한다.</p>
<pre><code>n=input()
if int(n)&lt;10:
    n=n.zfill(2) # 10보다 작은 경우에 앞에 0 붙여주기.
new_n=n
result=0

while True:
    num1=new_n[0]
    num2=new_n[1]
    small_sum=str(int(num1)+int(num2))
    new_n=num2+small_sum[-1]
    result+=1

    if n==new_n:
        break

print(result)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[도전 2] 조건문]]></title>
            <link>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-2-%EC%A1%B0%EA%B1%B4%EB%AC%B8</link>
            <guid>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-2-%EC%A1%B0%EA%B1%B4%EB%AC%B8</guid>
            <pubDate>Fri, 27 Jan 2023 15:02:19 GMT</pubDate>
            <description><![CDATA[<h1 id="도전-2-조건문">[도전 2] 조건문</h1>
<h2 id="주의할-점-1-파이썬은-위에서-아래로-실행된다">주의할 점 1. 파이썬은 위에서 아래로 실행된다.</h2>
<p>(예시) 2480번 : 주사위 세개</p>
<p>위에서 아래로 수행되기 때문에, 3개 모두 같은 경우 -&gt; 2개 같은 경우 -&gt; 모두 다른 경우 순서로 코드를 짰다.</p>
<pre><code># 더 짧게 코드를 작성하기.

D1, D2, D3=map(int, input().split())

def reward(D1, D2, D3):
    if D1==D2==D3:
        return 10000+D1*1000
    elif (D1==D2) or (D1==D3):
        return 1000+D1*100
    elif D2==D3:
        return 1000+D2*100
    else:
        return max(D1, D2, D3)*100

print(reward(D1, D2, D3))</code></pre><p><del>이게 왜 틀린 풀이인지 잘 모르겠다.</del></p>
<p>else 뒤에는 어떤 조건도 올 수 없다. else 자체가 위의 조건을 뺀 나머지 모든 경우를 지칭하기 때문에 바로 <strong>수행되는 코드가 나온다.</strong> 그래서 <strong>else 뒤에 if와 elif 조건을 넣어줄 수 없다.</strong></p>
<pre><code>## 틀린 풀이 : else 뒤에 또 조건이 나올 수 없다.
# 같은 눈 3개 -&gt; 1000 + 같은 눈 x 1000
# 같은 눈 2개 -&gt; 1000 + 같은 눈 x 100
# 모두 다른 눈 -&gt; 제일 큰 눈 x 100

D1, D2, D3=map(int, input().split())

def reward(D1, D2, D3):
    if D1==D2==D3:
        return 10000+D1*1000
    elif D1!=D2!=D3:
        return max(D1, D2, D3)*100
    else: # 같은 눈이 2개인 경우
        if (D1==D2) or (D1==D3):
            return 1000+D1*100
        elif D2==D3:
            return 1000+D2*100

print(reward(D1, D2, D3))</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[도전 1] 입출력과 사칙연산]]></title>
            <link>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-1-%EC%9E%85%EC%B6%9C%EB%A0%A5%EA%B3%BC-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0</link>
            <guid>https://velog.io/@tino-kim/%EB%8F%84%EC%A0%84-1-%EC%9E%85%EC%B6%9C%EB%A0%A5%EA%B3%BC-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0</guid>
            <pubDate>Fri, 27 Jan 2023 13:54:26 GMT</pubDate>
            <description><![CDATA[<h1 id="도전-1-입출력과-사칙연산">[도전 1] 입출력과 사칙연산</h1>
<h2 id="주의할-점-1-입력을-어떻게-받는지-잘-체크하기">주의할 점 1. 입력을 어떻게 받는지 잘 체크하기.</h2>
<p>어떤 경우는 한 줄에 여러 개를 받기도 하고, 어떤 경우는 한 줄에 한 개의 변수를 받기도 한다. 그런 것들을 잘 확인하고 코드를 짜야한다.</p>
<pre><code># 한 줄에 여러 변수 받기.
A,B,C=map(int, input().split())

# 한 줄에 하나의 변수 받기.
A=int(input())
B=input()</code></pre><h2 id="주의할-점-2-규칙-찾을-때-여러-숫자-대입해보기">주의할 점 2. 규칙 찾을 때, 여러 숫자 대입해보기.</h2>
<p>(예시) 3003번 : 킹, 퀸, 룩, 비숍, 나이트, 폰</p>
<p>처음에는 경우를 나누어서 생각을 했다. 그런데 경우를 나누고 여러 숫자를 대입하면서 살펴 보니, 규칙이라고는 별거 없었다. (대입해보면 생각보다 별거 없는 규칙이 나올 수도 있다는 점을 알아두기.)</p>
<pre><code># 처음에는 함수로 표현했지만, 별거 없어서 그냥 출력할 때에 데이터 조작했다.
print(1-k, 1-q, 2-l, 2-b, 2-n, 8-p)</code></pre><h2 id="주의할-점-3-이스케이프-문자">주의할 점 3. 이스케이프 문자</h2>
<ul>
<li>백슬래시 자체를 표기하고 싶은 경우에는 백슬래시를 2번 적어주면 된다.</li>
<li>작은 따옴표나 큰 따옴표를 표기하고 싶은 경우에는 백슬래시를 적고, 그 뒤에 표기하면 된다. 그리고 문자열로 감싸는 경우 작은 따옴표 또는 큰 따옴표끼리 겹치는 상황을 만들면 안 된다.</li>
</ul>
<p>이를 통하여 고양이, 강아지, 새싹 그림을 그릴 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[❌ [그리디 16] 잃어버린 괄호]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-16-%EC%9E%83%EC%96%B4%EB%B2%84%EB%A6%B0-%EB%B3%B4%EB%AC%BC</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-16-%EC%9E%83%EC%96%B4%EB%B2%84%EB%A6%B0-%EB%B3%B4%EB%AC%BC</guid>
            <pubDate>Mon, 23 Jan 2023 06:59:06 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-16-잃어버린-괄호">[그리디 16] 잃어버린 괄호</h1>
<h2 id="최적의-일반화">최적의 일반화</h2>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>(1) 문제
세준이는 양수와 +, -, 그리고 괄호를 가지고 식을 만들었다. 그리고 나서 세준이는 괄호를 모두 지웠다. 그리고 나서 세준이는 괄호를 적절히 쳐서 이 식의 값을 최소로 만들려고 한다.
괄호를 적절히 쳐서 이 식의 값을 최소로 만드는 프로그램을 작성하시오.</p>
<p>(2) 입력
첫째 줄에 식이 주어진다. 식은 ‘0’~‘9’, ‘+’, 그리고 ‘-’만으로 이루어져 있고, 가장 처음과 마지막 문자는 숫자이다. 그리고 연속해서 두 개 이상의 연산자가 나타나지 않고, 5자리보다 많이 연속되는 숫자는 없다. 수는 0으로 시작할 수 있다. 입력으로 주어지는 식의 길이는 50보다 작거나 같다.</p>
<p>(3) 출력
첫째 줄에 정답을 출력한다.</p>
<h3 id="2-문제-풀이하기">2. 문제 풀이하기.</h3>
<p>알고리즘은 거의 유사하게 접근했지만, 코드 구현을 못 하고 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 15] 보물]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-15-%EB%B3%B4%EB%AC%BC</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-15-%EB%B3%B4%EB%AC%BC</guid>
            <pubDate>Thu, 19 Jan 2023 15:27:04 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-15-보물">[그리디 15] 보물</h1>
<h2 id="최적의-일반화">최적의 일반화</h2>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>(1) 문제
옛날 옛적에 수학이 항상 큰 골칫거리였던 나라가 있었다. 이 나라의 국왕 김지민은 다음과 같은 문제를 내고 큰 상금을 걸었다.</p>
<p>길이가 N인 정수 배열 A와 B가 있다. 다음과 같이 함수 S를 정의하자.</p>
<p>S = A[0] × B[0] + ... + A[N-1] × B[N-1]</p>
<p>S의 값을 가장 작게 만들기 위해 A의 수를 재배열하자. 단, B에 있는 수는 재배열하면 안 된다.</p>
<p>S의 최솟값을 출력하는 프로그램을 작성하시오.</p>
<p>(2) 입력
첫째 줄에 N이 주어진다. 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어진다. N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거나 같은 음이 아닌 정수이다.</p>
<p>(3) 출력
첫째 줄에 S의 최솟값을 출력한다.</p>
<blockquote>
<p>S의 최솟값을 구하는 문제이기 때문에 탐욕법을 이용하면 된다. 그래서 그리디 문제이다.</p>
</blockquote>
<h3 id="2-문제-해결하기">2. 문제 해결하기.</h3>
<p><strong><em>물론 이 방법은 문제의 조건을 무시했기 때문에, 옳은 풀이는 아니다.</em></strong>
A를 오름차순으로 정렬하고 B를 내림차순으로 정렬하면 최솟값을 구할 수 있다.
아래의 예제를 보면 이해할 수 있을 것이다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/fcfdd7f5-5cc2-4a62-a899-ab6b4b12706f/image.png" alt=""></p>
<pre><code># 최적의 일반화 : 하지만, B를 정렬하면 안된다고 하였으니, 이 방법은 옳은 방법은 아니다.

N=int(input())
A=list(map(int, input().split()))
B=list(map(int, input().split()))
A.sort()
B.sort(reverse=True)

result=0
for idx in range(N):
    result+=A[idx]*B[idx]

print(result)</code></pre><p><strong>*문제의 조건에 맞게 *</strong> B를 정렬하지 않고 구할 수도 있다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/104e7286-0bc1-4826-9bb3-fe71d91ef3d6/image.png" alt=""></p>
<p>B 전체를 계속 돌리면서, B와 맞는 A를 골라주면 된다. B가 가장 작을 때, A는 가장 커야 된다. 그래야 S가 최소가 될 것이다.</p>
<p>Step 1. A를 내림차순으로 정렬하고, B를 무한 반복문을 이용하여 계속 돌린다.
Step 2. 기준이 되는 B를 고른다. (기준을 B의 첫 번째 인덱스의 값이라고 두자.)
Step 3. 가장 작은 B를 찾아준다.
Step 4. 그 B를 A의 첫 번째 요소와 곱해서 더해준다. 그 값은 result (즉 S) 라고 둔다.
Step 5. 이미 정해진 A의 요소와 B의 요소를 없애기 위하여 pop, remove를 이용한 뒤에 A,B를 새롭게 갱신해준다.
Step 6. N이 1이 되는 시점에서 종료한다. <strong>종료 조건은 반복문이 시작하기 전에 넣어야 런타임 에러(IndexError)가 뜨지 않는다.</strong></p>
<p><strong>주의할 점은 알고리즘에서의 위치와 실제 코드의 위치를 같게 해야된다는 점이다. 코드의 위치가 달라지면 의미가 달라지기 때문에, 원하는 값이 나오지 않을 수가 있기 때문이다.</strong></p>
<p>주석을 단 부분은 내가 실수한 부분이기 때문에 잘 봐두자!</p>
<pre><code># 최적의 일반화

N=int(input()) # 50보다 작거나 같은 자연수
A=list(map(int, input().split())) # 각 요소는 100보다 작거나 같은 음이 아닌 정수
B=list(map(int, input().split()))
A.sort(reverse=True) # 내림차순 정렬하기. 

result=0

while True:
    init_min=B[0] # 위치 중요하다.
    # 무한 반복문 밖에 두면 계속 init_min=1일 수 밖에 없다.
    if N==1: # 종료 조건을 위로 올려주기.
        result+=A[0]*B[0]
        break
    for idx in range(N):
        if init_min&lt;=B[idx]:
            continue
        else:
            init_min=B[idx]
    result+=A[0]*init_min # 위치 중요하다.
    # A 날린 후에 0번째 곱해주면 다른 값이 나오기 때문이다.
    A.pop(0)
    B.remove(init_min)
    N-=1

print(result)</code></pre><h3 id="3-리스트-요소를-제거하는-함수들">3. 리스트 요소를 제거하는 함수들</h3>
<ul>
<li>pop() : 리스트에서 인덱스를 이용하여 요소 제거하기. <strong>제거되는 값 반환 O</strong></li>
</ul>
<pre><code>fruits = [&#39;orange&#39;, &#39;apple&#39;, &#39;pear&#39;, &#39;banana&#39;, &#39;kiwi&#39;, &#39;apple&#39;, &#39;banana&#39;]
fruits.pop() # 제거되는 요소가 반환된다. 마지막 요소가 제거된다.
fruits

fruits = [&#39;orange&#39;, &#39;apple&#39;, &#39;pear&#39;, &#39;banana&#39;, &#39;kiwi&#39;, &#39;apple&#39;, &#39;banana&#39;]
fruits.pop(1) # 제거되는 요소가 반환된다. 인덱스 1 위치인 apple이 제거된다.
fruits</code></pre><ul>
<li>remove() : 리스트에서 지정된 값을 이용하여 요소 제거하기.</li>
</ul>
<pre><code>## 단, 값이 여러 개인 경우에는 첫 번째 위치의 요소 제거하기.
l=[1,2,3]
l.remove(1)
l

## 단, 값이 여러 개인 경우에는 첫 번째 위치의 요소 제거하기.
l=[1,1,1,2,3,4,4,5]
l.remove(4)
print(l)
l.remove(1)
print(l)</code></pre><ul>
<li>del : 리스트에서 인덱스를 이용하여 요소 제거하기. <strong>제거되는 값 반환 X</strong></li>
</ul>
<pre><code>## pop은 값은 반환하지만, del은 값을 반환하지 않는다. 
a = [-1, 1, 66.25, 333, 333, 1234.5]
del a[0]
print(a)
del a[2:4]
print(a)
del a[:]
print(a)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[❌ [그리디 14] 회의실 배정]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-14-%ED%9A%8C%EC%9D%98%EC%8B%A4-%EB%B0%B0%EC%A0%95</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-14-%ED%9A%8C%EC%9D%98%EC%8B%A4-%EB%B0%B0%EC%A0%95</guid>
            <pubDate>Thu, 19 Jan 2023 14:11:45 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-14-회의실-배정">[그리디 14] 회의실 배정</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Postgresql] 설치 오류 해결하기]]></title>
            <link>https://velog.io/@tino-kim/Postgresql-%EC%84%A4%EC%B9%98-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@tino-kim/Postgresql-%EC%84%A4%EC%B9%98-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Wed, 18 Jan 2023 17:30:04 GMT</pubDate>
            <description><![CDATA[<h1 id="postgresql-설치-오류-해결하기">[Postgresql] 설치 오류 해결하기</h1>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/a6461622-3704-4b93-9382-25e42f444a37/image.png" alt=""></p>
<p>이상한 에러가 떴다.</p>
<h2 id="1---install_runtimes-0-옵션-주기">1. --install_runtimes 0 옵션 주기.</h2>
<p>cmd에서 --install_runtimes 0 옵션 줘서 설치하는 방법이지만 에러가 떴다.</p>
<h2 id="2-administrator-account-활성화시키기">2. Administrator account 활성화시키기.</h2>
<p>cmd를 관리자 실행으로 열어야 된다. 그냥 열면 명령어가 막힌다.</p>
<ul>
<li>runas /user:계정명 프로그램명</li>
</ul>
<pre><code>et user administrator /active:yes
net user administrator * 
# 암호를 입력한다.
runas /user:administrator postgresql-15.1-1-windows-x64
# 에러가 뜬다.
# 경로를 복사하여 붙여 넣어봤다.
runas /user:administrator &quot;C:\Users\ajouu\Downloads\postgresql-15.1-1-windows-x64.exe&quot;
# 에러가 뜬다.</code></pre><p>계속 에러가 떴다.</p>
<h2 id="3-다른-공식-링크에서-다운로드-받기">3. 다른 공식 링크에서 다운로드 받기.</h2>
<ul>
<li>참고 문서 : <a href="https://superuser.com/questions/1475822/postgresql-install-fail-in-windows-10-icacls-error-access-denied">postgresql install fail in windows 10 || stackoverflow</a></li>
</ul>
<p>이제서야 다운로드가 진행되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 13] 동전 0]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-13-%EB%8F%99%EC%A0%84-0.ipynb</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-13-%EB%8F%99%EC%A0%84-0.ipynb</guid>
            <pubDate>Tue, 17 Jan 2023 03:29:15 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-13-동전-0">[그리디 13] 동전 0</h1>
<h2 id="최적의-일반화">최적의 일반화</h2>
<p>정답 비율 : 51.828%</p>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>(1) 문제
준규가 가지고 있는 동전은 총 N종류이고, 각각의 동전을 매우 많이 가지고 있다.</p>
<p>동전을 적절히 사용해서 그 가치의 합을 K로 만들려고 한다. 이때 필요한 동전 개수의 최솟값을 구하는 프로그램을 작성하시오.</p>
<p>(2) 입력
첫째 줄에 N과 K가 주어진다. (1 ≤ N ≤ 10, 1 ≤ K ≤ 100,000,000)</p>
<p><strong>둘째 줄부터 N개의 줄에 동전의 가치 Ai가 오름차순으로 주어진다. (1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수)</strong></p>
<ul>
<li>☑ 이 부분을 제대로 이해하지 못하여 중간에 애를 먹었다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/768da284-cb5e-4f3f-a8be-0f3835b311a9/image.png" alt=""></p>
<p>(3) 출력
첫째 줄에 K원을 만드는데 필요한 동전 개수의 최솟값을 출력한다.</p>
<blockquote>
<p>가장 좋은 것부터 고려 (가장 큰 수부터) 하는 점을 통하여 탐욕법으로 풀이하는 그리디 문제임을 알 수 있다. </p>
</blockquote>
<h3 id="2-문제-해결하기">2. 문제 해결하기.</h3>
<p>Step 1. N,K를 입력 받고 arr를 내림차순으로 정렬한다. 그리고 result를 1로 지정한다.
Step 2. N만큼 반복문을 돌리고 차례로 K가 각각의 arr보다 크거나 같은지 확인한다. 조건을 만족한다면 result에 N을 K로 나눈 몫만큼 더해주고, K는 그 나머지로 재할당한다.
Step 3. Step 2의 조건을 만족하지 않는다면 다시 반복문으로 올라간다.
Step 4. result를 출력한다.</p>
<pre><code># 미니 예제 1 : N=10, K=4200

N=10
K=4200
arr=[1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000]
arr.sort(reverse=True)
result=0

for idx in range(N):
    if K&gt;=arr[idx]:
        result+=K//arr[idx]
        K-=arr[idx]*(K//arr[idx])
    continue

print(result)</code></pre><pre><code># 미니 예제 2 : N=10, K=4790

N=10
K=4790
arr=[1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000]
arr.sort(reverse=True)
result=0

for idx in range(N):
    if K&gt;=arr[idx]:
        result+=K//arr[idx]
        K-=arr[idx]*(K//arr[idx])
    continue

print(result)</code></pre><p>위의 코드는 문제를 제대로 이해하지 못하여 잘못 풀이하였다. 결국 런타임 에러 (ValueError)가 떴다.</p>
<ul>
<li>☑ <strong><em>arr 부분은 언제든지 변경될 수 있는 부분이다. 위의 조건 (Ai는 Ai-1의 배수)만 지킨다면 문제가 없다.</em></strong> </li>
</ul>
<pre><code># 최적의 일반화

N, K=map(int, input().split())
# arr=[1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000]
arr_list=list()
result=0

for i in range(N):
    arr_list.append(int(input()))

for idx in range(N):
    arr_list.sort(reverse=True)
    result+=K//arr_list[idx]
    K=K%arr_list[idx]

print(result)</code></pre><p>조건을 하나 더 걸어줘서 더 빨리 끝나게 코드를 짰다. (K가 arr_list보다 작은 경우는 반복문으로 다시 올라가기.)</p>
<p>Step 1. N,K를 입력 받고 result를 1로 지정한다.
<strong>Step 2. arr_list를 입력 받는다.</strong>
Step 3. N만큼 반복문을 돌리고 <strong>arr_list를 내림차순으로 정렬한다.</strong> 그리고 K가 각각의 arr_list보다 크거나 같은지 확인한다. 조건을 만족한다면 result에 N을 K로 나눈 몫만큼 더해주고, K는 그 나머지로 재할당한다.
Step 4. Step 3의 조건을 만족하지 않는다면 다시 반복문으로 올라간다.
Step 5. result를 출력한다.</p>
<pre><code>N, K=map(int, input().split())
# arr=[1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000]
arr_list=list()
result=0

// arr_list 입력 받기.
for i in range(N):
    arr_list.append(int(input()))

// 내림차순으로 정렬하고, 조건에 맞으면 result와 K 구하기.
for idx in range(N):
    arr_list.sort(reverse=True)
    if K&gt;=arr_list[idx]:
        result+=K//arr_list[idx]
        K=K%arr_list[idx]
    continue

print(result)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] 기본 문법]]></title>
            <link>https://velog.io/@tino-kim/Javascript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@tino-kim/Javascript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Mon, 16 Jan 2023 15:44:22 GMT</pubDate>
            <description><![CDATA[<h1 id="javascript-기본-문법">[Javascript] 기본 문법</h1>
<p>프로그래밍 : <strong>데이터 조작하는 작업</strong>    </p>
<h2 id="🟥-변수-vs-상수">🟥 변수 vs 상수</h2>
<ul>
<li>변수 : 데이터 담고 꺼내쓰는 상자 (let과 const) </li>
</ul>
<pre><code>console.log() // 원하는 데이터 출력하기.
console.log(10+20) // 30</code></pre><h2 id="🟧-변수-선언-및-데이터-할당">🟧 변수 선언 및 데이터 할당</h2>
<ul>
<li>변수 사용하는 이유 : 데이터 재사용이 필요한 경우 </li>
</ul>
<p>(1) 변수 선언 : 변수명은 명사적이어야 한다.</p>
<pre><code>let box;</code></pre><p>(2) 데이터 할당 : <strong>변수 할당에 = 사용한다. (오로지 변수 할당에만 사용)</strong></p>
<pre><code>box=123*987;</code></pre><p>(1), (2)번 과정을 한꺼번에 진행할 수 있다.</p>
<pre><code>let box=123*987; // 한줄 선언 가능</code></pre><p>(3) 변수 참조</p>
<pre><code>console.log(box*3)</code></pre><h2 id="🟨-변수-선언-키워드">🟨 변수 선언 키워드</h2>
<table>
<thead>
<tr>
<th align="center">var</th>
<th align="center">let</th>
<th align="center">const</th>
</tr>
</thead>
<tbody><tr>
<td align="center">재선언 O</td>
<td align="center"><strong>재선언 X</strong></td>
<td align="center"><strong>재선언 X</strong></td>
</tr>
<tr>
<td align="center">재할당 O</td>
<td align="center">재할당 O</td>
<td align="center">재할당 X</td>
</tr>
</tbody></table>
<ul>
<li>재선언 : 이미 선언된 변수명으로 다시 선언하는 것을 의미한다.</li>
<li>재할당 : 이미 데이터가 할당된 변수에 다시 할당하는 것을 의미한다.</li>
</ul>
<p>var는 사용하지 않는다. 재선언이 되면 협업 시에 동료가 사용한 변수를 인지하지 못 하고 또 선언하여 사용하는 경우가 생길 수 있기 때문이다.</p>
<p>const는 재선언과 재할당이 불가능한 <strong>반드시 변경되면 안되는 값</strong>을 의미한다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/a589635a-5fda-4b07-a8ae-0cdc4e111e4a/image.png" alt=""></p>
<h2 id="🟩-string-vs-number">🟩 string vs number</h2>
<p>string, number는 데이터 타입이다.</p>
<ul>
<li>문자열 (string) : 텍스트 데이터</li>
</ul>
<pre><code>&#39; &#39; 또는 &quot; &quot; // 표현하는 방식
// 덧셈만 가능하다.</code></pre><ul>
<li>숫자 (number) </li>
</ul>
<pre><code>100 != &quot;100&quot; // 문자열 100과 숫자 100은 다르다.</code></pre><ul>
<li>NaN : Not A Number 의미한다.</li>
</ul>
<p>산술 연산자로 사칙 연산이 가능하다. (덧셈, 뺄셈, 곱셈, 나눗셈)
이 때 <strong>숫자로 반환 가능한지 먼저 체크하기!</strong></p>
<p>(1) 숫자로 반환 가능한 경우 : 숫자
(2) 숫자로 반환 불가능한 경우 : NaN</p>
<pre><code>// (1)의 경우

100*20=2000

// (2)의 경우

&quot;abc&quot;*20=NaN</code></pre><p><strong>(예외) 문자열 + 숫자 = 문자열 (덧셈이 문자열 연결 연산자 역할을 수행한다.)</strong></p>
<pre><code>// 예외인 경우 : 문자열 연결 연산자
&quot;a&quot;+1=&quot;a1&quot; // string</code></pre><h2 id="🟦-배열-array">🟦 배열 (array)</h2>
<ul>
<li>배열 : <strong>순서가 있는 데이터 창고를 의미한다.</strong> 순서가 있는 여러 개의 데이터를 관리한다.
데이터 타입이다. <strong>인덱스를 이용하여 요소에 접근한다.</strong></li>
</ul>
<p>(1) 배열 정의</p>
<pre><code>[ ] // 배열 정의</code></pre><p>(2) <strong>인덱스를 통한 요소 접근</strong></p>
<pre><code>let ranking=[&quot;Jason&quot;, &quot;Alice&quot;, &quot;Chris&quot;, &quot;Jane&quot;, &quot;Tom&quot;];
// 각각은 요소(element)이다.
// 인덱스(index)는 0부터 시작한다.

// 인덱스를 통한 요소 접근
ranking[0]; // Jason 
ranking[1]; // Alice
ranking[2]; // Chris
ranking[3]; // Jane
ranking[4]; // Tom</code></pre><h2 id="🟪-배열-메소드">🟪 배열 메소드</h2>
<ul>
<li>속성 (property) : 고유한 속성 </li>
</ul>
<pre><code>length // 인덱스와 다르게 1부터 시작한다.</code></pre><ul>
<li>메소드 (method) : <strong>어떤 기능을 가진 명령어</strong></li>
</ul>
<pre><code>push() // 끝에 요소를 추가한다. 추가 후 개수가 반환된다.
pop() // 마지막 제거한다. 삭제한 데이터를 반환한다.
indexof() // 해당 데이터의 인덱스를 반환한다. (없으면 -1 반환) 특정 데이터 이용하여 인덱스 구하기.
includes() // 포함이면 True, 미포함이면 False를 반환한다. (Boolean 반환) 특정 데이터 유무 확인하기.</code></pre><h2 id="🟫-객체-object">🟫 객체 (object)</h2>
<ul>
<li>객체 : 배열과는 다르게 <strong>순서가 없는 데이터 창고를 의미한다.</strong> 데이터 타입이다. 배열에서 <strong>추가 정보를 넣어야 하는 경우</strong>에는 굉장히 불편하다. 고로 이런 경우에는 객체를 사용한다. <strong>객체는 여러 개의 property를 갖는 데이터 타입</strong>이고, <strong>key와 value로 이루어져 있다. key를 이용하여 데이터에 접근한다.</strong></li>
</ul>
<p>(1) 객체 정의</p>
<pre><code>{ } // 객체 정의, 중괄호 이용</code></pre><p>(2) 객체 예시</p>
<pre><code>let =userData={
    name: &#39;jason;,
    age: 25,
    gender: &#39;male&#39;
    // 각각의 property (3개)
    }</code></pre><p>(3) key를 이용한 데이터 접근 방법</p>
<ul>
<li>Dot notation : 점을 이용하는 방법</li>
</ul>
<pre><code>userData.name // jason
userData.age // 25
userData.gender // male</code></pre><ul>
<li>Bracket notation : 대괄호를 이용하는 방법</li>
</ul>
<p><strong>이 때 주의할 점은 문자열로 입력 (그렇지 않은 경우에는 변수로 인식한다.)</strong></p>
<pre><code>userData[&quot;name&quot;] // jason
userData[&quot;age&quot;] // 25
userData[&quot;gender&quot;] // male</code></pre><ul>
<li>undefined : 변수가 정의되지 않음을 의미한다.</li>
</ul>
<pre><code>// 변수로 인식하는 경우
const name=&quot;amy&quot;;
userData[name] // amy
// 예상과 다른 잘못된 데이터가 나올 수 있다.</code></pre><p><strong>그래서 변수를 이용하여 데이터에도 접근할 수 있다.</strong></p>
<h2 id="⬛-객체-메소드">⬛ 객체 메소드</h2>
<ul>
<li>메소드 (method) : <strong>어떤 기능을 가진 명령어</strong></li>
</ul>
<pre><code>.keys() : key만 가져온다. // Object.keys(object 변수) 문자열 반환, 배열 반환
.values() : value만 가져온다. // Object.values(object 변수) 배열 반환
// value에는 어떠한 데이터도 포함이 가능하다. (배열도 가능하다.)</code></pre><p><strong>key와 value를 배열에 담아서 사용하는 이유 : 객체는 순서가 존재하지 않기 때문에, 반복문에서 사용하기 까다로움. 그래서 반복문에서는 배열을 이용한다.</strong></p>
<p>const는 재선언은 불가능하지만, 수정과 추가는 가능하다. <strong>따라서 새로운 property의 생성이 가능하다.</strong></p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/6fc5b3f4-1954-4ee6-ba85-bf927933adaf/image.png" alt=""></p>
<h2 id="⬜-함수">⬜ 함수</h2>
<ul>
<li>함수 : <strong>어떤 기능 수행, 계산 수행하는 코드 집합</strong></li>
</ul>
<p>(1) 함수 선언
(2) 함수 호출</p>
<p>(1), (2)를 이용하여 함수를 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 12] ATM]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-12-ATM</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-12-ATM</guid>
            <pubDate>Mon, 16 Jan 2023 15:30:43 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-12-atm">[그리디 12] ATM</h1>
<h2 id="최적의-일반화">최적의 일반화</h2>
<p>정답 비율 : 67.626%</p>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>인하은행에는 ATM이 1대밖에 없다. 지금 이 ATM앞에 N명의 사람들이 줄을 서있다. 사람은 1번부터 N번까지 번호가 매겨져 있으며, i번 사람이 돈을 인출하는데 걸리는 시간은 Pi분이다.</p>
<p>사람들이 줄을 서는 순서에 따라서, 돈을 인출하는데 필요한 시간의 합이 달라지게 된다. 예를 들어, 총 5명이 있고, P1 = 3, P2 = 1, P3 = 4, P4 = 3, P5 = 2 인 경우를 생각해보자. [1, 2, 3, 4, 5] 순서로 줄을 선다면, 1번 사람은 3분만에 돈을 뽑을 수 있다. 2번 사람은 1번 사람이 돈을 뽑을 때 까지 기다려야 하기 때문에, 3+1 = 4분이 걸리게 된다. 3번 사람은 1번, 2번 사람이 돈을 뽑을 때까지 기다려야 하기 때문에, 총 3+1+4 = 8분이 필요하게 된다. 4번 사람은 3+1+4+3 = 11분, 5번 사람은 3+1+4+3+2 = 13분이 걸리게 된다. 이 경우에 각 사람이 돈을 인출하는데 필요한 시간의 합은 3+4+8+11+13 = 39분이 된다.</p>
<p>줄을 [2, 5, 1, 4, 3] 순서로 줄을 서면, 2번 사람은 1분만에, 5번 사람은 1+2 = 3분, 1번 사람은 1+2+3 = 6분, 4번 사람은 1+2+3+3 = 9분, 3번 사람은 1+2+3+3+4 = 13분이 걸리게 된다. 각 사람이 돈을 인출하는데 필요한 시간의 합은 1+3+6+9+13 = 32분이다. 이 방법보다 더 필요한 시간의 합을 최소로 만들 수는 없다.</p>
<p>줄을 서 있는 사람의 수 N과 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어졌을 때, 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 구하는 프로그램을 작성하시오.</p>
<blockquote>
<p>이 문제는 최솟값을 찾는 그리디 문제이다. 탐욕법을 이용하여 풀이하면 된다. 나는 시간을 오름차순으로 정렬한 뒤에 각각의 시간을 구하여 결과값에 더해주는 방법을 사용했다.</p>
</blockquote>
<h3 id="2-문제-해결하기">2. 문제 해결하기.</h3>
<p>Step 1. 시간 정렬하기.
Step 2. 각각의 시간을 찾아주기.
Step 3. 각각의 시간을 결과값에 더해주기.
Step 4. 결과값 출력하기.</p>
<pre><code>N=int(input())
times=list(map(int, input().split()))
times.sort()
each_time=0 # 각각의 사람들의 시간
min_time=0 # 모든 사람들의 소모 시간의 합

for time in times:
    each_time+=time
    min_time+=each_time

print(min_time)</code></pre><p>함수로도 만들었다.</p>
<pre><code>### 사용자 함수

N=int(input())
times=list(map(int, input().split()))
times.sort()

def min_time(N, times):
    each_time=0
    result=0
    for time in times:
        each_time+=time
        result+=each_time
    return result

print(min_time(N, times))</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 11] 설탕 배달]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-11-%EC%84%A4%ED%83%95-%EB%B0%B0%EB%8B%AC</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-11-%EC%84%A4%ED%83%95-%EB%B0%B0%EB%8B%AC</guid>
            <pubDate>Fri, 13 Jan 2023 03:57:49 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-11-설탕-배달">[그리디 11] 설탕 배달</h1>
<h2 id="최적의-일반화">최적의 일반화</h2>
<p>정답 비율 : 35.885%</p>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.</p>
<p>상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.</p>
<p>상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오.</p>
<blockquote>
<p>일단 이 문제는 그리디 문제이다. 최대한 적은 횟수로 봉지를 가져가는 것이기 때문에 가장 좋은 것부터 선택하는 탐욕법을 이용하면 되기 때문이다. 하지만 나는 3부터 고려하여 문제를 풀었다. 구글링으로 최적의 코드를 보니, 5부터 고려하였고 내 코드보다 훨씬 간결하였다. 다음에는 5부터 고려하는 방식을 이용할 것이다.</p>
</blockquote>
<h3 id="2-문제-해결하기">2. 문제 해결하기.</h3>
<p>삽질을 굉장히 많이 한 문제이다. </p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/2d5121ae-eca8-47cf-8ea5-d17dfceae575/image.png" alt=""></p>
<p>3일 내내 삽질하였다. 하나를 해결하면 다른 하나가 해결이 안되는 문제가 계속 발생하여 많은 예제를 통하여 일반화를 하였다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/21d09065-e605-41ce-b12e-fe21a8fbe06b/image.png" alt=""></p>
<p>조건 ①, ②, ③을 찾을 수 있었다. 조건 ②의 5의 배수는 조건 ③에서 고려하기 때문에 빼도 좋다.</p>
<pre><code>N=int(input())

def delivery_sugar(N):
    # 5 이하인 수들 구현하기.
    count=0
    iter=1

    # 조건 ②
    if (N==1) or (N==2) or (N==4):
        return -1
    if (N==3):
        return 1

    # 조건 ③
    # 5의 배수들 구현하기.
    if N%5==0:
        count=N//5
        return count

    # 조건 ①
    # 제일 복잡한 부분 구현하기.
    while True:
        remaining=N-3*iter # iter : 3의 횟수
        if (remaining%5!=0) and (remaining&gt;=3): 
        # 5의 배수가 아니면서, 3보다 큰 경우
            iter+=1
            continue # 계속 무한 반복문 진행하기.
        if (remaining%5!=0) and (remaining&lt;3):
        # 5의 배수도 아니면서 3보다 작은 경우
            return -1 # 더 이상 진행 불가니 -1 리턴하기.
        count+=(iter+(remaining//5))
        # 3의 횟수 + 나머지를 5로 나눈 몫 = 전체 횟수
        return count

delivery_sugar(N)</code></pre><p><strong>주의 : 반드시 풀이를 제출할 때에 print() 해주기!! 위의 함수는 return만 진행하기 때문에, print()를 사용해야 제대로 된 답을 얻을 수 있다.</strong> </p>
<pre><code>## 내가 만든 함수에서는 return 밖에 없기 때문에, 반드시 print()를 이용하여 답을 출력해야 한다.
## 요즘 사용자 함수 만드는 것을 연습하고 있는데, 다른 문제에서는 이런 실수를 반복하지 말자!

N=int(input())

def delivery_sugar(N):
    # 5 이하인 수들 구현하기.
    count=0
    iter=1

    # 조건 ②
    if (N==1) or (N==2) or (N==4):
        return -1
    if N==3:
        return 1

    # 조건 ③
    # 5의 배수들 구현하기.
    if N%5==0:
        count=N//5
        return count

    # 조건 ①
    # 제일 복잡한 부분 구현하기.
    while True:
        remaining=N-3*iter # iter : 3의 횟수
        if (remaining%5!=0) and (remaining&gt;=3): 
        # 5의 배수가 아니면서, 3보다 큰 경우
            iter+=1
            continue # 계속 무한 반복문 진행하기.
        if (remaining%5!=0) and (remaining&lt;3):
        # 5의 배수도 아니면서 3보다 작은 경우
            return -1 # 더 이상 진행 불가니 -1 리턴하기.
        count+=(iter+(remaining//5))
        # 3의 횟수 + 나머지를 5로 나눈 몫 = 전체 횟수
        return count

print(delivery_sugar(N)) # 드디어 성공!</code></pre><p>이 풀이도 가능하다.</p>
<pre><code>## 내가 만든 함수에서는 return 밖에 없기 때문에, 반드시 print()를 이용하여 답을 출력해야 한다.
## 요즘 사용자 함수 만드는 것을 연습하고 있는데, 다른 문제에서는 이런 실수를 반복하지 말자!

N=int(input())

def delivery_sugar(N):
    # 5 이하인 수들 구현하기.
    count=0
    iter=1

    # 조건 ②
    if (N==1) or (N==2) or (N==4):
        return -1
    if (N==3):
        return 1

    # 조건 ③
    # 5의 배수들 구현하기.
    if N%5==0:
        count=N//5
        return count

    # 조건 ①
    # 제일 복잡한 부분 구현하기.
    while True:
        remaining=N-3*iter # iter : 3의 횟수
        if (remaining%5!=0) and (remaining&gt;=3): 
        # 5의 배수가 아니면서, 3보다 큰 경우
            iter+=1
            continue # 계속 무한 반복문 진행하기.
        if remaining&lt;3:
        # 3보다 작은 경우
            return -1 # 더 이상 진행 불가니 -1 리턴하기.
        count+=(iter+(remaining//5))
        # 3의 횟수 + 나머지를 5로 나눈 몫 = 전체 횟수
        return count

print(delivery_sugar(N)) # 드디어 성공!</code></pre><h3 id="3-구글링을-통해-얻은-최적의-일반화">3. 구글링을 통해 얻은 최적의 일반화</h3>
<p>가장 큰 수인 5부터 고려하는 방법이다. 이렇게 하면 5의 배수를 따로 고려하지 않아도 된다.</p>
<pre><code>n = int(input())
count = 0

while True:
    if (n % 5) == 0: # 5의 배수인 경우
        count = count + (n//5)
        print(count)
        break
    n = n-3 # 5의 배수가 아니면 3을 빼고 다시 5의 배수인지 고려해보기.
    count += 1 # 3의 횟수가 늘었으니, +1 처리하기.
    if n &lt; 0: # 0보다 작아지는 경우 사용 불가능하니, -1 출력하기.
        print(&quot;-1&quot;)
        break</code></pre><p>Step 1. 5의 배수인지 확인하기. 맞다면 그 만큼 더해주고 무한 반복문을 종료한다.
Step 2. 5의 배수가 아니라면, 3을 빼고 5의 배수인지 확인해보기. 이 때 3의 횟수가 +1 되었으니 +1 처리를 해야 한다.
Step 3. 계속 위의 과정을 반복하다가 음수가 되는 경우, -1을 출력한다. 그리고 무한 반복문을 종료한다.</p>
<p>깔끔한 그리디 문제 풀이인 듯 하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[❌ [그리디 10] 무지의 먹방 라이브]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-10-%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/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-10-%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, 12 Jan 2023 04:13:18 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-10-무지의-먹방-라이브">[그리디 10] 무지의 먹방 라이브</h1>
<h2 id="미니-예제-1">미니 예제 1</h2>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>food_times가 [3, 1, 2]이고, k=5인 경우이다.</p>
<h3 id="2-문제-해결하기">2. 문제 해결하기.</h3>
<p>이 미니 예제를 풀 때에는 count, idx를 변수로 두고 어떠한 과정이 진행됨에 따라 +1 처리를 해주었다. </p>
<p>Step 01. 무한 반복문으로 돌리고, 해당 food_times를 idx에서 -1 처리를 해준다. 그리고 count, idx를 +1 처리한다.
Step 02. idx가 마지막 인덱스를 넘어가는 경우에는 다시 처음으로 돌려준다. (idx=0)
Step 03. 해당 idx의 food_times가 0인 경우에는 idx를 +1 처리한 뒤에 작업을 진행한다.
Step 04. count가 k가 되면 반복문을 탈출한다.</p>
<pre><code># 미니 예제 1 : food_times=[3,1,2], k=5인 경우

food_times=[3,1,2]
idx=0
count=0

while True:
    food_times[idx]-=1
    print(idx)
    print(food_times)
    idx+=1
    count+=1
    if idx==3:
        idx=0
    if food_times[idx]==0:
        idx+=1
    if count == 5:
        break</code></pre><p>코드를 일반적으로 표현하면 아래와 같다.</p>
<pre><code>def solution(food_times, k):
    idx=0
    vacant_list=[0]*len(food_times)
    count=0

    while True:
        if count == k:
            break
        food_times[idx]-=1
        print(idx)
        print(food_times)
        idx+=1
        count+=1
        if idx==len(food_times):
            idx=0
        if food_times[idx]==0:
            if idx==len(food_times)-1:
                idx=0
                food_times[idx]-=1
            idx+=1
        if food_times[idx]==vacant_list:
            return -1
    return food_times[idx]

solution([3,1,2], 5) </code></pre><p>solution([2,9,10], 7) 를 넣어봤는데, 성공하였다.</p>
<h2 id="미니-예제-2">미니 예제 2</h2>
<h3 id="1-문제-설명하기-1">1. 문제 설명하기.</h3>
<p>food_times=[8,6,4]이고, k=15인 경우이다.</p>
<h3 id="2-문제-해결하기-1">2. 문제 해결하기.</h3>
<p>위와 동일하다.</p>
<pre><code># 미니 예제 2 : food_times=[8,6,4], k=15인 경우

def solution(food_times, k):
    idx=0
    vacant_list=[0]*len(food_times)
    count=0

    while True:
        if count == k:
            break
        food_times[idx]-=1
        print(idx)
        print(food_times)
        idx+=1
        count+=1
        if idx==len(food_times):
            idx=0
        if food_times[idx]==0:
            if idx==len(food_times)-1:
                idx=0
                food_times[idx]-=1
            idx+=1
        if food_times[idx]==vacant_list:
            return -1
    return food_times[idx]

solution([8,6,4], 15)</code></pre><h2 id="최적의-일반화">최적의 일반화</h2>
<h3 id="1-문제-설명하기-2">1. 문제 설명하기.</h3>
<p>위와 동일하다.</p>
<h3 id="2-문제-해결하기-2">2. 문제 해결하기.</h3>
<pre><code>def solution(food_times, k):
    idx=0
    vacant_list=[0]*len(food_times)
    count=0

    while True:
        if count == k:
            break
        food_times[idx]-=1
        print(idx)
        print(food_times)
        idx+=1
        count+=1
        if idx==len(food_times):
            idx=0
        if food_times[idx]==0:
            if idx==len(food_times)-1:
                idx=0
                food_times[idx]-=1
            idx+=1
        if food_times[idx]==vacant_list:
            return -1
    return food_times[idx]</code></pre><p>하지만 이렇게 풀이하면 프로그래머스에서는 오류라고 뜬다.
<strong>여기서 함수가 return을 이용하기 때문에, print()를 이용하여 함수를 출력했는데 런타임 에러가 뜬다. 알고리즘 자체가 잘못된 케이스인 것 같다.</strong></p>
<h3 id="3-책에-나와있는-최적의-일반화">3. 책에 나와있는 최적의 일반화</h3>
<p>큐를 이용하여 풀이한다고 나와있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 9] 볼링공 고르기]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-9-%EB%B3%BC%EB%A7%81%EA%B3%B5-%EA%B3%A0%EB%A5%B4%EA%B8%B0</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-9-%EB%B3%BC%EB%A7%81%EA%B3%B5-%EA%B3%A0%EB%A5%B4%EA%B8%B0</guid>
            <pubDate>Mon, 09 Jan 2023 10:16:01 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-9-볼링공-고르기">[그리디 9] 볼링공 고르기</h1>
<p>책에서 나온 풀이는 꼭 기억하기. <strong>하나를 기준으로 삼고, 다른 하나를 선택할 때에 사용자 정의 리스트를 만들어서 이용할 수 있다. (문제의 조건인 1 &lt;= M &lt;= 10 이용)</strong></p>
<h2 id="미니-예제-1">미니 예제 1</h2>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>A, B 두 사람이 있는데, 서로 무게가 다른 볼링공을 고르려고 한다.
N은 볼링공의 개수이고, M은 볼링공의 무게이다. (1 ~ M 까지의 자연수 형태)</p>
<h3 id="2-문제-해결하기">2. 문제 해결하기.</h3>
<p>나는 조건에 만족하는 경우에 +1 처리하는 방식으로 구하고자 한다. count라는 변수를 지정하여 0이라고 두고, 여기서 조건에 해당할 때마다 +1 처리를 해준다. </p>
<p><strong><em>여기서 주의할 점은 인덱스를 2개를 이용해야 된다는 점이다. (조합의 개수를 구할 때 인덱스가 2개가 필요하다.) 기준이 되는 인덱스와 그 다음 인덱스가 필요하기에 중첩 반복문을 이용한다.</em></strong></p>
<p>즉, 이 예제에서는</p>
<pre><code># 기준이 되는 인덱스, 그 다음 인덱스들
0 -&gt; [1, 2, 3, 4]
1 -&gt; [2, 3, 4]
2 -&gt; [3, 4]
3 -&gt; [4]</code></pre><p>Step 1. 기준이 되는 인덱스 반복문을 돌린다.
Step 2. 기준이 되는 인덱스 다음 인덱스들을 반복문으로 돌린다.
Step 3. A, B의 무게가 같은 경우는 넘긴다.
Step 4. A, B의 무게가 다른 경우는 +1 처리한다.</p>
<pre><code># 미니 예제 1 : N=5, M=3

N=5
M=3
count=0
weight=[1,3,2,3,2]

for index in range(N-1): # 기준이 되는 인덱스
    # print(index)
    for idx in range(index+1, N): # 그 다음 인덱스
        # print(idx)
    # print(&quot;--&quot;)
        if weight[index] == weight[idx]: # 무게가 같으면 넘기기.
            continue
        count+=1 # 무게 다른 경우는 +1 처리하기.

print(count)        </code></pre><h2 id="미니-예제-2">미니 예제 2</h2>
<h3 id="1-문제-설명하기-1">1. 문제 설명하기.</h3>
<p>A, B 두 사람이 있는데, 서로 무게가 다른 볼링공을 고르려고 한다.
N은 볼링공의 개수이고, M은 볼링공의 무게이다. (1 ~ M 까지의 자연수 형태)</p>
<h3 id="2-문제-해결하기-1">2. 문제 해결하기.</h3>
<p>나는 조건에 만족하는 경우에 +1 처리하는 방식으로 구하고자 한다. count라는 변수를 지정하여 0이라고 두고, 여기서 조건에 해당할 때마다 +1 처리를 해준다. </p>
<p><strong><em>여기서 주의할 점은 인덱스를 2개를 이용해야 된다는 점이다. (조합의 개수를 구할 때 인덱스가 2개가 필요하다.) 기준이 되는 인덱스와 그 다음 인덱스가 필요하기에 중첩 반복문을 이용한다.</em></strong></p>
<p>즉, 이 예제에서는</p>
<pre><code># 기준이 되는 인덱스, 그 다음 인덱스들
0 -&gt; [1, 2, 3, 4, 5, 6, 7]
1 -&gt; [2, 3, 4, 5, 6 ,7]
2 -&gt; [3, 4, 5, 6 ,7]
.
.
.
6 -&gt; [7]</code></pre><p>Step 1. 기준이 되는 인덱스 반복문을 돌린다.
Step 2. 기준이 되는 인덱스 다음 인덱스들을 반복문으로 돌린다.
Step 3. A, B의 무게가 같은 경우는 넘긴다.
Step 4. A, B의 무게가 다른 경우는 +1 처리한다.</p>
<pre><code># 미니 예제 2 : N=8, M=5

N=8
M=5
count=0
weight=[1,5,4,3,2,4,5,2]

for index in range(N-1):
    # print(index)
    for idx in range(index+1, N):
        # print(idx)
    # print(&quot;--&quot;)
        if weight[index] == weight[idx]:
            continue
        count+=1

print(count)    </code></pre><h2 id="최적의-일반화">최적의 일반화</h2>
<h3 id="1-문제-설명하기-2">1. 문제 설명하기.</h3>
<p>위와 동일하다. 위와 다른 점은 데이터를 직접 받는다는 점이다. N, M은 같이 받고, 공의 무게인 weight는 리스트의 형태로 받았다.</p>
<h3 id="2-문제-해결하기-2">2. 문제 해결하기.</h3>
<pre><code># 최적의 일반화

N, M=map(int, input().split())
weight=list(map(int, input().split()))
count=0


for index in range(N-1):
    # print(index)
    for idx in range(index+1, N):
        # print(idx)
    # print(&quot;--&quot;)
        if weight[index] == weight[idx]:
            continue
        count+=1

print(count)    </code></pre><h3 id="3-책에-나와있는-최적의-일반화">3. 책에 나와있는 최적의 일반화</h3>
<p><strong><em>책에서는 볼링공의 무게가 1 ~ 10임을 이용한다. (모든 조건 이용)</em></strong></p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/b95c4350-1f3e-468f-9e26-f115f0f36780/image.png" alt=""></p>
<table>
<thead>
<tr>
<th align="center">기준</th>
<th align="center">나의 풀이</th>
<th align="center">책의 풀이</th>
</tr>
</thead>
<tbody><tr>
<td align="center">모든 경우의 수 구하기.</td>
<td align="center">조건에 맞으면 더하기.</td>
<td align="center"><strong>(A의 선택) x (B의 선택)</strong></td>
</tr>
<tr>
<td align="center">무게 나열하기.</td>
<td align="center">중첩 반목문 이용하기.</td>
<td align="center"><strong>(정렬된) 무게 리스트 이용하기.</strong></td>
</tr>
</tbody></table>
<p>일단 미니 예제를 통하여 풀어보자. N=5이고 M=3이다. 볼링공의 무게는 [1, 2, 2, 3, 3] 이다.</p>
<p>Step 1. 0으로 채워진 리스트 만들기.
Step 2. 정렬된 무게로 채워진 리스트 만들기.
Step 3. A를 기준으로 잡고, B의 경우의 수 구하기.
Step 4. (A 기준) x (B의 경우의 수)를 구하고자 하는 값에 더해주기.</p>
<pre><code># 책에 나와있는 일반화

N, M=5, 2 # 볼링공의 개수, 최대 무게
data=[1,2,2,3,3]

## Step 1.
array=[0]*11 # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 0 ~ 10까지 해당하는 볼링공의 무게

## Step 2.
for x in data:
    array[x]+=1
print(array)

## Step 3.
result=0
for i in range(1, M+1): # A 기준
    N-=array[i] # B 경우의 수
    # print(N)
    ## Step 4.
    result+=array[i]*N

print(result)</code></pre><pre><code>N,M=map(int, input().split())
data=list(map(int, input().split()))
result=0

## Step 1.
array=[0]*11 # 0 ~ 10까지 해당하는 볼링공의 무게

## Step 2.
for i in data:
    array[i]+=1
print(array)

## Step 3,4.
for i in range(1, M+1): # A 기준
    N-=array[i]
    result+=N*array[i]

print(result)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[❌ [그리디 8] 만들 수 없는 금액]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-8-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%97%86%EB%8A%94-%EA%B8%88%EC%95%A1</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-8-%EB%A7%8C%EB%93%A4-%EC%88%98-%EC%97%86%EB%8A%94-%EA%B8%88%EC%95%A1</guid>
            <pubDate>Mon, 09 Jan 2023 10:15:03 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-8-만들-수-없는-금액">[그리디 8] 만들 수 없는 금액</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 7] 문자열 뒤집기]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-7-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%92%A4%EC%A7%91%EA%B8%B0</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-7-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%92%A4%EC%A7%91%EA%B8%B0</guid>
            <pubDate>Fri, 06 Jan 2023 14:03:47 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-7-문자열-뒤집기">[그리디 7] 문자열 뒤집기</h1>
<p><strong>연속된 하나 이상의 수를 뒤집어서</strong> 전부 0 또는 1로 변경해야 하는데 최소로 뒤집어야 한다. 주어진 숫자에서 <code>연속된 0의 집합의 개수 또는 연속된 1의 집합의 개수가 더 적은 것을 뒤집어야 최소의 뒤집기로 0 또는 1로 만들 수 있다.</code> 따라서 탐욕법이고 그리디 방법이다.</p>
<h2 id="미니-예제-1">미니 예제 1</h2>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>S가 0001100 인 경우이다. </p>
<p>Step 1. <code>S에서 연속된 0의 집합의 개수와 연속된 1의 집합의 개수를 구한다.</code> 0001100 인 경우에는 000 | 11 | 00 이기 때문에, 연속된 0의 집합의 개수는 2개이고 연속된 1의 집합의 개수는 1개이다.</p>
<p>Step 2. 초기값을 만들어준다. (여기서 초기값은 현재 수의 바로 앞 숫자를 의미한다.)
<strong>Step 2-1. 초기값이 0인 경우에는 1이 나올 때 연속된 0의 집합의 개수에 +1 처리한다. 그리고 초기값을 재설정한다.</strong>
<strong>Step 2-2. 초기값이 1인 경우에는 0이 나올 때 연속된 1의 집합의 개수에 +1 처리한다. 그리고 초기값을 재설정한다.</strong></p>
<p>Step 3. 2단계까지 진행하면 마지막 집합의 개수는 세어주지 않는다. 따라서 <strong>마지막 집합이 어떤 것인지 확인하고 +1 처리한다.</strong></p>
<h3 id="2-문제-풀이하기">2. 문제 풀이하기.</h3>
<pre><code># 미니 예제 1 : S=0001100 인 경우

S=&quot;0001100&quot;
count_one=0
count_zero=0

## Step 1.
init=int(S[0])

## Step 2.
for num in S[1:]:
    num=int(num)
    if init==0:
        if num==init:
            init=num
            continue
        count_zero+=1
        init=num
    else:
        if num==init:
            init=num
            continue
        count_one+=1
        init=num

## Step 3.
if (int(S[-1])==1) and (int(S[-2])==1):
    count_one+=1
if (int(S[-1])==0) and (int(S[-2])==0):
    count_zero+=1

if count_zero&lt;=count_one:
    result=count_zero
result=count_one

print(result)</code></pre><h2 id="최적의-일반화">최적의 일반화</h2>
<h3 id="1-문제-설명하기-1">1. 문제 설명하기.</h3>
<p>Step 1. <code>S에서 연속된 0의 집합의 개수와 연속된 1의 집합의 개수를 구한다.</code> 0001100 인 경우에는 000 | 11 | 00 이기 때문에, 연속된 0의 집합의 개수는 2개이고 연속된 1의 집합의 개수는 1개이다.</p>
<p>Step 2. 초기값을 만들어준다. (여기서 초기값은 현재 수의 바로 앞 숫자를 의미한다.)
<strong>Step 2-1. 초기값이 0인 경우에는 1이 나올 때 연속된 0의 집합의 개수에 +1 처리한다. 그리고 초기값을 재설정한다.</strong>
<strong>Step 2-2. 초기값이 1인 경우에는 0이 나올 때 연속된 1의 집합의 개수에 +1 처리한다. 그리고 초기값을 재설정한다.</strong></p>
<p>Step 3. 2단계까지 진행하면 마지막 집합의 개수는 세어주지 않는다. 따라서 <strong>마지막 집합이 어떤 것인지 확인하고 +1 처리한다.</strong></p>
<h3 id="2-문제-풀이하기-1">2. 문제 풀이하기.</h3>
<pre><code># Check!

S=&quot;1011001001&quot;
count_one=0
count_zero=0

## Step 1.
init=int(S[0])

## Step 2.
for num in S[1:]:
    num=int(num)
    if init==0:
        if num==init:
            init=num
            continue
        count_zero+=1
        init=num
    else:
        if num==init:
            init=num
            continue
        count_one+=1
        init=num

## Step 3.
if (int(S[-1])==1) and (int(S[-2])==1):
    count_one+=1
if (int(S[-1])==0) and (int(S[-2])==0):
    count_zero+=1

if count_zero&lt;=count_one:
    result=count_zero
result=count_one

print(result) # 3개가 나와야 한다.</code></pre><pre><code># 최적의 일반화

S=input()
count_one=0
count_zero=0
init=int(S[0])

for num in S[1:]:
    num=int(num)
    if init==0:
        if num==init:
            init=num
            continue
        count_zero+=1
        init=num
    else:
        if num==init:
            init=num
            continue
        count_one+=1
        init=num

if (int(S[-1])==1) and (int(S[-2])==1):
    count_one+=1
if (int(S[-1])==0) and (int(S[-2])==0):
    count_zero+=1

if count_zero&lt;=count_one:
    result=count_zero
result=count_one

print(result)</code></pre><h3 id="3-책에-나와있는-최적의-일반화">3. 책에 나와있는 최적의 일반화</h3>
<p>접근 방식은 동일하다. 하지만 나처럼 계속 초기값을 재설정하는 것보다 인덱스를 이용하는 것이 더 직관적으로 보기 좋다.</p>
<table>
<thead>
<tr>
<th align="center">기준</th>
<th align="center">나의 풀이</th>
<th align="center">책의 풀이</th>
</tr>
</thead>
<tbody><tr>
<td align="center">바로 앞, 현재 숫자</td>
<td align="center">초기값 재설정하기.</td>
<td align="center"><strong>인덱스 이용하기.</strong></td>
</tr>
</tbody></table>
<p>Step 1. 첫 번째 값 (즉 현재의 숫자)를 지정해주기. <strong>1인 경우 count_one에 +1 처리하고, 0인 경우 count_zero에 +1 처리한다.</strong></p>
<p>🌠 Step 2. <strong>인덱스를 이용하여</strong> 현재의 수와 그 전의 수를 표기할 것이다. <code>(현재 숫자의 인덱스) = (앞에 있는 숫자의 인덱스) + 1</code> 를 이용하면 된다. <strong>따라서 그 전의 숫자의 인덱스로 반복문을 돌려준다.</strong> </p>
<p>🌠 <strong>현재의 숫자와 앞의 숫자가 다른 경우 현재의 수가 1이면 count_zero에 +1 처리하고, 0인 경우 count_one에 +1 처리한다.</strong></p>
<p>Step 3. 가장 적은 횟수가 최소로 뒤집어서 전부 0 또는 1로 만드는 횟수이다.</p>
<pre><code># 책에 나와있는 풀이

S=input()
count_zero=0
count_one=0

## 1. 첫 번째 값에 따라 count_zero에 더해줄지 count_one에 더해줄지 고민하기.
if S[0]==&quot;1&quot;:
    count_one+=1
else:
    count_zero+=1

## 2. 전 숫자의 인덱스 까지 돌리고 (전 숫자의 인덱스 + 1) = 현재 숫자의 인덱스임을 이용한다.
for idx in range(len(S)-1):
    if S[idx] != S[idx+1]: # 현재와 전 숫자가 다른 경우
        if S[idx+1] == &quot;1&quot;: # 현재의 수가 1이면
            count_zero+=1 # count_zero에 +1
        else: # 현재의 수가 0이면
            count_one+=1 # count_one에 +1

## 3. 최소인 값이 최소의 횟수로 뒤집는 것이다.
print(min(count_zero, count_one)) </code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 6] 곱하기 혹은 더하기]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-6-%EA%B3%B1%ED%95%98%EA%B8%B0-%ED%98%B9%EC%9D%80-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-6-%EA%B3%B1%ED%95%98%EA%B8%B0-%ED%98%B9%EC%9D%80-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 06 Jan 2023 13:38:15 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-6-곱하기-혹은-더하기">[그리디 6] 곱하기 혹은 더하기</h1>
<p>곱하거나 더하여 가장 큰 수를 만드는 코드를 구현해야 한다. 최대한 많은 곱셈을 사용해야 가장 큰 수를 구현할 수 있기 때문에, 탐욕법을 이용해야 한다. 즉, 그리디 문제이다. </p>
<h2 id="미니-예제-1">미니 예제 1</h2>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>S가 02984인 경우이다. 최대한 많은 곱셈을 이용하기 위하여 덧셈을 사용하는 규칙을 찾았다.
S를 하나씩 풀어서 <code>0 이거나 1 또는 총합(result) 이 0인 경우</code>는 더해야 된다고 생각이 들었다.</p>
<p>그래서 조건을 걸어줘서 문제를 풀이하였다.</p>
<h3 id="2-문제-풀이하기">2. 문제 풀이하기.</h3>
<pre><code># 미니 예제 1 : S=02984 인 경우

S=&quot;02984&quot;
result=0

for num in S:
    num=int(num)
    if (num==0) or (num==1) or (result==0):
        result+=num
    else:
        result*=num

print(result)</code></pre><h2 id="미니-예제-2">미니 예제 2</h2>
<h3 id="1-문제-설명하기-1">1. 문제 설명하기.</h3>
<p>S가 567인 경우이다. 위와 같은 방법으로 풀이하였다.</p>
<h3 id="2-문제-풀이하기-1">2. 문제 풀이하기.</h3>
<pre><code># 미니 예제 2 : S=567 인 경우

S=&quot;567&quot;
result=0

for num in S:
    num=int(num)
    if (num==0) or (num==1) or (result==0):
        result+=num
    else:
        result*=num

print(result)</code></pre><h2 id="최적의-일반화">최적의 일반화</h2>
<h3 id="1-문제-설명하기-2">1. 문제 설명하기.</h3>
<p>위와 같은 방법으로 풀이하였다.</p>
<h3 id="2-문제-풀이하기-2">2. 문제 풀이하기.</h3>
<pre><code># 최적의 일반화

S=input()
result=0

for num in S:
    num=int(num)
    if (num==0) or (num==1) or (result==0):
        result+=num
    else:
        result*=num

print(result)</code></pre><h3 id="3-책에-나와있는-최적의-일반화">3. 책에 나와있는 최적의 일반화</h3>
<p>책에서는 나와 비슷하게 풀었다. 하지만 내가 놓친 부분이 있다. <strong>나는 총합이 0인 경우만 덧셈으로 연결하였는데, 총합이 1인 경우에도 덧셈으로 연결해야 한다.</strong></p>
<p>예를 들자면 총합이 1인 경우 4를 더해주거나 곱하여 가장 큰 수를 만들어야 되는 경우가 있다고 하자. <strong><em>덧셈을 이용하면 1+4=5 이고, 곱셈을 이용하면 1x4=4 이기 때문에 더해주는 것이 더 유리하다.</em></strong></p>
<p>그래서 조건을 <strong>1 이하라고</strong> 넣어주었다.</p>
<table>
<thead>
<tr>
<th align="center">기준</th>
<th align="center">나의 풀이</th>
<th align="center">책의 풀이</th>
</tr>
</thead>
<tbody><tr>
<td align="center">반복문</td>
<td align="center">num 그대로 출력하기.</td>
<td align="center">입력 데이터를 이용하여 <strong>인덱스를 이용 (1 ~ 끝)</strong>하여 출력하기.</td>
</tr>
<tr>
<td align="center">조건문</td>
<td align="center">num==0 또는 num==1 또는 result==0</td>
<td align="center">num&lt;=1 또는 <strong>result (처음 설정은 S의 첫 번째 숫자로 지정)&lt;=1</strong></td>
</tr>
</tbody></table>
<pre><code># 책에 나와있는 최적의 일반화

S=input()
result=int(S[0]) # 첫 번째 숫자 의미하면서 회차 지날 수록 총합이 된다.

for idx in range(1, len(S)): # 인덱스 (1 ~ 끝까지)
    num=int(S[idx])
    if (num&lt;=1) or (result&lt;=1):
        result+=num
    else:
        result*=num

print(result)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[그리디 5] 모험가 길드]]></title>
            <link>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-5-%EB%AA%A8%ED%97%98%EA%B0%80-%EA%B8%B8%EB%93%9C</link>
            <guid>https://velog.io/@tino-kim/%EA%B7%B8%EB%A6%AC%EB%94%94-5-%EB%AA%A8%ED%97%98%EA%B0%80-%EA%B8%B8%EB%93%9C</guid>
            <pubDate>Thu, 05 Jan 2023 05:01:51 GMT</pubDate>
            <description><![CDATA[<h1 id="그리디-5-모험가-길드">[그리디 5] 모험가 길드</h1>
<h2 id="미니-예제-1">미니 예제 1</h2>
<h3 id="1-문제-설명하기">1. 문제 설명하기.</h3>
<p>모험가 N명을 공포도에 따라서 최대 그룹으로 나누는 문제이다. <del>주의할 점은 공포도 수치만큼 모험가를 묶어야 된다는 점이다. 그러므로 공포도가 높은 모험가부터 묶어야 하기 때문에,</del> 가장 좋은 것을 택해야 하는 그리디 문제이다.</p>
<p><strong>모든 카드를 이용하지 않아도 된다. 그러므로 최대 그룹 수를 만들기 위하여 <code>공포도 수치가 가장 낮은 카드부터 그룹으로 지정해야 한다.</code></strong></p>
<h3 id="2-문제-풀이하기">2. 문제 풀이하기.</h3>
<p>N=5이고, 각 모험가의 공포도가 [2, 3, 1, 2, 2] 이다.</p>
<p>Step 1. 모험가의 공포도를 오름차순으로 나열한다.
Step 2. 무한 반복문을 돌리고, <code>공포도의 최대가 공포도 길이보다 큰 경우,</code> 반복문의 종료 조건으로 걸어준다.
Step 3. 규칙에 따라 그룹으로 묶은 뒤에 공포도를 재설정하고 그룹 수를 세어준다.</p>
<pre><code># 미니 예제 : N=5, [2,3,1,2,2]

N=5
data=[2,3,1,2,2]
count=0

data.sort() # sort에는 내림차순 매개변수가 존재한다.

while True:
    if min(data) in data:
        data=data[min(data):]
        count+=1
    if max(data)&gt;len(data):
        break

print(count)</code></pre><h2 id="최적의-일반화">최적의 일반화</h2>
<h3 id="1-문제-설명하기-1">1. 문제 설명하기.</h3>
<p>N과 각 모험가의 공포도를 따로 받아서 문제를 진행한다. 위의 내용과 동일하다. 각 모험가의 공포도는 리스트에 받고 data 라고 하자.</p>
<h3 id="2-문제-풀이하기-1">2. 문제 풀이하기.</h3>
<p>Step 1. 모험가의 공포도를 오름차순으로 나열한다.
Step 2. 무한 반복문을 돌리고, <code>공포도의 최대가 공포도 길이보다 큰 경우,</code> 반복문의 종료 조건으로 걸어준다.
Step 3. 규칙에 따라 그룹으로 묶은 뒤에 공포도를 재설정하고 그룹 수를 세어준다.</p>
<p><strong>여기서 주의할 점은 나는 최소값을 이용하여 각 모험가의 공포도를 재설정하였다.</strong> </p>
<p>예를 들면 최소값이 3인 경우, 3명의 모험가가 필요하기 때문에 그 모험가를 1개의 집단에 넣을 수 있다. 그러므로 남은 공포도로 다시 집단을 구성해야하기 때문에, 최소값을 인덱스로 사용하여 이미 이룬 집단의 구성원들을 날려버렸다.</p>
<pre><code># 최적의 일반화

N=int(input())
data=list(map(int, input().split()))
count=0

data.sort() # sort에는 내림차순 매개변수가 존재한다.

while True:
    if min(data) in data:
        data=data[min(data):] 
        count+=1
    if max(data)&gt;len(data):
        break

print(count)</code></pre><p><del><strong>내가 풀이한 일반화는 좋지 않은 일반화이다. 왜냐하면 반복문 빠져나오는 조건이 안 좋기 때문이다.</strong></del></p>
<p>예를 들자면 [1,2,2,2,2,4]인 경우 위의 코드로 [1]이 하나로 묶이고 [2,3]도 하나로 묶일 수 있으나, [2,2] 또한 원래 묶일 수 있으나 4&gt;3 이기 때문에 무한 반복문이 끝나버린다. 따라서 이런 경우에는 원하는 답과 다른 결과가 나올 수 있다. 그러니 책에 나와있는 풀이로 이해를 하자.</p>
<h3 id="3-책에-나와있는-최적의-일반화">3. 책에 나와있는 최적의 일반화</h3>
<table>
<thead>
<tr>
<th align="center">기준</th>
<th align="center">나의 풀이</th>
<th align="center">책의 풀이</th>
</tr>
</thead>
<tbody><tr>
<td align="center">변수 설정</td>
<td align="center">그룹 수</td>
<td align="center"><strong>그룹 수와 모험가의 수</strong></td>
</tr>
<tr>
<td align="center">공포도 재설정</td>
<td align="center">인덱스 이용하기.</td>
<td align="center">모험가의 수가 공포도 이상임을 이용한다.</td>
</tr>
</tbody></table>
<p><strong>모험가의 수가 공포도가 동일한 경우</strong>, 그룹으로 지정하는 것이 최대 그룹 수로 묶는 방법이다. 그리고 <strong>공포도와 모험가의 수</strong>가 최대 그룹을 묶는 중요한 요인이기 때문에 <strong>2개의 변수를 이용했다.</strong></p>
<pre><code># 책에 나와있는 일반화 (숫자 대입한 코드)

N=5
data=[2,3,1,2,2]

result=0 # 총 그룹의 수
count=0 # 현재 그룹에 속한 모험가의 수
data.sort() # 오름차순 정렬하기. [1,2,2,2,3]으로 정렬하기.

for i in data: # 각 모험가의 공포도를 하나씩 가져오기.
    count+=1 # 모험가 +1명 포함시키기. 
    if count&gt;=i: # 공포도 기준으로 그룹핑하기 때문이다.
        result+=1 # 그룹으로 설정하기.
        count=0 # 모험가의 수 초기화하기.

print(result)</code></pre><pre><code># 책에 나와있는 일반화
# 변수를 2개를 이용 : 현재 그룹에 속한 모험가 수, 최대 그룹 수

N=int(input())
data=list(map(int, input().split()))

result=0
count=0
data.sort()

for data in data: # 1 &gt; 2 &gt; 2 &gt; 2 &gt; 3 순으로 등장한다.
    count+=1
    if count&gt;=data:
            result+=1
            count=0

print(result)</code></pre><h3 id="4-정리">4. 정리</h3>
<p>성능 : 나의 일반화 풀이 &lt;&lt; 책에 나와있는 일반화 풀이 </p>
<p><strong><em>변수를 지정할 때, 중요한 요소들을 뽑아서 모두 변수로 만들어주는 것이 좋아보인다.</em></strong></p>
<p>이 문제에서는 <strong>그룹에 포함되는 모험가 수 (공포도와 관련이 있으면서, 최대 그룹 수를 구하는 요인)와 최대 그룹 수 (구하고자 하는 값)가 중요하기 때문에,</strong> 변수를 2개를 이용하여 일반화하였다.</p>
<p><strong><em>결론 : 다음에 문제 풀 때에는 문제의 결과와 문제를 푸는 중요 요인을 찾아서 변수로 지정하기!!!</em></strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ML] Iris 데이터를 이용한 분류 모델]]></title>
            <link>https://velog.io/@tino-kim/Step1-ML-1f19l429</link>
            <guid>https://velog.io/@tino-kim/Step1-ML-1f19l429</guid>
            <pubDate>Tue, 03 Jan 2023 07:10:26 GMT</pubDate>
            <description><![CDATA[<h1 id="ml-iris-데이터를-이용한-분류-모델">[ML] Iris 데이터를 이용한 분류 모델</h1>
<h2 id="0-iris-데이터-처리-및-시각화">0. Iris 데이터 처리 및 시각화</h2>
<h3 id="step-1-iris-데이터-프레임-만들기">Step 1. Iris 데이터 프레임 만들기.</h3>
<pre><code>from sklearn.datasets import load_iris
iris = load_iris()</code></pre><p>iris 데이터를 불러왔는데, dictionary 형태이다. 데이터 프레임 형태로 변경해야 모델 학습 및 예측이 용이하기 때문에, 데이터 프레임 형태로 고쳐보자.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/ac755e15-43e5-4b84-b5fe-543ee3c73abe/image.png" alt=""></p>
<ul>
<li><code>DESCR</code>: 데이터셋의 정보를 보여준다. (description)</li>
<li><code>data</code>: feature data</li>
<li><code>feature_names</code>: feature data의 컬럼 이름</li>
<li><code>target</code>: label data (수치형)</li>
<li><code>target_names</code>: label의 이름 (문자형)</li>
</ul>
<p>data의 형태는 (150, 4)이고 target의 형태는 (150, )인 벡터이다. 그리고 feature (dimensionality)는 4개이며, class는 3개이다.</p>
<pre><code>data=iris.data # iris feature data
target=iris.target # iris target data
feature_names=iris.feature_names # iris feature names
target_names=iris.target_names # iris target names

df_iris=pd.DataFrame(data, columns=feature_names)
# feature data dataframe

df_iris[&quot;target&quot;]=target # add target data
df_iris.head()</code></pre><p>iris 데이터를 df_iris 라는 데이터 프레임으로 만들어주었다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/1fe4a71e-4144-4225-87bc-c39595df55fb/image.png" alt=""></p>
<h3 id="step-2-iris-데이터-시각화하기">Step 2. Iris 데이터 시각화하기.</h3>
<p>df_iris는 target이 숫자로 되어있어 시각화하는 경우에 보기가 불편하다. 따라서 숫자를 target_names로 변경하여 df_iris_visual 데이터 프레임을 만들자.</p>
<pre><code>df_iris_visual=df_iris.copy()
df_iris_visual.head()

df_iris_visual[&quot;target&quot;]=df_iris_visual[&quot;target&quot;].map({0:&#39;setosa&#39;, 1:&#39;versicolor&#39;, 2:&#39;virginica&#39;})
df_iris_visual.head()</code></pre><p>이렇게 직접 숫자와 target_names를 넣을 수도 있지만, class가 많은 경우에는 하기 힘들 수 있다. </p>
<p>따라서 리스트 컴프리헨션을 이용하여 dict을 만들어보자.</p>
<p><strong>Step 1. set을 이용하여 target에 어떤 숫자가 있는지 살펴보기.
Step 2. list + append 이용하여 key값 채우기.
Step 3. 리스트 컴프리헨션 이용하여 값이 0인 dict 만들어주기.
Step 4. dict의 값에 원하는 값 채우기.</strong></p>
<pre><code># step 1. target에 어떤 숫자가 있는지 확인하기.
set(iris.target) # target에 들어있는 숫자 알 수 있다.

# step 2. append 이용하여 리스트에 넣어주기.
target_list=[]

for key in range(3):
    target_list.append(key)

print(target_list)

# step 3. 리스트 컴프리헨션 이용하여 딕셔너리에 넣어주기.
target_dict={key : 0 for key in target_list}
target_dict # {0: 0, 1: 0, 2: 0}

# step 4. 딕셔너리 value에 값 넣어주기.

for idx in range(3):
    target_dict[idx]=iris.target_names[idx]

&quot;&quot;&quot;
target_dict[0]=iris.target_names[0]
target_dict[1]=iris.target_names[1]
target_dict[2]=iris.target_names[2]
&quot;&quot;&quot;</code></pre><p><strong><em>귀찮으면 리스트 컴프리헨션 이용 시에 dict의 값을 채워버릴 수도 있다.</em></strong></p>
<pre><code>{key : iris.target_names[key] for key in target_list}</code></pre><p>이후에는 동일하게 map을 이용하여 변경해주면 된다.</p>
<ol>
<li>sepal width와 sepal length 간 산점도 살펴보기.</li>
</ol>
<pre><code>fig = plt.figure(figsize=(6,4), dpi=200)
sns.scatterplot(data=df_iris_visual, x=&quot;sepal width (cm)&quot;
, y=&quot;sepal length (cm)&quot;, hue=&quot;target&quot;, palette=&quot;Set1&quot;)
plt.title(&#39;Sepal&#39;)
plt.legend(fontsize=8)
plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/tino-kim/post/2008932f-22c9-4ed0-bd93-93da843b3ee6/image.png" alt=""></p>
<ol start="2">
<li>petal width와 petal length 간 산점도 살펴보기.</li>
</ol>
<pre><code>fig = plt.figure(figsize=(6,4), dpi=200)
sns.scatterplot(data=df_iris_visual, x=&quot;petal length (cm)&quot;
, y=&quot;petal width (cm)&quot;, hue=&quot;target&quot;, palette=&quot;Set1&quot;)
plt.title(&#39;Petal&#39;)
plt.legend(fontsize=8)
plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/tino-kim/post/90e81eb4-8531-476e-af86-e5eeaa15cc74/image.png" alt=""></p>
<ol start="3">
<li>PCA를 이용하여 차원 축소한 뒤 3D로 표현하기.</li>
</ol>
<p>3차원은 x, y, z로 이루어져 있다.
따라서 feature가 4이므로, PCA를 이용하여 3차원으로 만들어준 뒤에 3D 그래프를 그려보았다.</p>
<pre><code>from mpl_toolkits.mplot3d import Axes3D
from sklearn.decomposition import PCA

fig = plt.figure(figsize=(8, 6), dpi=200)
ax = Axes3D(fig, elev=-150, azim=110) 
# elev, azim으로 각도를 조절한다.
X_reduced = PCA(n_components=3).fit_transform(df_iris.drop(&#39;target&#39;, axis=1)) 
# feature는 4개인데, 차원은 3차원이기 때문에 PCA 이용하여 차원 축소를 시켜준다.
ax.scatter(X_reduced[:, 0], X_reduced[:, 1], X_reduced[:, 2], c=df_iris[&#39;target&#39;],
           cmap=plt.cm.Set1, edgecolor=&#39;k&#39;, s=40) # target으로 색깔 구분하기.

ax.set_title(&quot;Iris 3D&quot;)
ax.set_xlabel(&quot;x&quot;)
ax.w_xaxis.set_ticklabels([])
ax.set_ylabel(&quot;y&quot;)
ax.w_yaxis.set_ticklabels([])
ax.set_zlabel(&quot;z&quot;)
ax.w_zaxis.set_ticklabels([])

plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/tino-kim/post/98135123-2454-4378-8d40-87b1b54fe725/image.png" alt=""></p>
<h3 id="step-3-훈련-데이터와-검증-데이터-나누기">Step 3. 훈련 데이터와 검증 데이터 나누기.</h3>
<p><strong>일단 X, y로 나눈 뒤에 train, validation으로 나눠주자.</strong></p>
<p>과정 1. X는 target을 제외한 모든 열을 의미하고, y는 target 열만 의미한다.
과정 2. train은 훈련 데이터이고, validation은 검증 데이터이다.</p>
<pre><code>from sklearn.model_selection import train_test_split

feature=list(df_iris.columns.difference([&quot;target&quot;]))
# difference는 차집합을 의미한다.
# 즉 모든 칼럼에서 target을 뺀 칼럼이 feature이다.

X=df_iris[feature] # target 제외한 데이터
X.head()

y=df_iris[&quot;target&quot;] # target 데이터


## 클래스의 분포 고려하지 않은 경우

x_train, x_valid, y_train, y_valid = train_test_split(X, y)
# 순서 주의하기. (x 먼저 쓰고, y 쓰기.)</code></pre><p>이 경우는 <strong><u>클래스의 분포를 고려하지 않고 데이터를 나눈 경우이다. stratify = y를 적용하면 클래스의 분포를 고려하여 데이터를 나눠준다.</u></strong></p>
<pre><code>import numpy as np

print(&quot;label count of y : &quot;, np.bincount(y))
print(&quot;label count of train_y : &quot;, np.bincount(y_train))
print(&quot;label count of valid_y : &quot;, np.bincount(y_valid))</code></pre><p>np.bincount를 이용하여 각 target에 해당되는 횟수를 구하였다. <strong>class의 비율을 고려하지 않아서 y_train의 개수가 균일하지 않음을 알 수 있다.</strong> 따라서 머신 러닝의 성능 저하를 일으킬 가능성이 높다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/c0f53715-f951-42b1-b027-ff7db6c5b14a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/768c097f-5775-430f-9ae7-6cff7d9081b7/image.png" alt=""></p>
<p>이번에는 클래스의 분포를 고려하여 데이터를 나누기 위하여 <code>stratify=y (클래스의 분포 고려)</code>를 이용하자.</p>
<pre><code>## 클래스의 분포를 고려한 경우

x_train, x_valid, y_train, y_valid = train_test_split(X, y, stratify=y)
# 순서 주의하기. (x 먼저 쓰고, y 쓰기.)</code></pre><pre><code>import numpy as np

print(&quot;label count of y : &quot;, np.bincount(y))
print(&quot;label count of train_y : &quot;, np.bincount(y_train))
print(&quot;label count of valid_y : &quot;, np.bincount(y_valid))</code></pre><p>np.bincount를 이용하여 각 target에 해당되는 횟수를 구하였다. <strong>class의 비율을 고려하여 y_train의 개수가 거의 균일함을 알 수 있다.</strong> 따라서 머신 러닝의 성능 저하를 일으킬 가능성이 적다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/5466e1d3-0f1c-4d6a-b4cf-e9f5b108ee80/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/24b2808b-515e-4f8d-8e17-198b2a221b4b/image.png" alt=""></p>
<h2 id="1-logistic-regression-로지스틱-회귀">1. Logistic Regression 로지스틱 회귀</h2>
<p>로지스틱 회귀 : 선형 관계에서 분류를 진행한다.
<strong>로지스틱 회귀와 SVM은 원래 이진 분류만 가능하다. 하지만 3개 이상인 경우 OvR 또는 OvO 방법을 이용한다.</strong></p>
<ul>
<li>OvR (one-vs-rest) : 1개 클래스와 (k-1)개 클래스로 이진 분류에 대한 확률을 구하고, <strong>총합을 통해 최종 클래스를 판별한다.</strong></li>
<li>OvO (one-vs-one) : 각각 1개씩 이진 분류하여 <strong>가장 많이 양성으로 선택된 클래스를 최종 클래스로 판별한다.</strong> 
(ex) 봄, 여름, 가을, 겨울 : 봄-여름, 봄-가을, 봄-겨울, ... , 가을-겨울 : 총 6개의 분류기이다.</li>
</ul>
<p><strong>대부분 계산 과정이 적은 OvR 전략을 선호한다.</strong></p>
<pre><code>from sklearn.linear_model import LogisticRegression

## Step 1. 모델 생성하기.
lr=LogisticRegression()

## Step 2. 모델 학습하기.
lr.fit(x_train, y_train)

## Step 3. 모델 예측하기.
pred=lr.predict(x_valid)

## Step 4. 모델 평가하기.
(pred==y_valid).mean() 
# 같으면 1, 다르면 0으로 지정하고 평균을 구하면 정확도가 나온다.</code></pre><h2 id="2-sgd-확률적-경사-하강법">2. SGD 확률적 경사 하강법</h2>
<p>확률적 경사 하강법 : 경사 하강법과 비슷한 알고리즘이다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/a60a99d4-044e-49a4-b6e5-becb93e6a341/image.png" alt=""></p>
<h3 id="2-1-모델-사용하기">2-1. 모델 사용하기.</h3>
<pre><code>from sklearn.linear_model import SGDClassifier

## Step 1. 모델 생성하기.
sgd=SGDClassifier()

## Step 2. 모델 학습하기.
sgd.fit(x_train, y_train)

## Step 3. 모델 예측하기.
pred=sgd.predict(x_valid)

## Step 4. 모델 평가하기.
(pred==y_valid).mean()</code></pre><h3 id="2-2-하이퍼-파라미터-튜닝하기">2-2. 하이퍼 파라미터 튜닝하기.</h3>
<pre><code>sgd = SGDClassifier(penalty=&#39;elasticnet&#39;, random_state=0, n_jobs=-1)
# penalty : 오버피팅을 방지
# random_state : 고정 (임의의 숫자를 넣어주기), 반드시 고정하기.
# n_jobs : 지원하는 알고리즘에는 설정해주는 것이 좋다. -1로 지정하면 CPU 모두 사용하겠다는 의미이다.</code></pre><p>이리저리 변경하면서 코드 돌려보기.</p>
<h2 id="3-kneighborclassifier-최근접-이웃-알고리즘">3. KNeighborClassifier 최근접 이웃 알고리즘</h2>
<p>최근접 이웃 알고리즘 : K 기준으로 클래스의 개수 세어줘서 <code>많은 클래스의 개수를 갖는 쪽으로 분류하기.</code> K는 홀수로 잡는 것이 좋다. 짝수인 경우에는 클래스의 개수가 같아지는 경우가 생길 수도 있기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/9c657a85-7c47-4733-8b83-58115fe0b04b/image.png" alt=""></p>
<pre><code>from sklearn.neighbors import KNeighborsClassifier

## Step 1. 모델 생성하기.
knc=KNeighborsClassifier(n_jobs=-1)

## Step 2. 모델 학습하기.
knc.fit(x_train, y_train)

## Step 3. 모델 예측하기.
pred=knc.predict(x_valid)

## Step 4. 모델 평가하기.
(pred==y_valid).mean()</code></pre><pre><code>knc = KNeighborsClassifier(n_neighbors=7, n_jobs=-1)
knc.fit(x_train, y_train)
knc_pred = knc.predict(x_valid)
(knc_pred==y_valid).mean()</code></pre><h2 id="4-svc-서포트-벡터-머신">4. SVC 서포트 벡터 머신</h2>
<p>서포트 벡터 머신 : 이진 분류만 가능하다. (다중 분류인 경우 OvO나 OvR 이용하기.) <strong>경계로 표현되는 데이터들 중에서 가장 큰 폭을 가진 경계를 찾는 알고리즘이다.</strong></p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/4cac8ad0-5026-432f-b0c2-ccd241328261/image.png" alt=""></p>
<pre><code>from sklearn.svm import SVC

## Step 1. 모델 생성하기.
svc=SVC(random_state=0)

## Step 2. 모델 학습하기.
svc.fit(x_train, y_train)

## Step 3. 모델 예측하기.
pred=svc.predict(x_valid)

## Step 4. 모델 평가하기.
(pred==y_valid).mean()</code></pre><p>decision_function을 이용하여 <code>각 클래스 별 확률값</code>을 보여줄 수 있다. 같은 행 중에서 가장 큰 확률값을 가진 클래스를 선택하기.</p>
<pre><code>svc.decision_function(x_valid)[:5] # 각 클래스 별 확률값을 반환한다.</code></pre><h2 id="5-decision-tree-의사-결정-나무">5. Decision Tree 의사 결정 나무</h2>
<p>의사 결정 나무 : 스무고개처럼, 나무 가지치기를 통하여 소그룹으로 나누어 판별하는 알고리즘이다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/9344433c-51b9-4b40-8b58-e3a4e4930442/image.png" alt=""></p>
<pre><code>from sklearn.tree import DecisionTreeClassifier

## Step 1. 모델 생성하기.
dtc=DecisionTreeClassifier()

## Step 2. 모델 학습하기.
dtc.fit(x_train, y_train)

## Step 3. 모델 예측하기.
pred=dtc.predict(x_valid)

## Step 4. 모델 평가하기.
(pred==y_valid).mean()</code></pre><p>graphviz를 이용하여 의사 결정 나무 구조를 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/8560cf7d-822f-4e7c-b4d9-dd9cf85d23a7/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/ac4643b9-8cc2-45ad-a062-2b655cc3073c/image.png" alt=""></p>
<p>위의 내용을 이용하여 .png로 변환하여 의사 결정 나무 구조를 그리는 함수를 만들었다.</p>
<pre><code>from sklearn.tree import export_graphviz
from subprocess import call

def graph_tree(model):
    # .dot 파일로 export 해줍니다
    export_graphviz(model, out_file=&#39;tree.dot&#39;)

    # 생성된 .dot 파일을 .png로 변환
    call([&#39;dot&#39;, &#39;-Tpng&#39;, &#39;tree.dot&#39;, &#39;-o&#39;, &#39;decistion-tree.png&#39;, &#39;-Gdpi=600&#39;])

    # .png 출력
    return Image(filename = &#39;decistion-tree.png&#39;, width=500)

graph_tree(dtc)</code></pre><p><img src="https://velog.velcdn.com/images/tino-kim/post/6b5141f0-bbbf-43b0-83ec-2bbf87ca5f88/image.png" alt=""></p>
<p>하이퍼 파라미터를 통해 깊이를 조정할 수 있다.</p>
<pre><code>dtc = DecisionTreeClassifier(max_depth=2) # 깊이를 제한하기.
dtc.fit(x_train, y_train)
dtc_pred = dtc.predict(x_valid)
(dtc_pred==y_valid).mean()

graph_tree(dtc)</code></pre><p><img src="https://velog.velcdn.com/images/tino-kim/post/93297476-64ca-45d9-87e5-f674eb176394/image.png" alt=""></p>
<p>너무 깊게 들어가면 과적합 위험이 있기 때문에, 깊이를 조정해주는 것이다.</p>
<ul>
<li>(추가 방법) Windows export_graphviz Install and Use</li>
</ul>
<p>Step 1. tree.dot으로 내보내기.
Step 2. prompt에서 export_graphviz 설치하기.
Step 3. .png로 변환하기.</p>
<pre><code>## Step 1.
tree.export_graphviz(clf,
                     out_file=&quot;tree.dot&quot;,
                     feature_names = fn, 
                     class_names=cn,
                     filled = True)

## Step 2.
conda install python-graphviz

## Step 3.
dot -Tpng tree.dot -o tree.png</code></pre><ul>
<li>참고 문서 : <a href="https://towardsdatascience.com/visualizing-decision-trees-with-python-scikit-learn-graphviz-matplotlib-1c50b4aa68dc">Visualizing Decision Trees with Python (Scikit-learn, Graphviz, Matplotlib)</a></li>
</ul>
<h2 id="6-오차">6. 오차</h2>
<h3 id="6-1-정확도의-한계">6-1. 정확도의 한계</h3>
<p>breast_cancer() 데이터를 로드해서 가져왔다. 양성 데이터와 음성 데이터 5개를 이용하여 샘플 데이터를 만들고 로지스틱 회귀모형을 이용하여 분류를 하였는데 정확도가 0.98정도 나왔다. 그리고 모두 1이라고 예측을 하고 정확도가 0.99정도 나왔다.</p>
<pre><code>lr=LogisticRegression()
lr.fit(train_x, train_y)
pred=lr.predict(test_x)
(pred==test_y).mean() # 0.98

my_pred=lr.predict(np.ones(shape=test_y.shape)) # 1로만 예측하기.
(my_pred==test_y).mean() # 0.99</code></pre><p><strong><em>과연 1이라고만 예측한 분류기가 정말 좋은 분류기일까? 정확도로만 성능을 판단하는 것은 오류를 불러일으킬 수 있다.</em></strong></p>
<p>그래서 실제 분류기 성능을 알기 위한 방법들이 존재한다.</p>
<ol>
<li>혼동 행렬</li>
<li>정밀도</li>
<li>재현율</li>
<li>f1-score</li>
</ol>
<h3 id="6-2-혼동-행렬-confusion-metrix">6-2. 혼동 행렬 (Confusion Metrix)</h3>
<p>실제 분류기 성능을 알 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/91a1d252-a12b-405a-a203-1c058d31d7ef/image.png" alt=""></p>
<pre><code>from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, pred)</code></pre><p>heatmap을 이용하여 혼동 행렬을 그릴 수 있다.</p>
<pre><code>plt.figure(figsize=(4,2), dpi=200)
sns.heatmap(confusion_matrix(y_test, pred), annot=True, cmap=&quot;Reds&quot;)
plt.xlabel(&#39;Predict&#39;)
plt.ylabel(&#39;Actual&#39;)
plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/tino-kim/post/015628d6-58ef-40f2-8ccc-dd0013ac53d3/image.png" alt=""></p>
<h3 id="6-3-정밀도-precision">6-3. 정밀도 (Precision)</h3>
<p>분모가 positive라고 예측한 합이다. </p>
<p><strong>정밀도 = (진짜 1인 경우) / (1이라고 예측한 경우)</strong> = $$\frac{tp}{tp + fp}$$</p>
<pre><code>from sklearn.metrics import precision_score
precision_score(y_test, pred)</code></pre><h3 id="6-4-재현율-recall">6-4. 재현율 (Recall)</h3>
<p>분모가 positive의 합이다. 그래서 진짜 양성의 비율을 의미하여 <strong><em>TPR (True Positive Rate)</em></strong> 라고 불리기도 한다.</p>
<p><strong>재현율 = (1이라고 예측하고 진짜 1인 경우) / (진짜 1인 경우)</strong> = $$\frac{tp}{tp + fn}$$</p>
<h3 id="6-5-f1-score">6-5. F1-Score</h3>
<p>정밀도와 재현율은 상관 관계이다. (trade-off 관계) 한 쪽이 오르면 다른 한쪽은 떨어지는 관계를 가진다. 그래서 정밀도와 재현율의 <strong>조화 평균</strong>인 $$f1-score$$가 등장한다.</p>
<p>$$2*\frac{정밀도 * 재현율}{정밀도 + 재현율}=\frac{TP}{TP+\frac{FN+FP}{2}}$$</p>
<pre><code>from sklearn.metrics import f1_score
f1-score(y_test, pred)</code></pre><p>그래서 공모전에서 $$f1-score$$ 로 성능을 체크하는 경우가 많은 것 같다.</p>
<p><img src="https://velog.velcdn.com/images/tino-kim/post/7bc398ca-de61-4c7a-81bc-a187c47bf039/image.png" alt=""></p>
<ul>
<li>빨간색 부분이 정밀도와 관련이 있다. (positive라고 예측한 것의 합)</li>
<li>녹색 부분이 재현율과 관련이 있다. (진짜 positive의 합)</li>
<li>f1-score는 정밀도와 재현율의 조화 평균이다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>