<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>black-mins.log</title>
        <link>https://velog.io/</link>
        <description>BE</description>
        <lastBuildDate>Tue, 27 Apr 2021 16:47:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>black-mins.log</title>
            <url>https://images.velog.io/images/black-mins/profile/b1e8f523-7b10-4e50-a65b-556bbc29a761/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. black-mins.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/black-mins" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Algorism/HackerRank] Frequency Queries]]></title>
            <link>https://velog.io/@black-mins/AlgorismHackerRank-Frequency-Queries</link>
            <guid>https://velog.io/@black-mins/AlgorismHackerRank-Frequency-Queries</guid>
            <pubDate>Tue, 27 Apr 2021 16:47:45 GMT</pubDate>
            <description><![CDATA[<h3 id="👉-문제-링크">👉 <a href="https://www.hackerrank.com/challenges/frequency-queries/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=dictionaries-hashmaps">문제 링크</a></h3>
<h3 id="✏️-문제-요약">✏️ 문제 요약</h3>
<ul>
<li>숫자를 저장, 제거, 빈도수 검색을 할 수 있는 쿼리 메소드를 만듬</li>
<li>숫자를 저장하면 빈도수는 증가</li>
<li>숫자를 제거하면 빈도수는 감소<blockquote>
<p>ex 쿼리...
1 1 // 숫자 1 저장
1 1 // 숫자 1 저장
3 2 // 빈도수 2를 검색했을 때 숫자 1이 있음
2 1 // 숫자 1 제거
3 1 // 빈도수 1로 검색했을 때 숫자 1이 있음
1 3 // 숫자 3 저장
3 1 // 빈도수 1로 검색했을 때 숫자 1 또는 3이 있음</p>
</blockquote>
</li>
</ul>
<h3 id="💡-문제-풀이">💡 문제 풀이</h3>
<ul>
<li><p><strong>숫자별로 빈도수를 관리하기 위해 맵을 사용</strong>
=&gt; 단, 맵 하나만 사용하면 맵의 모든 value에서 빈도수와 일치하는 값을 검색해야 함
=&gt; 맵을 하나만 사용하면 TC 중 검색 쿼리시에 1개에서 타임 아웃 발생함
=&gt; 문제에서 원하는건 검색시에도 O(1)만 원하는 것으로 보임
=&gt; Worst Case에서는 명령어 loop까지 O(N^2)이라서 그럴지도...</p>
</li>
<li><p>상단 타임아웃 처리를 위해 빈도수를 기준으로 몇 개의 숫자가 있는지 관리하는 맵 사용</p>
</li>
</ul>
<h3 id="💻-구현-코드">💻 구현 코드</h3>
<details>
<summary>코드 보기</summary>

<pre><code class="language-java">    static final int INSERT_COMMAND = 1;
    static final int DELETE_COMMAND = 2;
    static final int SEARCH_COMMAND = 3;

    // Complete the freqQuery function below.
    static List&lt;Integer&gt; freqQuery(List&lt;List&lt;Integer&gt;&gt; queries) {
        List&lt;Integer&gt; answerList = new ArrayList&lt;&gt;();

        Map&lt;Integer, Integer&gt; numberMap = new HashMap&lt;&gt;();  // 저장할 숫자 기준으로 빈도수를 가지고 있는 맵
        Map&lt;Integer, Integer&gt; frequencyMap = new HashMap&lt;&gt;();  // 빈도수를 기준으로 몇개의 숫자가 있는지 관리하는 맵

        for (List&lt;Integer&gt; query : queries) {
            int command  = query.get(0);
            int num = query.get(1);

            switch (command) {
                case INSERT_COMMAND:
                    if (numberMap.containsKey(num)) { 
                        // 저장전 빈도수 관리맵에서 해당 숫자의 빈도수를 제거
                        frequencyMap.computeIfPresent(numberMap.get(num), (key, frequency) -&gt; frequency - 1);
                    }

                    numberMap.merge(num, 1, Integer::sum);

                    // 저장후 빈도수 관리맵에서 해당 숫자의 빈도수를 추가
                    frequencyMap.compute(numberMap.get(num), (key, frequency) -&gt; frequency == null ? 1 :  frequency + 1);
                    break;
                case DELETE_COMMAND:
                    if (numberMap.containsKey(num)) {
                        // 저장 명령어와 동일한 처리
                        frequencyMap.computeIfPresent(numberMap.get(num), (key, frequency) -&gt; frequency - 1);
                    }

                    numberMap.computeIfPresent(num, (key, value) -&gt; value &gt; 0 ? value - 1 : 0);

                    if (numberMap.containsKey(num)) {
                        // 저장 명령어와 동일한 처리
                        frequencyMap.compute(numberMap.get(num), (key, frequency) -&gt; frequency == null ? 1 : frequency + 1);
                    }
                    break;
                case SEARCH_COMMAND:
                    int answer =  frequencyMap.getOrDefault(num, 0) &gt; 0 ? 1 : 0;
                    answerList.add(answer);
                    break;
            }
        }

        return answerList;
    }</code></pre>
</details>]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorism/HackerRank] Greedy Florist]]></title>
            <link>https://velog.io/@black-mins/AlgorismHackerRank-Greedy-Florist</link>
            <guid>https://velog.io/@black-mins/AlgorismHackerRank-Greedy-Florist</guid>
            <pubDate>Mon, 26 Apr 2021 16:48:55 GMT</pubDate>
            <description><![CDATA[<h3 id="👉-문제-링크">👉 <a href="https://www.hackerrank.com/challenges/greedy-florist/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=greedy-algorithms">문제 링크</a></h3>
<h3 id="✏️-문제-요약">✏️ 문제 요약</h3>
<ul>
<li>친구들에게 덤탱이 씌운 꽃 가격을 최소한의 비용으로 구매하라</li>
<li>덤탱이 공식: <strong>한 사람이 꽃을 2개이상 사는경우, 2개부터는 1개를 더한 값으로 받는다.</strong>
$$
\displaystyle\ 3 * (1)+ 2 * (1 + 1) + 1 * (2 + 1) = 10
$$<blockquote>
<p>ex:) [1, 2, 3] 각각의 꽃 가격일 때, 한 사람이 꽃을 사는 최소 비용은 위 수식과 같다.
제일 비싼 3원짜리 꽃을 1개 삼
그 다음 비싼 2원짜리 꽃은 이전에 3원짜리를 샀으므로 1개를 더한 값으로 구매
마지막 1원짜리를 사기전에는 2원, 3원 꽃을 산 만큼 2개를 더한 값으로 구매</p>
</blockquote>
</li>
</ul>
<h3 id="💡-문제-풀이">💡 문제 풀이</h3>
<ul>
<li><p>최소 비용으로 구매하려면 덤탱이 없이 원래 꽃 가격으로 사야한다.
=&gt; 모든 꽃을 1개씩은 사야하므로, 구매할 꽃의 개수보다 인원 수가 많거나 같으면 덤탱이를 당할일이 없다.</p>
</li>
<li><p>꽃을 구매할 인원 수가 꽃 개수보다 작은 경우, 덤탱이를 최대한 줄여야한다.
=&gt; 싼 가격에 큰 수 덤탱이를 곱해야 비용이 줄어든다.</p>
</li>
<li><p>위 2개를 조합해 보면...</p>
<ul>
<li>비싼 꽃부터 인원 수만큼 구매한다.</li>
<li>꽃을 다 구매했다면, 최소비용이다.</li>
<li>아직 더 사야할 꽃이 있다면, 모든 인원이 꽃을 샀기 때문에 덤탱이 개수가 1개씩 증가한 가격으로 꽃을 구매한다. 이 때도, 비싼 꽃부터 덤탱이 공식으로 구매한다.</li>
<li>이 내용을 반복한다.</li>
</ul>
</li>
</ul>
<h3 id="💻-구현-코드">💻 구현 코드</h3>
<ol>
<li><p>주어진 배열을 내림차순으로 정렬</p>
</li>
<li><p>인원 수만큼 꽃을 사보고, 꽃이 남아 있으면 덤탱이를 씌움</p>
</li>
</ol>
<details>
<summary>코드 보기</summary>

<pre><code class="language-java">    static int getMinimumCost(int k, int[] c) {
        List&lt;Integer&gt; descendingList = Arrays.stream(c).boxed()
                .sorted(Collections.reverseOrder())
                .collect(Collectors.toList());

        int minimizedCost = 0;
        int multiply = 0;  // 덤탱이 곱셈

        for (int i = 0; i &lt; descendingList.size(); i++) {
            if (i % k == 0) {
                multiply++;
            }

            minimizedCost += (multiply) * descendingList.get(i);
        }

        return minimizedCost;
    }</code></pre>
</details>]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorism/HackerRank] Sherlock and Anagrams]]></title>
            <link>https://velog.io/@black-mins/AlgorismHackerRank-Sherlock-and-Anagrams</link>
            <guid>https://velog.io/@black-mins/AlgorismHackerRank-Sherlock-and-Anagrams</guid>
            <pubDate>Mon, 19 Apr 2021 11:16:36 GMT</pubDate>
            <description><![CDATA[<h3 id="👉-문제-링크">👉 <a href="https://www.hackerrank.com/challenges/sherlock-and-anagrams/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=dictionaries-hashmaps">문제 링크</a></h3>
<h3 id="✏️-문제-요약">✏️ 문제 요약</h3>
<ul>
<li><p>주어진 문자열에서 Anagram 경우의 수가 되는 부분 문자열 찾기</p>
<blockquote>
<p>Anagram은 문자열 순서를 바꿔 동일한 철자로 이루어진 문자열 쌍을 말함
ex:) abc == cba</p>
</blockquote>
</li>
<li><p>단, 주어진 문자열의 순서를 변경한 경우의 수는 고려하지 않는다.</p>
<blockquote>
<p>현재 알고리즘 문제의 Anagram 조건이므로 다른 문제에서는 해당하지 않음
주어진 문자열: abca 라고 했을 때, 임의로 caab와 같은 식으로 주어진 문자열을 변경하지는 않는다.</p>
</blockquote>
</li>
<li><p>하지만 Anagram의 경우의 수가 되는 부분 문자열은 문자열 순서가 변경되어도 됨</p>
<blockquote>
<p>주어진 문자열: abca 에서 Anagram을 찾기 위한 부분 집합 비교로 [ab], [ac(= ca를 뒤집음)]  식으로 확인하는 비교는 가능함</p>
</blockquote>
</li>
</ul>
<h3 id="💡-문제-풀이">💡 문제 풀이</h3>
<ul>
<li><ol>
<li>Anagram이 가능한 부분 문자열은 순서를 변경하여 비교가 가능하므로, 고정된 순서로 정렬 후 비교하면 쌍을 이루는지 쉽게 비교 가능하다.
따라서 모든 부분 문자열을 뽑아 알파벳 순서(오름차순, 내림차순 아무거나)를 정하여, 부분 문자열을 Key로 가진 해쉬맵으로 해당 문자열 개수를 카운팅 한다.<blockquote>
<p>알파벳 순서와 상관없이 카운팅하기 때문에 count &gt; 1인 경우는 Anagram이 가능한 쌍이 존재한다.</p>
</blockquote>
</li>
</ol>
</li>
<li><ol start="2">
<li>부분 문자열의 경우의 수는 카운트 수(n)개 중 2개를 뽑는 경우의 수(=수학 조합)와 같다.
$$
\begin{pmatrix}
n\
2
\end{pmatrix}
$$<blockquote>
<p>예시는 단일 문자열 a로만 나타내고, ab, abc처럼 다른 알파벳과 결합되어 있는 부분 문자열의 경우도 순서가 중요하지 않기 때문에 아래의 규칙과 동일하다.
(n, m)은 index를 의미함</p>
<ul>
<li>주어진 문자열: aa</li>
</ul>
<ol>
<li>a 가 1개인 문자열 수는 2개이므로, Anagram이 가능한 경우의 수는 2C2 ==&gt; 1개
(0, 1)</li>
<li>a 가 2개인 문자열 수는 1개이므로, Anagram 쌍이 없음
총: 1개<br/></li>
</ol>
<ul>
<li>주어진 문자열: aaa</li>
</ul>
<ol>
<li>a 가 1개인 문자열 수는 3개이므로, Anagram이 가능한 경우의 수는 3C2 ==&gt; 3개
(0, 1), (0, 2), (1, 2)</li>
<li>a 가 2개인 문자열 수는 2개이므로, Anagram이 가능한 경우의 수는 2C2 ==&gt; 1개
(0<del>1, 1</del>2)</li>
<li>a 가 3개인 문자열 수는 1개이므로, Anagram 쌍이 없음
총: 4개<br/></li>
</ol>
<ul>
<li>주어진 문자열: aaaa</li>
</ul>
<ol>
<li>a 가 1개인 문자열 수는 4개이므로, Anagram이 가능한 경우의 수는 4C2 ==&gt; 6개
(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)</li>
<li>a 가 2개인 문자열 수는 3개이므로, Anagram이 가능한 경우의 수는 3C2 ==&gt; 3개
(0<del>1, 1</del>2), (0<del>1, 2</del>3), (1<del>2, 2</del>3)</li>
<li>a 가 3개인 문자열 수는 2개이므로, Anagram이 가능한 경우의 수는 2C2 ==&gt; 1개
(0<del>2, 1</del>3)</li>
<li>a 가 4개인 문자열 수는 1개이므로, Anagram 쌍이 없음
총: 10개<br/>
</li>
</ol>
</blockquote>
</li>
</ol>
</li>
</ul>
<ol start="3">
<li>상기 2번을 어떻게 구현하냐에 따라 구현이 좀 더 간단해 질 수 있음
구현 코드에서는 조합식이 등차수열의 합 공식과 동일하게 도출되어 등차수열의 합 공식을 사용함</li>
</ol>
<h3 id="💻-구현-코드">💻 구현 코드</h3>
<details>
<summary>코드 보기</summary>

<pre><code class="language-java">    public static int sherlockAndAnagrams(String s) {
        Map&lt;String, Integer&gt; countMap = new HashMap&lt;&gt;();

        for (int i = 0; i &lt; s.length(); i++) {
            for (int j = i + 1; j &lt; s.length() + 1; j++) {
                // 부분 문자열을 알파벳 오름차순 순서로 변경하여 새로운 부분 문자열을 생성
                String a = s.substring(i, j).chars()
                        .sorted()
                        .mapToObj(ch -&gt; String.valueOf((char) ch))
                        .collect(Collectors.joining());

                // 부분 문자열을 카운팅하는 해쉬맵에 저장
                countMap.merge(a, 1, Integer::sum);
            }
        }

        // 카운팅된 수를 기준으로 2개를 뽑아 조합한 값이 개별 경우의 수
        // 각 개별 경우의 수를 합한 값이 총 문자열의 Anagram 경우의 수
        return countMap.values().stream()
                .filter(value -&gt; value &gt; 1)
                .mapToInt(value -&gt; value * (value - 1) / 2)
                .sum();
    }</code></pre>
</details>]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorism/HackerRank] Max Min]]></title>
            <link>https://velog.io/@black-mins/AlgorismHackerRank-Max-Min</link>
            <guid>https://velog.io/@black-mins/AlgorismHackerRank-Max-Min</guid>
            <pubDate>Tue, 13 Apr 2021 17:13:11 GMT</pubDate>
            <description><![CDATA[<h3 id="👉-문제-링크">👉 <a href="https://www.hackerrank.com/challenges/angry-children/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=greedy-algorithms">문제 링크</a></h3>
<h3 id="✏️-문제-요약">✏️ 문제 요약</h3>
<ul>
<li>주어진 숫자 배열에서 k개의 숫자들 중에 (가장 큰 수 - 가장 작은 수)의 값이 가장 작은 결과를 찾아라
= k 개의 숫자 중 2개의 숫자를 뽑아 차이가 가장 작은 결과</li>
</ul>
<h3 id="💡-문제-풀이">💡 문제 풀이</h3>
<ul>
<li><p>직관적으로 생각하면 숫자 배열을 우선 정렬하고, k번째의 수(k개 중 가장 큰 수) - 첫번째 수(k개 중 가장 작은 수)로 구함</p>
</li>
<li><p>하지만 주의해야 할 케이스(반례 케이스)가 2가지 존재함</p>
<ol>
<li><p>2개의 숫자 차이가 0이 되는 경우
=&gt; 동일한 2개의 숫자를 뽑아 0을 만들면 가장 작은 수가 됨</p>
<blockquote>
<p>ex:) k = 2, 주어진 배열 = [1, 2, 1, 2, 1]인 경우
=&gt; (2, 2)를 뽑음</p>
</blockquote>
</li>
<li><p>정렬된 상태의 k번째의 수 - 첫번째 수가 반드시 최적해를 만족하지 못 함
=&gt; 연속된 작은 숫자, 연속된 큰 숫자 상관없이 <strong>연속성이 더 좋은 숫자 배열이 최적해를 만족함</strong></p>
<blockquote>
<p>ex:) k = 3, 주어진 배열 = [1, 5, 6, 100, 101, 102]인 경우 
=&gt; (100, 101, 102)를 뽑음</p>
</blockquote>
</li>
</ol>
</li>
</ul>
<h3 id="💻-구현-코드">💻 구현 코드</h3>
<ol>
<li><p>주어진 배열을 우선 정렬</p>
</li>
<li><p>반례까지 포함하여 계산을 해야하므로, 정렬된 배열을 끝까지 계산해 봐야됨</p>
</li>
</ol>
<details>
<summary>코드 보기</summary>

<pre><code class="language-java">    public static int maxMin(int k, int[] arr) {
        Arrays.sort(arr);

        int minimizedValue = Integer.MAX_VALUE;  // 최적해를 구하기전 임시값 설정

        for (int i = 0; i &lt; arr.length - k + 1; i++) {
            // k개의 숫자 중 가장 큰 수와 작은 수의 차이를 구함
            int temp = arr[i + k - 1] - arr[i];

            if (minimizedValue &gt; temp) {
                minimizedValue = temp;
            }
        }

        return minimizedValue;
    }</code></pre>
</details>]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorism/HackerRank] Luck Balance]]></title>
            <link>https://velog.io/@black-mins/AlgorismHackerRank-Luck-Balance</link>
            <guid>https://velog.io/@black-mins/AlgorismHackerRank-Luck-Balance</guid>
            <pubDate>Tue, 13 Apr 2021 15:34:14 GMT</pubDate>
            <description><![CDATA[<h3 id="👉-문제-링크">👉 <a href="https://www.hackerrank.com/challenges/luck-balance/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=greedy-algorithms">문제 링크</a></h3>
<h3 id="✏️-문제-요약">✏️ 문제 요약</h3>
<ul>
<li><p>주인공은 행운이 축적된다고 믿으며, 코딩 대회를 준비중
코딩 대회에서 이기면 행운이 감소하고, 진다면 행운이 추가된다고 믿음 </p>
</li>
<li><p>대회별로 행운 수치가 다름</p>
</li>
<li><p><strong>가장 큰 행운 축적값을 구하고자 함</strong></p>
</li>
<li><p><strong>단, 중요한 대회는 k번이 있으며 k번은 무조건 져야함
그리고 k번을 지고난 이후의 중요한 대회는 무조건 이겨야함</strong></p>
</li>
</ul>
<h3 id="💡-문제-풀이">💡 문제 풀이</h3>
<ul>
<li><p>대회를 이기든, 지든 문제 풀이와는 연관 없음</p>
</li>
<li><p>모든 대회를 지는 것이 가장 큰 행운 축적값이 됨</p>
</li>
<li><p>탐욕 알고리즘을 사용해 보면 직관적으로 행운 수치가 큰 대회를 지면 됨
중요한 대회에서는 점수가 큰 k번의 대회에서 지고, 이외에 중요한 대회에서는 이기면 됨
계산을 쉽게 하기 위해 정렬을 이용</p>
</li>
</ul>
<h3 id="💻-구현-코드">💻 구현 코드</h3>
<ol>
<li><p>주어진 배열을 우선 정렬
중요도가 높은 순서로 먼저 정렬
중요도가 동일한 경우는 행운 수치가 높은 순서로 정렬(중요하지 않은 대회는 정렬이 필요없긴 함)</p>
</li>
<li><p>중요한 대회는 k번을 지고, 나머지는 이김
중요하지 않은 대회는 모두 짐</p>
</li>
</ol>
<details>
<summary>코드 보기</summary>

<pre><code class="language-java">    public static int luckBalance(int k, int[][] contests) {
        sortOrderByImportantAndLuckValue(contests);

        int balance = 0;

        for (int i = 0; i &lt; contests.length; i++) {
            if (contests[i][1] == 1) {
                if (k &gt; 0) {
                    k--;        // 중요한 경기는 k번만 가능함
                    balance += contests[i][0];      // 이미 행운 값이 큰 순서로 정렬이 되어 있으므로 k번의 중요 경기는 모두 지는 것으로 간주
                } else {
                    balance -= contests[i][0];
                }
            } else {
                balance += contests[i][0];
            }
        }

        return balance;
    }

    /**
     * 중요도 높은 순서(중요 -&gt; 비중요)로 우선 정렬(내림차순)
     * 중요도가 동일한 경우, 행운 값이 더 많은 순서로 정렬(내림차순)
     */
    public static void sortOrderByImportantAndLuckValue(int[][] arr) {
        Arrays.sort(arr, (a, b) -&gt; {
            if (a[1] &lt; b[1]) {
                return 1;
            } else if (a[1] == b[1]) {
                return b[0] - a[0];
            } else {
                return -1;
            }
        });
    }</code></pre>
</details>]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorism/HackerRank] Roads and Libraries]]></title>
            <link>https://velog.io/@black-mins/Algorism-HackerRank-Roads-and-Libraries</link>
            <guid>https://velog.io/@black-mins/Algorism-HackerRank-Roads-and-Libraries</guid>
            <pubDate>Tue, 06 Apr 2021 17:16:21 GMT</pubDate>
            <description><![CDATA[<h3 id="👉-문제-링크">👉 <a href="https://www.hackerrank.com/challenges/torque-and-development/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=graphs">문제 링크</a></h3>
<h3 id="✏️-문제-요약">✏️ 문제 요약</h3>
<ul>
<li><strong>모든 도시에서 방문할 수 있는 도서관을 최소 비용으로 지어야함</strong></li>
<li>비용은 크게 도서관 건설 비용, 도시를 연결하는 도로 비용 2가지 존재</li>
<li>연결이 가능한 도시 목록을 가지고 있음</li>
<li>도서관 건설 최소 비용에 따라 도시별로 도로는 연결될 수도 있고, 아닐수도 있음</li>
</ul>
<h3 id="💡-문제-풀이">💡 문제 풀이</h3>
<ul>
<li><p>도서관 건설 비용 &lt;= 도로 연결 비용인 경우</p>
<blockquote>
<p>도로 연결 비용보다 도서관 건설 비용이 저렴한 경우에는 각 도시별로 도서관을 짓는게 최소 비용</p>
</blockquote>
</li>
<li><p>도서관 건설 비용 &gt; 도로 연결 비용인 경우</p>
<blockquote>
<p>특정 한 도시에 도서관을 짓고, 연결할 수 있는 모든 도시의 도로를 연결
1개의 도로로 2개의 도시를 연결 할 수 있으므로, 2개의 도시를 연결한 경우 1개의 도로 건설 비용만 부가</p>
</blockquote>
</li>
<li><p>자료구조</p>
<blockquote>
<p>구현 코드에서는 모든 연결된 도시의 경우의 수를 파악하기 위해 그래프 사용</p>
</blockquote>
</li>
</ul>
<h3 id="💻-구현-코드">💻 구현 코드</h3>
<ul>
<li>리스트를 활용한 그래프 사용</li>
<li>그래프 탐색 방법으로는 DFS를 재귀로 구현</li>
<li>모든 도시는 단 1번만 방문하므로, 도시별 방문 횟수는 결국 도시별 도서관 수 or 도시간의 연결하는 도로의 개수를 구하는데 사용함</li>
</ul>
<details>
<summary>코드 보기</summary>

<pre><code class="language-java">    // 도서관 건설 최소 비용을 구함
    static long roadsAndLibraries(int n, int c_lib, int c_road, int[][] cities) {
        List&lt;ArrayList&lt;Integer&gt;&gt; roadGraph = initRoadGraph(n, cities);
        boolean[] visited = new boolean[n];

        long totalCost = 0;

        for (int i = 0; i &lt; roadGraph.size(); i++) {
            if (!visited[i]) {
                if (c_lib &gt; c_road) {
                    totalCost += c_lib + (c_road * (countNumberOfVisitsByDfs(i, visited, roadGraph) - 1));
                } else {
                    totalCost += c_lib * countNumberOfVisitsByDfs(i, visited, roadGraph);
                }
            }
        }

        return totalCost;
    }

    // 도시간 연결하는 그래프
    static List&lt;ArrayList&lt;Integer&gt;&gt; initRoadGraph(int n, int[][] cities) {
        List&lt;ArrayList&lt;Integer&gt;&gt; roadGraph = new ArrayList&lt;&gt;();

        for (int i = 0; i &lt; n; i++) {
            roadGraph.add(new ArrayList&lt;&gt;());
        }

        for (int i = 0; i &lt; cities.length; i++) {
            roadGraph.get(cities[i][0] - 1).add(cities[i][1] - 1);
            roadGraph.get(cities[i][1] - 1).add(cities[i][0] - 1);
        }

        return roadGraph;
    }

    // 도시별 방문 횟수
    static long countNumberOfVisitsByDfs(int index, boolean[] visited, List&lt;ArrayList&lt;Integer&gt;&gt; roadGraph) {
        long cityVisitCount = 1;
        visited[index] = true;

        for (int i = 0; i &lt; roadGraph.get(index).size(); i++) {
            if (!visited[roadGraph.get(index).get(i)]) {
                cityVisitCount += countNumberOfVisitsByDfs(roadGraph.get(index).get(i), visited, roadGraph);
            }
        }

        return cityVisitCount;
    }</code></pre>
</details>]]></description>
        </item>
    </channel>
</rss>