<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>TH</title>
    <link>https://sskl660.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 11 May 2026 06:57:10 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>sskl660</managingEditor>
    <item>
      <title>[Java]Set</title>
      <link>https://sskl660.tistory.com/94</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Set&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Set은 내부 데이터를 &lt;b&gt;중복해서 저장할 수 없고, 저장된 객체에 순서가 없다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;따라서 Set은 List와 같이 인덱스를 사용하여 원소에 바로 접근할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HashSet&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java는 내부적으로 Set 인터페이스를 따로 정의해 두었다. 이곳에 다양한 Set 구현체를 활용하여 코드를 작성할 수 있는데, &lt;b&gt;HashSet은 기본적인 Set의 특성을 그대로 반영한 클래스&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;Set&amp;lt;Integer&amp;gt; set = new HashSet&amp;lt;&amp;gt;();
set.add(5);
set.add(5);
set.add(1);
set.add(1);
set.add(3);

System.out.println(set);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;218&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K7pek/btrwIhwUYxS/FPBQ0JhbGsVIKkaB5Y6zvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K7pek/btrwIhwUYxS/FPBQ0JhbGsVIKkaB5Y6zvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K7pek/btrwIhwUYxS/FPBQ0JhbGsVIKkaB5Y6zvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK7pek%2FbtrwIhwUYxS%2FFPBQ0JhbGsVIKkaB5Y6zvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;218&quot; height=&quot;44&quot; data-origin-width=&quot;218&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음과 같이 중복된 자료를 저장하더라도 중복되지 않게 저장되는 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TreeSet&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Set은 TreeSet을 사용하여 내부적으로 정렬된 상태를 유지하도록 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;TreeSet&amp;lt;Integer&amp;gt; set = new TreeSet&amp;lt;&amp;gt;(new Comparator&amp;lt;Integer&amp;gt;() {
	@Override
	public int compare(Integer o1, Integer o2) {
		// Set을 내림차순으로 정렬하는 기준 설정
		return Integer.compare(o2, o1);
	}
	
});

set.add(5);
set.add(5);
set.add(1);
set.add(1);
set.add(3);

System.out.println(set.pollFirst());
System.out.println(set.pollLast());
System.out.println(set);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;또 코드와 같이 Deque의 특성을 가지고 있어, 앞뒤로 꺼내는 연산이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;393&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sFRK7/btrwGj2R7Ot/5xZkeeCF5PeNGkkQma93M0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sFRK7/btrwGj2R7Ot/5xZkeeCF5PeNGkkQma93M0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sFRK7/btrwGj2R7Ot/5xZkeeCF5PeNGkkQma93M0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsFRK7%2FbtrwGj2R7Ot%2F5xZkeeCF5PeNGkkQma93M0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;393&quot; height=&quot;88&quot; data-origin-width=&quot;393&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LinkedHashSet&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Set은 삽입 순서를 보장하지 않는다. 하지만 LinkedHashSet은 연결리스트 형태로 구현이 되어 있기 때문에 삽입 순서를 보장하는 특징이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;LinkedHashSet&amp;lt;Integer&amp;gt; set = new LinkedHashSet&amp;lt;&amp;gt;();
		
set.add(5);
set.add(5);
set.add(1);
set.add(1);
set.add(3);
set.add(7);
set.add(-1);

System.out.println(set);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;22&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cf6PCR/btrwKFX6ceb/0SeRK8aiOHJy4aogOXR0gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cf6PCR/btrwKFX6ceb/0SeRK8aiOHJy4aogOXR0gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cf6PCR/btrwKFX6ceb/0SeRK8aiOHJy4aogOXR0gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcf6PCR%2FbtrwKFX6ceb%2F0SeRK8aiOHJy4aogOXR0gk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;178&quot; height=&quot;22&quot; data-origin-width=&quot;178&quot; data-origin-height=&quot;22&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/자료구조 for Algorithm</category>
      <category>HashSet</category>
      <category>java</category>
      <category>LinkedHashSet</category>
      <category>set</category>
      <category>TreeSet</category>
      <category>자료구조</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/94</guid>
      <comments>https://sskl660.tistory.com/94#entry94comment</comments>
      <pubDate>Tue, 22 Mar 2022 00:52:20 +0900</pubDate>
    </item>
    <item>
      <title>[Java]우선순위큐(PriorityQueue)</title>
      <link>https://sskl660.tistory.com/93</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;우선순위큐(PriorityQueue)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스택은 후입선출, 큐는 선입선출을 특징을 가졌다. 이와 달리 &lt;b&gt;우선순위큐는 사용자가 지정한 우선순위에 의거하여 원소를 꺼내는 특징&lt;/b&gt;이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본적인 사용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java에서는 PrioryQueue 클래스를 이미 내부적으로 포함하고 있다. 이는 기본적으로 &lt;b&gt;오름차순으로 수를 꺼낼 수 있도록 구현&lt;/b&gt;되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1647876283674&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();
pq.offer(5);
pq.offer(3);
pq.offer(9);
pq.offer(1);

while(!pq.isEmpty()) {
	System.out.println(pq.poll());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;77&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pAk62/btrwJV7RxFB/Winvw0MjnYaLvUCXKvVhk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pAk62/btrwJV7RxFB/Winvw0MjnYaLvUCXKvVhk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pAk62/btrwJV7RxFB/Winvw0MjnYaLvUCXKvVhk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpAk62%2FbtrwJV7RxFB%2FWinvw0MjnYaLvUCXKvVhk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;269&quot; height=&quot;77&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;77&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정렬기준 정하기(사용자 정의)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PriorityQueue의 생성하는 단계에서 &lt;b&gt;Comparator 인터페이스를 재정의&lt;/b&gt;한다면 원소가 뽑히는 순서(정렬 기준)를 사용자가 원하는대로 재정의할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1647876386826&quot; class=&quot;pgsql&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(new Comparator&amp;lt;Integer&amp;gt;() {
	@Override
	public int compare(Integer o1, Integer o2) {
		return Integer.compare(o2, o1); // 내림차순 정렬
	}
});
pq.offer(5);
pq.offer(3);
pq.offer(9);
pq.offer(1);

while(!pq.isEmpty()) {
	System.out.println(pq.poll());
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음과 같이 Comparator 인터페이스를 생성하면 compare 함수를 재정의하여 원하는 비교 기준을 설정해주어야 한다. 위의 예시에서는 내림차순으로 정렬할 수 있도록 설정하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djeIGv/btrwA0aHRx1/z6M0mEAjEaKghJzX689pLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djeIGv/btrwA0aHRx1/z6M0mEAjEaKghJzX689pLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djeIGv/btrwA0aHRx1/z6M0mEAjEaKghJzX689pLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjeIGv%2FbtrwA0aHRx1%2Fz6M0mEAjEaKghJzX689pLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;294&quot; height=&quot;133&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체 정렬&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위와 같이 내부적으로 정렬 기준을 정하는 것은 다른 객체를 정렬하는 기준을 만들어줄수도 있다. 때문에 2차원 배열과 같은 내용도 정렬이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1647876480914&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PriorityQueue&amp;lt;int[]&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(new Comparator&amp;lt;int[]&amp;gt;() {
	@Override
	public int compare(int[] o1, int[] o2) {
		// 만일 2차원 배열의 첫 번째 원소가 같다면, 2번째 원소를 기준으로 내림차순 정렬한다.
		if(o1[0] == o2[0]) {
			return Integer.compare(o2[1], o1[1]);
		}
		// 2차원 배열의 첫 번째 원소를 기준으로 오름차순 정렬한다.
		return Integer.compare(o1[0], o2[0]);
	}
});
pq.offer(new int[] {5, 2});
pq.offer(new int[] {3, 3});
pq.offer(new int[] {1, 4});
pq.offer(new int[] {1, 5});
pq.offer(new int[] {7, 5});

while(!pq.isEmpty()) {
	System.out.println(Arrays.toString(pq.poll()));
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;당연히 객체를 만들고, 객체의 원소를 비교 대상으로 두어 객체의 정렬 기준을 정해주는 것도 가능&lt;/b&gt;하다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 자체의 정렬 기준을 만들고 싶은 경우에는 &lt;b&gt;정의한 객체에 Comparable 인터페이스를 포함시켜 객체 자체의 정렬 기준을 미리 정해주는 방법도 존재&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Algorithm/자료구조 for Algorithm</category>
      <category>java</category>
      <category>PriorityQueue</category>
      <category>우선순위큐</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/93</guid>
      <comments>https://sskl660.tistory.com/93#entry93comment</comments>
      <pubDate>Tue, 22 Mar 2022 00:16:56 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 문자열 문제풀이시 자주 사용되는 내용들</title>
      <link>https://sskl660.tistory.com/92</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;String &amp;harr; Integer&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// String -&amp;gt; Integer
int num = Integer.parseInt(string);

// Integer -&amp;gt; String
String string = Integer.toString(num);

// Byte, Long, Float, Double 모두 동일한 함수를 가지고 있다.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;String &amp;harr; Character&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;/***
 * String -&amp;gt; Character
 */
String sentence = &quot;15151515&quot;;
// 한 글자 변환
char c = sentence.charAt(0);

// 전체 글자 변환
char[] c_arr = sentence.toCharArray();

/***
 * Character -&amp;gt; String
 */
// 한 글자 변환
String string = String.valueOf(c);

// 전체 글자 변환
String string = String.valueOf(c_arr);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Integer &amp;harr; Character&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;// Integer -&amp;gt; Character
char c =  6 + '0';

// Character -&amp;gt; Integer
int num = c - '0';
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;부분 문자열 구하기&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;String string = &quot;Hello World!&quot;;
System.out.println(string.substring(0, 5)); // start_idx, end_idx + 1
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/문자열</category>
      <category>java</category>
      <category>문자열</category>
      <category>스킬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/92</guid>
      <comments>https://sskl660.tistory.com/92#entry92comment</comments>
      <pubDate>Mon, 21 Mar 2022 22:23:34 +0900</pubDate>
    </item>
    <item>
      <title>[Java]최장 공통 부분 수열(LCS, Longest Common Subsequence)</title>
      <link>https://sskl660.tistory.com/90</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*최장 공통 부분 수열(LCS, Longest Common Subsequence)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;최장 공통 부분 수열이란, 주어진 &lt;b&gt;두 수열이 주어졌을 때 두 수열 모두의 부분 수열이 되는 수열 중 가장 긴 것&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;LCS를 구하는 문제는 역시&amp;nbsp;&lt;b&gt;백준 Gold5 9251 LCS&amp;nbsp;&lt;/b&gt;문제를 기반으로 알고리즘을 설명하도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 문제 주소 : &lt;a href=&quot;https://www.acmicpc.net/problem/9251&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/9251&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625992597175&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;9251번: LCS&quot; data-og-description=&quot;LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/9251&quot; data-og-url=&quot;https://www.acmicpc.net/problem/9251&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/LPPBi/hyKRKpCNku/JUK1j9KHBVisrXDnOBNby1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/9251&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/9251&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/LPPBi/hyKRKpCNku/JUK1j9KHBVisrXDnOBNby1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;9251번: LCS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;해당 테스트 케이스를 바탕으로 LCS를 이해하면 다음과 같다. 아래 그림을 참고하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;423&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ypiqh/btq9jHrhgR1/Ejk474wDUATI6uE9o3FIQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ypiqh/btq9jHrhgR1/Ejk474wDUATI6uE9o3FIQ0/img.png&quot; data-alt=&quot;두 수열의 부분 수열 중 공통 되는 부분 수열의 길이가 가장 긴 것.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ypiqh/btq9jHrhgR1/Ejk474wDUATI6uE9o3FIQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fypiqh%2Fbtq9jHrhgR1%2FEjk474wDUATI6uE9o3FIQ0%2Fimg.png&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;423&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;두 수열의 부분 수열 중 공통 되는 부분 수열의 길이가 가장 긴 것.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*동적 계획법을 활용한 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;Knapsack Problem, LIS와 마찬가지로 해당 블로그에 포스팅한&amp;nbsp;&lt;b&gt;'동적 계획법 접근 방식'&lt;/b&gt;을 바탕으로 문제를 해결하겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;※ 참고 : &lt;a href=&quot;https://sskl660.tistory.com/87&quot;&gt;https://sskl660.tistory.com/87&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625992814355&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java]동적 계획법(Dynamic Programming)&quot; data-og-description=&quot;*동적 계획법(Dynamic Programming) -&amp;gt;동적 계획법이란&amp;nbsp;특정 범위까지의 최적해(상위 문제)를 구하기 위하여&amp;nbsp;다른 범위까지의 최적해(하위 문제)를 이용하여 효율적으로 해를&amp;nbsp;구하는&amp;nbsp;알고리즘 설계 &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/87&quot; data-og-url=&quot;https://sskl660.tistory.com/87&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/y8dC5/hyKRQXA51f/haH7eDm4CCBbBVf234FJb1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/btDNAA/hyKRFuZBfU/b6zzjwOxJmA84GNitmD1K1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/keD0A/hyKREQohH8/hV4W3NCEkUkCTdaDBH9lnk/img.png?width=952&amp;amp;height=627&amp;amp;face=0_0_952_627&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/87&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/87&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/y8dC5/hyKRQXA51f/haH7eDm4CCBbBVf234FJb1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/btDNAA/hyKRFuZBfU/b6zzjwOxJmA84GNitmD1K1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/keD0A/hyKREQohH8/hV4W3NCEkUkCTdaDBH9lnk/img.png?width=952&amp;amp;height=627&amp;amp;face=0_0_952_627');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java]동적 계획법(Dynamic Programming)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*동적 계획법(Dynamic Programming) -&amp;gt;동적 계획법이란&amp;nbsp;특정 범위까지의 최적해(상위 문제)를 구하기 위하여&amp;nbsp;다른 범위까지의 최적해(하위 문제)를 이용하여 효율적으로 해를&amp;nbsp;구하는&amp;nbsp;알고리즘 설계&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문제를 특정한 부분 문제로 생각해보고, 해당 문제를 저장할 dp 테이블을 정의해본다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 각 문자열이 비교되는 위치에서 가질 수 있는 LCS의 최대 값은 무엇일까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;LCS 문제 풀이의 기본적인 접근은 위 질문으로부터 시작된다. 주어진 테스트 케이스를 예로 들면, 다음과 같은 느낌을 갖는 다는 것을 이해해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;437&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuwBk4/btq9gSGmIdw/QXfYKKh5KpVt6wJKrMmEaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuwBk4/btq9gSGmIdw/QXfYKKh5KpVt6wJKrMmEaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuwBk4/btq9gSGmIdw/QXfYKKh5KpVt6wJKrMmEaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuwBk4%2Fbtq9gSGmIdw%2FQXfYKKh5KpVt6wJKrMmEaK%2Fimg.png&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;437&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 해당 위치에서 가질 수 있는 LCS의 최대 값을 효과적으로 저장하기 위해, 2차원 배열을 활용하여 값을 저장한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;각 문자열이 비교되는 위치에서 가질 수 있는 LCS의 최대 값을 저장한다는 말이 잘 이해되지 않을 것이다. 우선 결론적으로 &lt;b&gt;LCS 문제 해결은 아래 2차원 배열 형태의 dp 테이블을 활용&lt;/b&gt;하게 될 것이다. 아래 그림을 참고한다면 조금 더 이해하기 좋을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;624&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUzcMt/btq9jGFVpxg/q7JZ64mzp13kOJErIWCfl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUzcMt/btq9jGFVpxg/q7JZ64mzp13kOJErIWCfl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUzcMt/btq9jGFVpxg/q7JZ64mzp13kOJErIWCfl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUzcMt%2Fbtq9jGFVpxg%2Fq7JZ64mzp13kOJErIWCfl1%2Fimg.png&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;624&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 우선 값을 채워보자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선, 첫 번째 문자열에 대하여 두 번째 문자열의 문자를 하나씩 비교하며 테이블을 갱신해보자. 그렇다면 두 번째 문자열의 첫 번째 문자인 'C'와 첫 번째 문자열을 비교하게 될 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;626&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rxoN3/btq9f6FO6yj/y0oEwgV3Yu1ITUQkzv8oi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rxoN3/btq9f6FO6yj/y0oEwgV3Yu1ITUQkzv8oi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rxoN3/btq9f6FO6yj/y0oEwgV3Yu1ITUQkzv8oi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrxoN3%2Fbtq9f6FO6yj%2Fy0oEwgV3Yu1ITUQkzv8oi1%2Fimg.png&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;626&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 C를 A와 비교한다면 두 문자가 일치하지 않기 때문에, LCS의 값은 1이 된다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;632&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXPvzg/btq9gXIpLF2/9ubQOmj55TetW8dTdfAhJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXPvzg/btq9gXIpLF2/9ubQOmj55TetW8dTdfAhJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXPvzg/btq9gXIpLF2/9ubQOmj55TetW8dTdfAhJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXPvzg%2Fbtq9gXIpLF2%2F9ubQOmj55TetW8dTdfAhJk%2Fimg.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;632&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;두 번째로 C를 C와 비교한다면 두 문자는 일치하므로, 해당 위치에서 가질 수 있는 LCS의 값은 1이 된다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;423&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tMEX1/btq9iBEQEx7/YZxmKK7yHAJHfpCMJMo1pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tMEX1/btq9iBEQEx7/YZxmKK7yHAJHfpCMJMo1pK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tMEX1/btq9iBEQEx7/YZxmKK7yHAJHfpCMJMo1pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtMEX1%2Fbtq9iBEQEx7%2FYZxmKK7yHAJHfpCMJMo1pK%2Fimg.png&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;423&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;세 번째로 C와 A를 비교하면 두 문자는 일치하지 않는다. 그렇다면 해당 위치에 0을 채워야 할까? dp 테이블의 정의를 다시 살펴보자. &lt;b&gt;해당 위치의 의미는 두번째 문자열의 첫 문자인 'C'가 첫 번째 문자열의 첫 번째 문자와 두 번째 문자의 비교를 끝내고 세 번째 문자인 'A'와 비교하는 위치&lt;/b&gt;이다. 또한, &lt;b&gt;그 위치에 지금까지 C가 해당 위치에서 가질 수 있는 최대 LCS의 값을 저장&lt;/b&gt;해야 한다고 하였다. 따라서, &lt;b&gt;이전 문자에서 비교했던 최대 값인 1을 그대로 해당 위치에 가져와야함&lt;/b&gt;을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;645&quot; data-origin-height=&quot;409&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJnDKX/btq9lTxZ5Ur/NOQmg8WzJRABoeoKbfKNc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJnDKX/btq9lTxZ5Ur/NOQmg8WzJRABoeoKbfKNc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJnDKX/btq9lTxZ5Ur/NOQmg8WzJRABoeoKbfKNc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJnDKX%2Fbtq9lTxZ5Ur%2FNOQmg8WzJRABoeoKbfKNc0%2Fimg.png&quot; data-origin-width=&quot;645&quot; data-origin-height=&quot;409&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지 방식으로 나머지 테이블도 채울 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;417&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0KW5P/btq9gA7OGV8/kbKgFNewBKBVJEBsy2hM1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0KW5P/btq9gA7OGV8/kbKgFNewBKBVJEBsy2hM1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0KW5P/btq9gA7OGV8/kbKgFNewBKBVJEBsy2hM1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0KW5P%2Fbtq9gA7OGV8%2FkbKgFNewBKBVJEBsy2hM1K%2Fimg.png&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;417&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;여기서 주의해야 할 점은&amp;nbsp;&lt;b&gt;첫 번째 문자열과 두 번째 문자열 모두 상호적으로 해당 위치의 의미는 각 문자열이 비교되는 위치에서 가질 수 있는 LCS의 최대 값을 의미&lt;/b&gt;한다는 것이다. 우선 나머지 테이블도 채워보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;자, 그럼 이번에는 두 번째 문자열의 두 번째 문자열인 'A'에 대하여 첫 번째 문자열의 모든 문자열을 비교해보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;418&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beWGKq/btq9juSyhFM/Lx1lxK52oaDvpfbQQfpJKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beWGKq/btq9juSyhFM/Lx1lxK52oaDvpfbQQfpJKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beWGKq/btq9juSyhFM/Lx1lxK52oaDvpfbQQfpJKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeWGKq%2Fbtq9juSyhFM%2FLx1lxK52oaDvpfbQQfpJKK%2Fimg.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;418&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 처음부터 A와 A를 비교하므로 문자가 일치한다. 그렇다면 &lt;b&gt;당연히 해당 위치에 적어도 1이라는 값을 가지게 될 것&lt;/b&gt;임을 알 수 있다. 그렇다고 &lt;b&gt;무작정 규칙을 생각하지 않으면서 그 값을 넣으면 안된다는 것을 지금까지 여러 다이나믹 프로그래밍 문제를 풀면서 경험적으로 알게 되었다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;416&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1Tapl/btq9lmUfnWP/JICFA1ttHXWeDA6lKqsh3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1Tapl/btq9lmUfnWP/JICFA1ttHXWeDA6lKqsh3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1Tapl/btq9lmUfnWP/JICFA1ttHXWeDA6lKqsh3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1Tapl%2Fbtq9lmUfnWP%2FJICFA1ttHXWeDA6lKqsh3k%2Fimg.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;416&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그렇다면 이전 문자열의 비교에서 사용된 것 처럼, &lt;b&gt;이전에 구했던 최대 값을 전이 시키면 되지 않을까?&lt;/b&gt; 하지만 0이라는 값을 전이 시키면 해당 위치에는 0이라는 값이 들어갈 것이다. &lt;b&gt;아직은 정보가 부족&lt;/b&gt;하다. &lt;b&gt;우선 테이블을 채우는 과정을 계속 진행&lt;/b&gt;해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBmIeB/btq9kQ2BBBn/Z8XZPPhJJ3hjxBqmwcRS6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBmIeB/btq9kQ2BBBn/Z8XZPPhJJ3hjxBqmwcRS6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBmIeB/btq9kQ2BBBn/Z8XZPPhJJ3hjxBqmwcRS6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBmIeB%2Fbtq9kQ2BBBn%2FZ8XZPPhJJ3hjxBqmwcRS6k%2Fimg.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 두 번째 문자열의 첫 번째 문자인 'C'를 첫 번째 문자열과 비교하며 채워나갔던 것처럼, A와 C는 문자가 서로 일치하지 않으므로 그 값을 전이시켜 두 번째 열을 채웠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxcyOZ/btq9f5toLGj/bHDqfKhWknfrTxLDFAYJt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxcyOZ/btq9f5toLGj/bHDqfKhWknfrTxLDFAYJt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxcyOZ/btq9f5toLGj/bHDqfKhWknfrTxLDFAYJt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxcyOZ%2Fbtq9f5toLGj%2FbHDqfKhWknfrTxLDFAYJt0%2Fimg.png&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그렇다면 세번째 열에서도 1을 채워야 하는가? 일단 첫 번째 경우와 다른점은&amp;nbsp;&lt;b&gt;세 번째 위치에서 A와 A로 문자열이 서로 일치한다는 것이다. &lt;u&gt;그렇지만, 두 번째 문자열에 현재 위치까지 보유한 A라는 문자는 단 하나 뿐이고, 무턱대고 해당 위치를 + 1해버린다면 두 번째 문자열의 2번째 위치까지 A라는 문자가 두 개라는 것을 의미&lt;/u&gt;&lt;/b&gt;하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;또 다른 정보는, 우선 &lt;b&gt;직관적으로 해당 위치에서 각 문자열의 &quot;CA&quot;라는 부분이 공통적을 도출된다는 것을 알 수 있다. 따라서 해당 위치는 최소 2의 값을 가져야 함&lt;/b&gt;도 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mSS5R/btq9lnMoltD/SifkkoYTgmkHUJ4ENaSId1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mSS5R/btq9lnMoltD/SifkkoYTgmkHUJ4ENaSId1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mSS5R/btq9lnMoltD/SifkkoYTgmkHUJ4ENaSId1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmSS5R%2Fbtq9lnMoltD%2FSifkkoYTgmkHUJ4ENaSId1%2Fimg.png&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;자, 여기서 규칙성을 파악해보자. &lt;b&gt;테이블의 행을 i, 열을 j&lt;/b&gt;라고 한다면 &lt;b&gt;해당 위치의 위(i - 1), 왼쪽(j - 1), 왼쪽 위 대각선 (i - 1, j - 1)방향의 정보를 참고할 수 있고 결론적으로 해당 정보들을 바탕으로 현재 위치의 값들을 갱신&lt;/b&gt;하게 된다. 그렇다면&amp;nbsp;&lt;u&gt;&lt;b&gt;각 위치의 정보가 의미하는 바를 분석&lt;/b&gt;&lt;/u&gt;해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN8QeK/btq9fxCXBJS/rmZu6leM0EoCUpBFavcljk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN8QeK/btq9fxCXBJS/rmZu6leM0EoCUpBFavcljk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN8QeK/btq9fxCXBJS/rmZu6leM0EoCUpBFavcljk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN8QeK%2Fbtq9fxCXBJS%2FrmZu6leM0EoCUpBFavcljk%2Fimg.png&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(4) 윗 행(i - 1)의 값이 의미하는 정보&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;해당 위치의 바로 윗 행이 의미하는 정보는 두 번째 문자열의 'C'가 해당 위치에서 첫 번째 문자열의 'A'까지 비교하면서 얻은 최대 LCS의 값을 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/phzRe/btq9kQuMhQu/JDvsMImCA9WhbySlE7jjCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/phzRe/btq9kQuMhQu/JDvsMImCA9WhbySlE7jjCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/phzRe/btq9kQuMhQu/JDvsMImCA9WhbySlE7jjCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FphzRe%2Fbtq9kQuMhQu%2FJDvsMImCA9WhbySlE7jjCk%2Fimg.png&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(5) 왼쪽 열(j - 1)의 값이 의미하는 정보&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;해당 위치의 바로 왼쪽 열이 의미하는 정보는 첫 번째 문자열의 두 번째 문자인 'C'가 해당 위치에서 두 번째 문자열의 'A'까지 비교하면서 얻은 최대 LCS의 값을 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBhZCk/btq9gAzWp1D/PTPkMHpkmntqvXa4xttku0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBhZCk/btq9gAzWp1D/PTPkMHpkmntqvXa4xttku0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBhZCk/btq9gAzWp1D/PTPkMHpkmntqvXa4xttku0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBhZCk%2Fbtq9gAzWp1D%2FPTPkMHpkmntqvXa4xttku0%2Fimg.png&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(6) 윗 행(i - 1), 왼쪽 열(j - 1)의 값이 의미하는 정보&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;해당 위치의 윗 행, 왼쪽 열이 의미하는 정보는 현재 문자에 대하여 &lt;b&gt;각 이전 문자열의 이전 문자가 해당 위치에서 가질 수 있는 최대 LCS의 값&lt;/b&gt;을 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;422&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0baMP/btq9jGsoNWb/zoGV0eB5T3b8Jm0HHnFmk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0baMP/btq9jGsoNWb/zoGV0eB5T3b8Jm0HHnFmk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0baMP/btq9jGsoNWb/zoGV0eB5T3b8Jm0HHnFmk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0baMP%2Fbtq9jGsoNWb%2FzoGV0eB5T3b8Jm0HHnFmk0%2Fimg.png&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;422&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(7) 4, 5, 6에서 얻은 정보를 종합해보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 우리는 앞서 테이블을 채우는 과정에서&amp;nbsp;&lt;b&gt;경험적으로 해당 위치의 문자가 같거나, 다르다면 처리를 다르게 해주어야 될 것 같다&lt;/b&gt;는 사실을 유추해볼 수 있었다. 이제 그 정보와 앞서 얻은 정보를 결합해 볼 차례이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 해당 위치의 문자가 일치하는 경우.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;475&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5Ka2w/btq9iAeTOvS/x9jM4c8jkjWGIx1FE9YZY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5Ka2w/btq9iAeTOvS/x9jM4c8jkjWGIx1FE9YZY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5Ka2w/btq9iAeTOvS/x9jM4c8jkjWGIx1FE9YZY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5Ka2w%2Fbtq9iAeTOvS%2Fx9jM4c8jkjWGIx1FE9YZY1%2Fimg.png&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;475&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;앞서 언급한 바와 같이, 해당 문자의 대각선에 위치한 값의 의미는 &lt;b&gt;각 이전 문자열의 이전 문자가 해당 위치에서 가질 수 있는 최대 LCS의 값&lt;/b&gt;이라고 하였다. 즉,&amp;nbsp;&lt;b&gt;현재 문자가 일치한다면 각 문자가 추가되는 위치에서 LCS의 값을 증가시킬 가능성이 존재&lt;/b&gt;한다는 것을 의미한다. 따라서 &lt;b&gt;해당 값에 + 1을 하여 해당 테이블을 갱신&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 해당 위치의 문자가 일치하지 않는 경우.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음 테이블을 채워보자. 이번에는 A와 Y라는 문자가 일치하지 않기 때문에, 대각선 정보는 활용할 수 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;429&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OPVus/btq9fcTnO2w/kIfcNvcmoYDrCgbzrMuDP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OPVus/btq9fcTnO2w/kIfcNvcmoYDrCgbzrMuDP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OPVus/btq9fcTnO2w/kIfcNvcmoYDrCgbzrMuDP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOPVus%2Fbtq9fcTnO2w%2FkIfcNvcmoYDrCgbzrMuDP1%2Fimg.png&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;429&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;일치하지 않기 때문에, 이제 남은 윗 행 정보와 왼쪽 열의 정보를 활용해야 한다는 사실을 알 수 있다. 그리고 그 정의 그대로, 각 &lt;b&gt;첫 번째 문자열과 두 번째 문자열이 지금까지 조사한 최대 LIS의 값 중 더 큰 값을 갖는 것을 선택&lt;/b&gt;해야 한다는 것을 유추해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;429&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pTL7Z/btq9kQBwlAX/k43KNgmO74b62CQD4Qdng1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pTL7Z/btq9kQBwlAX/k43KNgmO74b62CQD4Qdng1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pTL7Z/btq9kQBwlAX/k43KNgmO74b62CQD4Qdng1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpTL7Z%2Fbtq9kQBwlAX%2Fk43KNgmO74b62CQD4Qdng1%2Fimg.png&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;429&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;따라서 이때는 좌측의 값이 더 크기 때문에, 좌측의 값을 해당 테이블에 갱신해주는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;413&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZttCX/btq9iA0hW8V/FGkEGwhJVmVT1PVF74uBpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZttCX/btq9iA0hW8V/FGkEGwhJVmVT1PVF74uBpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZttCX/btq9iA0hW8V/FGkEGwhJVmVT1PVF74uBpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZttCX%2Fbtq9iA0hW8V%2FFGkEGwhJVmVT1PVF74uBpk%2Fimg.png&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;413&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 부분 문제의 관계를 생각하며 점화식을 도출한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;즉, 해당 위치의 &lt;b&gt;문자가 일치하느냐의 여부&lt;/b&gt;에 따라서&amp;nbsp;&lt;b&gt;다른 점화식을 적용하여 해당 위치의 값을 갱신&lt;/b&gt;해야 된다는 것을 이해할 수 있다. 따라서 다음과 같은 점화식을 도출할 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;120&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cninq3/btq9hPo6G4Z/EBQynMRY2sQYzIOapIxFe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cninq3/btq9hPo6G4Z/EBQynMRY2sQYzIOapIxFe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cninq3/btq9hPo6G4Z/EBQynMRY2sQYzIOapIxFe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcninq3%2Fbtq9hPo6G4Z%2FEBQynMRY2sQYzIOapIxFe1%2Fimg.png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;120&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 점화식을 바탕으로 dp 테이블을 갱신하면서 최종적으로 전체 문제를 해결한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 해당 점화식을 진행하기 위해서는&amp;nbsp;&lt;b&gt;서로 문자가 없는 상태에서 시작하는 경우도 고려(기저 조건)&lt;/b&gt;해야 하기 때문에 기존 배열에 패딩을 추가하여 0으로 초기화 해줘야 한다는 사실을 알 수 있다(문자가 없는 경우 비교를 수행해도 일치하는 문자는 없기 때문에 0).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;686&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DGaCE/btq9hzUOCst/ckSzjhFXlXHUcgygznCsA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DGaCE/btq9hzUOCst/ckSzjhFXlXHUcgygznCsA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DGaCE/btq9hzUOCst/ckSzjhFXlXHUcgygznCsA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDGaCE%2Fbtq9hzUOCst%2FckSzjhFXlXHUcgygznCsA1%2Fimg.png&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;686&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이렇게 각 테이블을 채우고 &lt;b&gt;dp[B문자열의길이][A문자열의길이]가 의미하는 것은 B문자열의 K라는 문자가 A문자열의 P라는 문자까지 비교하며 얻은 최대 LCS의 값&lt;/b&gt;을 의미하게 된다. 따라서 해당 값을 출력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;위의 규칙을 그대로 코드로 옮기면 된다. 아래 코드를 참고하자.&lt;/p&gt;
&lt;pre id=&quot;code_1625996571993&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class LCS {
	static char[] A, B;
	static int[][] dp;
	static int max = 0;
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		// 각 문자열을 입력 받는다.
		String a = br.readLine();
		String b = br.readLine();
		// 각 문자열의 길이가 다르므로 따로 저장해둔다.
		int alength = a.length();
		int blength = b.length();
		// 각 문자열을 나눠서 저장할 char 배열.
		A = new char[alength + 1];
		B = new char[blength + 1];
		// 각 문자열을 char 배열에 문자 하나씩 옮겨 담는다.
		for(int i = 1; i &amp;lt;= alength; i++) {
			A[i] = a.charAt(i - 1);
		}
		for(int i = 1; i &amp;lt;= blength; i++) {
			B[i] = b.charAt(i - 1);
		}
		
		// 각 문자의 비교가 끝났을 때, 해당 위치에서 가질 수 있는 LCS의 값을 저장할 2차원 dp테이블을 정의한다.
		// 첫 행에서도 이전 문자를 참고할 수 있도록 패딩을 준다.
		dp = new int[blength + 1][alength + 1];
		
		// B의 모든 문자열을 A문자열과 비교
		for(int i = 1; i &amp;lt;= blength; i++) {
			for(int j = 1; j &amp;lt;= alength; j++) {
				// 만일 두 문자가 같은 경우
				if(B[i] == A[j]) {
					// 대각선의 값을 참고하여 LCS의 값을 + 1한다.
					dp[i][j] = dp[i - 1][j - 1] + 1;
				}
				// 두 문자가 다른 경우
				else {
					// 각 문자열의 이전 문자 중 최대 LCS값을 선택.
					dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
				}
			}
		}
		
		// 최종으로 탐색한 위치에 LCS의 최대 값이 저장되어 있을 것이다.
		System.out.println(dp[blength][alength]);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;두 문자열의 각 문자를 비교하는 과정을 수반하기 때문에,&amp;nbsp;&lt;b&gt;O(N^2)의 시간복잡도&lt;/b&gt;를 갖게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 여기까지가 &lt;b&gt;다이나믹 프로그래밍에서 가장 유명한 3가지 예제 였다(Knapsack, LIS, LCS).&lt;/b&gt; 이는&lt;b&gt; 다이나믹 프로그래밍이 무엇인지 감을 잡기 좋은 예제&lt;/b&gt;들이고, &lt;b&gt;몇몇 문제에서는 이곳에서 배운 논리를 기반으로 문제를 출제&lt;/b&gt;하기도 하므로 기본적인 예제에 대한 이해는 반드시 해두도록 하자.&lt;/p&gt;</description>
      <category>Algorithm/동적 계획법</category>
      <category>BOJ 9251</category>
      <category>lcs</category>
      <category>longest common subsequence</category>
      <category>다이나믹 프로그래밍</category>
      <category>동적 계획법</category>
      <category>백준 9251</category>
      <category>최장 공통 부분 수열</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/90</guid>
      <comments>https://sskl660.tistory.com/90#entry90comment</comments>
      <pubDate>Sun, 11 Jul 2021 18:49:32 +0900</pubDate>
    </item>
    <item>
      <title>[Java]최장 증가 부분 수열(LIS, Longest Increasing Subsequence)</title>
      <link>https://sskl660.tistory.com/89</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*최장 증가 부분 수열(LIS, Longest Increasing Subsequence)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;최장 증가 부분 수열이란, 주어진 수열에서&amp;nbsp;&lt;b&gt;오름차순으로 정렬된 가장 긴 부분 수열&lt;/b&gt;을&amp;nbsp;&lt;b&gt;찾는 문제&lt;/b&gt;이다. 여기서&amp;nbsp;&lt;b&gt;부분 수열은 연속적이거나, 유일할 필요는 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;아래 그림을 참고하여 이해하도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;115&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MXhKq/btq9fWPVSNo/kqSKaPo3eIIjBRykek9Rl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MXhKq/btq9fWPVSNo/kqSKaPo3eIIjBRykek9Rl0/img.png&quot; data-alt=&quot;증가하는 부분 수열. 수열이 연속적일 필요는 없다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MXhKq/btq9fWPVSNo/kqSKaPo3eIIjBRykek9Rl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMXhKq%2Fbtq9fWPVSNo%2FkqSKaPo3eIIjBRykek9Rl0%2Fimg.png&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;115&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;증가하는 부분 수열. 수열이 연속적일 필요는 없다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;151&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/48R5s/btq9fwDYaMa/TpniOLD4VdkjqSCXXh0Oh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/48R5s/btq9fwDYaMa/TpniOLD4VdkjqSCXXh0Oh0/img.png&quot; data-alt=&quot;최장 증가 부분 수열. 해당 수열에서 찾을 수 있는 가장 긴 부분 수열이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/48R5s/btq9fwDYaMa/TpniOLD4VdkjqSCXXh0Oh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F48R5s%2Fbtq9fwDYaMa%2FTpniOLD4VdkjqSCXXh0Oh0%2Fimg.png&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;151&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최장 증가 부분 수열. 해당 수열에서 찾을 수 있는 가장 긴 부분 수열이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;해당 예시로 주어진 배열에서는 가장 긴 증가하는 부분 수열(이하 LIS)은 1, 2, 3, 7임을 직관적으로 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;LIS를 구하는 문제는 Knapsack, LCS와 더불어 다이나믹 프로그래밍의 기초를 다지는데 자주 사용되는 예제 중 하나이다. 이 문제 역시&amp;nbsp;&lt;b&gt;백준 Silver2 11053 가장 긴 증가하는 부분 수열&lt;/b&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;문제를 기반으로 알고리즘을 설명하도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 문제 주소 : &lt;a href=&quot;https://www.acmicpc.net/problem/11053&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/11053&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625980643994&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;11053번: 가장 긴 증가하는 부분 수열&quot; data-og-description=&quot;수열 A가 주어졌을 때, 가장 긴 증가하는&amp;nbsp;부분&amp;nbsp;수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분&amp;nbsp;수열은&amp;nbsp;A = {10, 20, 10, 30, 20, 50} 이&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/11053&quot; data-og-url=&quot;https://www.acmicpc.net/problem/11053&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cilpoc/hyKQvnenuI/VWh9snz7z4tYkKaRaWBMo1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/11053&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/11053&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cilpoc/hyKQvnenuI/VWh9snz7z4tYkKaRaWBMo1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;11053번: 가장 긴 증가하는 부분 수열&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;수열 A가 주어졌을 때, 가장 긴 증가하는&amp;nbsp;부분&amp;nbsp;수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분&amp;nbsp;수열은&amp;nbsp;A = {10, 20, 10, 30, 20, 50} 이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 이 문제 역시 백 트래킹을 활용하여 문제를 해결할 수 있지만, 해당 풀이는&amp;nbsp;&lt;b&gt;O(2^N)의 시간 복잡도&lt;/b&gt;를 갖기도 하고 Knapsack Problem과 유사한 논리를 바탕으로 풀이할 수 있기 때문에 생략하도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*동적 계획법을 활용한 풀이 : O(N^2)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;먼저, 비교적 이해하기 쉬운 동적 계획법을 활용한 풀이를 바탕으로 문제를 해결해보자.&amp;nbsp;&lt;b&gt;해당 풀이는 O(N^2)의 시간 복잡도&lt;/b&gt;를 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;Knapsack Problem과 마찬가지로 해당 블로그에 포스팅한 &lt;b&gt;'동적 계획법 접근 방식'&lt;/b&gt;을 바탕으로 문제에 접근해보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;※ 참고 : &lt;a href=&quot;https://sskl660.tistory.com/87&quot;&gt;https://sskl660.tistory.com/87&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625981646473&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java]동적 계획법(Dynamic Programming)&quot; data-og-description=&quot;*동적 계획법(Dynamic Programming) -&amp;gt;동적 계획법이란&amp;nbsp;특정 범위까지의 최적해(상위 문제)를 구하기 위하여&amp;nbsp;다른 범위까지의 최적해(하위 문제)를 이용하여 효율적으로 해를&amp;nbsp;구하는&amp;nbsp;알고리즘 설계 &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/87&quot; data-og-url=&quot;https://sskl660.tistory.com/87&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/y8dC5/hyKRQXA51f/haH7eDm4CCBbBVf234FJb1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/btDNAA/hyKRFuZBfU/b6zzjwOxJmA84GNitmD1K1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/keD0A/hyKREQohH8/hV4W3NCEkUkCTdaDBH9lnk/img.png?width=952&amp;amp;height=627&amp;amp;face=0_0_952_627&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/87&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/87&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/y8dC5/hyKRQXA51f/haH7eDm4CCBbBVf234FJb1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/btDNAA/hyKRFuZBfU/b6zzjwOxJmA84GNitmD1K1/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/keD0A/hyKREQohH8/hV4W3NCEkUkCTdaDBH9lnk/img.png?width=952&amp;amp;height=627&amp;amp;face=0_0_952_627');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java]동적 계획법(Dynamic Programming)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*동적 계획법(Dynamic Programming) -&amp;gt;동적 계획법이란&amp;nbsp;특정 범위까지의 최적해(상위 문제)를 구하기 위하여&amp;nbsp;다른 범위까지의 최적해(하위 문제)를 이용하여 효율적으로 해를&amp;nbsp;구하는&amp;nbsp;알고리즘 설계&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문제를 특정한 부분 문제로 생각해보고, 해당 문제를 저장할 dp 테이블을 정의해본다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 해당 수열의 i번째 원소의 위치에서 가질 수 있는 LIS의 값은 무엇일까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;문제에 따르면 수열의 크기가 N인 배열이 입력으로 주어질 것이고, 우리는 우선 간단하게 &lt;b&gt;N개의 원소 중 1번째, 2번째, 3번째... N번째 위치 해당 원소가 가질 수 있는 LIS의 값&lt;/b&gt;을 &lt;b&gt;부분 문제&lt;/b&gt;로 생각해볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;따라서, 해당 위치에서 해당 원소가 가질 수 있는 LIS의 값을 &lt;b&gt;저장할 1차원 dp 테이블&lt;/b&gt;을 만들고 문제에 접근해보자. 아래 그림을 참고하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;450&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KfkeG/btq9gXuH148/yVFApYKyCniRYXqh4z7rA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KfkeG/btq9gXuH148/yVFApYKyCniRYXqh4z7rA1/img.png&quot; data-alt=&quot;dp 테이블의 원소의 값은 배열의 해당 위치의 원소에서 가질 수 있는 LIS의 값을 의미한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KfkeG/btq9gXuH148/yVFApYKyCniRYXqh4z7rA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKfkeG%2Fbtq9gXuH148%2FyVFApYKyCniRYXqh4z7rA1%2Fimg.png&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;450&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;dp 테이블의 원소의 값은 배열의 해당 위치의 원소에서 가질 수 있는 LIS의 값을 의미한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선, 첫 번째 원소부터 생각해보자. 10이라는 원소가 가질 수 있는 LIS의 값은&amp;nbsp;&lt;b&gt;우선 본인 그 자체의 길이&lt;/b&gt;를 생각할 수 있다. 따라서 dp[1]의 값은 1로 채울 수 있음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;446&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9OhE7/btq9e0S4E7W/Bu21YNYZsKY1dejQNAwwaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9OhE7/btq9e0S4E7W/Bu21YNYZsKY1dejQNAwwaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9OhE7/btq9e0S4E7W/Bu21YNYZsKY1dejQNAwwaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9OhE7%2Fbtq9e0S4E7W%2FBu21YNYZsKY1dejQNAwwaK%2Fimg.png&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;446&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음으로 두 번째 원소 20을 살펴보자. 우선,&amp;nbsp;&lt;b&gt;첫 번째 원소와 마찬가지로, 20은 본인 그 자체의 길이&lt;/b&gt;를 바탕으로 초기화가 가능하기 때문에 1이라는 값으로&amp;nbsp;&lt;u&gt;&lt;b&gt;초기화&lt;/b&gt;&lt;/u&gt;할 수 있음을 알 수 있다. 이로부터&amp;nbsp;&lt;b&gt;우선 해당 테이블의 원소에 dp 값을 채울 때 원소의 값을 1로 초기화할 수 있음&lt;/b&gt;을 유추해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;434&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xOm5b/btq9kQ9eoPr/NmMB1Bt5lW9RpO3L9iQMd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xOm5b/btq9kQ9eoPr/NmMB1Bt5lW9RpO3L9iQMd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xOm5b/btq9kQ9eoPr/NmMB1Bt5lW9RpO3L9iQMd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxOm5b%2Fbtq9kQ9eoPr%2FNmMB1Bt5lW9RpO3L9iQMd0%2Fimg.png&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;434&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 하지만 &lt;b&gt;우리는 우선 직관적으로 해당 위치에서 LIS의 값이 1로 설정되면 안된다는 것&lt;/b&gt;을 알고있다. &lt;b&gt;이전 원소(10)에 비하여 증가하는 상태&lt;/b&gt;이므로 해당 위치의 값은 2로 설정되어야 한다는 것을 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;442&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zpZsz/btq9kPoXplW/F4HbSjoZblkeFnt9PtRwI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zpZsz/btq9kPoXplW/F4HbSjoZblkeFnt9PtRwI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zpZsz/btq9kPoXplW/F4HbSjoZblkeFnt9PtRwI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzpZsz%2Fbtq9kPoXplW%2FF4HbSjoZblkeFnt9PtRwI0%2Fimg.png&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;442&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 이 단계에서 부터 지금까지 기억해둔 dp 테이블에 저장된 값과 비교하여 규칙성을 찾을 수 있다면 좋겠지만 그 관계를 유추하기 쉽지 않을 것이다. 우선 다른 원소들도 차근차근 채워보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음으로 세 번째 원소인 10을 살펴보자. 마찬가지로 본인의 길이를 바탕으로 해당 위치를 1로 설정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;446&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuo8zA/btq9hyIfkDM/RLJPzyvACzXfzXAa1hmZJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuo8zA/btq9hyIfkDM/RLJPzyvACzXfzXAa1hmZJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuo8zA/btq9hyIfkDM/RLJPzyvACzXfzXAa1hmZJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcuo8zA%2Fbtq9hyIfkDM%2FRLJPzyvACzXfzXAa1hmZJ0%2Fimg.png&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;446&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;두 번째 원소를 채울 때와는 다르게, 해당 위치에서는 직관적으로 보아도 그 값이 갱신될 가능성이 없어보인다. 따라서, 해당 테이블은 1로 채우고 넘어갈 수 있음을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음으로 네 번째 원소인 30을 살펴보자. 마찬가지로 해당 위치는 1로 초기화가 가능할 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;448&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz04zh/btq9izUrPHt/FKVL4IKeASmWPndV8A3Iq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz04zh/btq9izUrPHt/FKVL4IKeASmWPndV8A3Iq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz04zh/btq9izUrPHt/FKVL4IKeASmWPndV8A3Iq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz04zh%2Fbtq9izUrPHt%2FFKVL4IKeASmWPndV8A3Iq1%2Fimg.png&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;448&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;하지만 직관적으로 보았을 때,&amp;nbsp;&lt;b&gt;해당 위치는 10, 20이후 30이라는 증가된 부분 수열을 이룰 수 있는 위치&lt;/b&gt;이기 때문에 해당 위치의 값이 3이 되어야 한다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;436&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fh7RY/btq9gBerjU4/yrDjMYJKkXcgcTtsEKo9jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fh7RY/btq9gBerjU4/yrDjMYJKkXcgcTtsEKo9jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fh7RY/btq9gBerjU4/yrDjMYJKkXcgcTtsEKo9jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFh7RY%2Fbtq9gBerjU4%2FyrDjMYJKkXcgcTtsEKo9jk%2Fimg.png&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;436&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 자, 이제&amp;nbsp;&lt;b&gt;규칙성을 파악&lt;/b&gt;해보자. 우선&amp;nbsp;&lt;b&gt;dp 테이블에 저장되는 값은 해당 원소의 위치에서 가질 수 있는 LIS의 값&lt;/b&gt;이었다는 것을 잊어서는 안된다.&amp;nbsp;&lt;b&gt;그렇다면 그 값 들을 어떻게 활용&lt;/b&gt;할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선&amp;nbsp;&lt;b&gt;30이라는 값은 앞선 원소들(10, 20, 10)에 비하여 큰 값&lt;/b&gt;을 가지고 있음을 알 수 있다.&amp;nbsp;즉,&lt;b&gt; 어떤 원소가 오더라도 해당 원소 뒤에 추가 되면서 최장 증가 부분 수열이 될 수 있음&lt;/b&gt;을 나타낸다고 이해할 수 있다. 근데 우리가 dp 테이블에 저장한 값은 해당 원소의 위치에서 가질 수 있는 LIS의 길이였다. 즉,&amp;nbsp;&lt;b&gt;해당 위치에서 앞 원소들에 비하여 증가할 가능성&lt;/b&gt;&lt;b&gt;이 존재&lt;/b&gt;한다면,&amp;nbsp;&lt;b&gt;해당 위치의 LIS의 값에 자신의 길이를 +1&lt;/b&gt; 해주면 된다는 것을 파악할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, 다시 처음부터 &lt;b&gt;자신의 길이인 1로 채우는 경우(초기화)&lt;/b&gt;부터 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;446&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgV3Ic/btq9e0yQdn0/hvR9Oy0sUFsWigtmAr7zAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgV3Ic/btq9e0yQdn0/hvR9Oy0sUFsWigtmAr7zAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgV3Ic/btq9e0yQdn0/hvR9Oy0sUFsWigtmAr7zAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgV3Ic%2Fbtq9e0yQdn0%2FhvR9Oy0sUFsWigtmAr7zAK%2Fimg.png&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;446&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 1번째 원소(10)에 대하여 30이라는 수는 부분 수열의 길이를 증가시킬 수 있으므로 dp[1] + 1의 값을 dp[4]의 값 후보에 올릴 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dy5ts4/btq9lTEFNTI/X1WL7WIqz7qWZN03th2OWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dy5ts4/btq9lTEFNTI/X1WL7WIqz7qWZN03th2OWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dy5ts4/btq9lTEFNTI/X1WL7WIqz7qWZN03th2OWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdy5ts4%2Fbtq9lTEFNTI%2FX1WL7WIqz7qWZN03th2OWk%2Fimg.png&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지로 2, 3번째 원소(20, 10)에 대하여 30이라는 수는 부분 수열의 길이를 증가시킬 수 있으므로 dp[2] + 1, dp[3] + 1의 값을 dp[4]의 값 후보에 올릴 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;438&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvZ32w/btq9iBdG33f/OsukccGo9sqKZwtFyXkGK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvZ32w/btq9iBdG33f/OsukccGo9sqKZwtFyXkGK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvZ32w/btq9iBdG33f/OsukccGo9sqKZwtFyXkGK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvZ32w%2Fbtq9iBdG33f%2FOsukccGo9sqKZwtFyXkGK1%2Fimg.png&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;438&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;자, 그렇다면 이제 본인의 길이 1과 1, 2, 3번째 원소에 대하여 본인을 추가시킨 LIS의 길이 중 가장 큰 값은 무엇인가? 이는&amp;nbsp;&lt;b&gt;2번째 원소로부터 본인의 길이를 추가시킨 3이 될 것&lt;/b&gt;임을 알 수 있다.&amp;nbsp;&lt;b&gt;따라서 해당 위치의 값은 3이 되는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;452&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/of2hS/btq9lnS53Z4/rJHDakyNVoGYWZYduKuZ5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/of2hS/btq9lnS53Z4/rJHDakyNVoGYWZYduKuZ5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/of2hS/btq9lnS53Z4/rJHDakyNVoGYWZYduKuZ5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fof2hS%2Fbtq9lnS53Z4%2FrJHDakyNVoGYWZYduKuZ5k%2Fimg.png&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;452&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음으로 5번째 원소인 20에 대하여 생각해보자. 앞선 논리를 이해했다면 해당 규칙을 그대로 적용시키기만 하면 5번째 원소의 위치에서의 LIS의 값은 쉽게 구할 수 있다. 우선, 본인의 길이인 1로 해당 원소의 값을 채운다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dF05Ev/btq9mmNn78a/dT2fDARkLXpckItOkYk90K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dF05Ev/btq9mmNn78a/dT2fDARkLXpckItOkYk90K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dF05Ev/btq9mmNn78a/dT2fDARkLXpckItOkYk90K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdF05Ev%2Fbtq9mmNn78a%2FdT2fDARkLXpckItOkYk90K%2Fimg.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이때, 2&lt;b&gt;0이라는 값은 앞선 원소(10, 20, 10, 30)에 대하여 그 값이 10인 경우(1번째, 3번째 원소)에 대해서만 부분 수열의 길이가 증가할 가능성&lt;/b&gt;이 있다. 따라서, &lt;b&gt;해당 위치의 LIS의 값에 본인의 길이를 + 1한 경우만 후보&lt;/b&gt;에 올라갈 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;448&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clQWyo/btq9gzAUcEM/Fiy76go9QAgfnhJqi7XjU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clQWyo/btq9gzAUcEM/Fiy76go9QAgfnhJqi7XjU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clQWyo/btq9gzAUcEM/Fiy76go9QAgfnhJqi7XjU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclQWyo%2Fbtq9gzAUcEM%2FFiy76go9QAgfnhJqi7XjU1%2Fimg.png&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;448&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;당연히 이 값 중 가장 큰 값은 2가 될 것이고, 해당 위치에는 2라는 값으로 채워질 것임을 알 수 있다. 직관적으로 보아도 해당 위치에서 가질 수 있는 LIS의 값은 2가 되는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;438&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0zVDw/btq9f42eNoA/pB4LLkZJG0SrxA9tkTIDD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0zVDw/btq9f42eNoA/pB4LLkZJG0SrxA9tkTIDD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0zVDw/btq9f42eNoA/pB4LLkZJG0SrxA9tkTIDD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0zVDw%2Fbtq9f42eNoA%2FpB4LLkZJG0SrxA9tkTIDD1%2Fimg.png&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;438&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;마지막 원소인 50역시 마찬가지 논리로 생각하면 dp[4]의 값을 활용하여 최종적으로 dp[6] = 4가 됨을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;421&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kYuOV/btq9f5GQx77/BpiRgytcSLcSStbcDgZ4A1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kYuOV/btq9f5GQx77/BpiRgytcSLcSStbcDgZ4A1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kYuOV/btq9f5GQx77/BpiRgytcSLcSStbcDgZ4A1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkYuOV%2Fbtq9f5GQx77%2FBpiRgytcSLcSStbcDgZ4A1%2Fimg.png&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;421&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 부분 문제의 관계를 생각하며 점화식을 도출한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;위의 규칙성을 점화식으로 세워보자. &lt;b&gt;우선, 해당 원소의 위치에 방문할 때 마다 해당 위치의 길이는 본인의 길이로 초기화 할 수 있다는 사실&lt;/b&gt;을 기반으로&amp;nbsp;&lt;b&gt;dp[i] = 1로 초기화(기저 조건)&lt;/b&gt;할 수 있다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;또한,&amp;nbsp;&lt;b&gt;방문한 원소의 위치의 모든 앞 원소에 대하여 부분 수열의 길이가 증가할 가능성이 존재(Arr[i] &amp;gt; Arr[1]...Arr[i - 1인 모든 경우)&lt;/b&gt;한다면,&amp;nbsp;&lt;b&gt;해당 위치의 dp 테이블의 값에 + 1(본인의 길이)을 한 값&lt;/b&gt;이&amp;nbsp;&lt;b&gt;dp[i]의 후보가 될 수 있다는 사실&lt;/b&gt;을 기반으로 점화식을 세울 수 있다. 즉 아래와 같은 식을 세울 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n7HfS/btq9fw46MOI/ba3pOk3eQT1BQHvkjnK4zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n7HfS/btq9fw46MOI/ba3pOk3eQT1BQHvkjnK4zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n7HfS/btq9fw46MOI/ba3pOk3eQT1BQHvkjnK4zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn7HfS%2Fbtq9fw46MOI%2Fba3pOk3eQT1BQHvkjnK4zk%2Fimg.png&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 점화식을 바탕으로 dp 테이블을 갱신하면서 최종적으로 전체 문제를 해결한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;여기에서는 Knapsack Problem과 다르게, &lt;b&gt;dp[N]의 값을 최종 답안으로 도출하면 안된다!&amp;nbsp;&lt;/b&gt;dp 테이블의 정의를 다시 살펴보면 &lt;b&gt;dp 테이블에 저장된 값은 해당 위치에서 '해당 원소가' 가질 수 있는 LIS의 값이었지, 해당 수열에서 가질 수 있는 LIS가 아니었다는 것에 주의&lt;/b&gt;해야 한다. 위의 예시에서 5, 6번째 위치를 바꿔 생각해보면 이해하기 쉽다. 아래 그림을 참고하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;396&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bruIVc/btq9hyO3qO0/Bxmhta9XkqRlgkEVvoVY11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bruIVc/btq9hyO3qO0/Bxmhta9XkqRlgkEVvoVY11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bruIVc/btq9hyO3qO0/Bxmhta9XkqRlgkEVvoVY11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbruIVc%2Fbtq9hyO3qO0%2FBxmhta9XkqRlgkEVvoVY11%2Fimg.png&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;396&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;지금까지 살펴본 바와 같이, 규칙성과 기억된 값(dp 테이블)을 적절히 활용하는 방법을 충분히 이해하였다면 코드를 작성하는 것은 매우 간단하고 쉬운 일이다. 아래 코드를 참고하도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1625984641014&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class LIS_DP1 {
	static int N;
	static int[] arr;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		arr = new int[N];
		for (int i = 0; i &amp;lt; N; i++) {
			arr[i] = sc.nextInt();
		}

		// 각 위치에서의 LIS를 저장할 1차원 dp 테이블을 정의한다.
		int[] dp = new int[N];
		// 최대 LIS의 값.
		int max = 1;

		// 첫 번째 원소부터 N번째 원소까지 dp 테이블의 값을 채워 나간다.
		for (int i = 0; i &amp;lt; N; i++) {
			// 우선 해당 위치를 본인의 길이(1)로 초기화한다.
			dp[i] = 1;
			// 현재 원소의 위치에 대하여, 앞의 원소의 값을 비교하며 값을 갱신한다.
			for (int j = 0; j &amp;lt; i; j++) {
				// 만일 부분 수열이 증가할 가능성이 있다면
				if (arr[j] &amp;lt; arr[i]) {
					// dp 테이블에 저장된 LIS를 바탕으로 가장 큰 값을 dp[i]의 값으로 갱신한다.
					dp[i] = Math.max(dp[i], dp[j] + 1);
				}
			}

			// 전체 수열에서 LIS의 값을 갱신한다.
			max = Math.max(max, dp[i]);
		}

		System.out.println(max);
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;해당 로직을 이해했다면 알 수 있겠지만, 각 위치에서 모든 앞 원소를 참고하는 2중 for문으로 구성되기 때문에 O(N^2)의 시간 복잡도를 갖는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*동적 계획법을 활용한 풀이 : O(NlogN)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이번에 살펴볼 방법은 직관적으로 이해하기도 힘들고,&amp;nbsp;&lt;b&gt;이분 탐색&lt;/b&gt;을 활용하기 때문에 난이도가 있는 풀이라고 할 수 있겠다. 그래서 이해가 잘 안 되는 것이 당연하지만.. 우선 아이디어의 컨셉부터 살펴 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;앞선 방법을 이용하면, 각 원소의 위치를 조사할 때 마다&amp;nbsp;&lt;b&gt;앞의 모든 원소를 탐색&lt;/b&gt;하는 과정을 거쳐야 했다. 따라서 O(N^2)이라는 시간 복잡도를 가지게 되었고, 이번에 사용하려는 방법에서는&amp;nbsp;&lt;b&gt;앞의 모든 원소를 탐색하는 과정을 O(logN)&lt;/b&gt;까지 줄여볼 수 있지 않을까? 라는 물음에서 출발한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문제를 특정한 부분 문제로 생각해보고, 해당 문제를 저장할 dp 테이블을 정의해본다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 현재 위치에서 부분 수열의 길이가 추가될 가능성이 있는가?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;앞의 해결 방법에서는&amp;nbsp;&lt;b&gt;앞의 모든 원소의 크기와 비교&lt;/b&gt;하면서&amp;nbsp;&lt;b&gt;현재 위치에서 부분 수열의 길이가 추가될 가능성이 있는지 파악&lt;/b&gt;하였다. 하지만 이 방법에서는 조금 다른 방법으로 그 가능성을 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 현재까지 조사한 앞 원소들에 대하여, 부분 수열을 만들 수 있는 최적의 수 조합을 저장해보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;예를 들어 i번째 원소를 조사한다고 생각했을때 1 ~ i - 1번째 원소에 대하여 i번째 원소가 부분 수열의 길이를 증가시킬 가능성이 있는지 생각하기 위해서, &lt;b&gt;1 ~ i - 1번째 원소에서 i번째 수가 부분 수열을 만들 수 있는 가능성을 쉽게 파악할 정보를 제공할 배열&lt;/b&gt;을 만든다는 이야기이다. 그런데 신기하게도 이 방법에서&amp;nbsp;&lt;b&gt;이 배열은 만들어진다면 그 가능성을 쉽게 파악할 수 있을 뿐&lt;/b&gt; 만 아니라,&lt;b&gt; 그 배열의 총 길이 자체가 LIS의 값이 된다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;실제 테스트 케이스를 바탕으로 그림을 보면서 이해해보자. 우선 &lt;u&gt;&lt;b&gt;i번째 위치에서&lt;/b&gt; &lt;b&gt;1차원 dp 테이블에 채워진 원소의 총 길이는 '전체 수열에서 해당 위치에서 가질 수 있는' LIS의 길이&lt;/b&gt;&lt;/u&gt;를 의미하고, &lt;u&gt;&lt;b&gt;원소의 값들은 i번째 원소가 부분 수열의 길이를 늘릴 가능성이 있는지 파악할 원소로 구성&lt;/b&gt;&lt;/u&gt;되어 있다. 여기에서 주의할 점은 앞 방법과 다르게&amp;nbsp;&lt;b&gt;해당 위치에서 기록된 dp배열의 길이 그 자체가 전체 문제(최종 LIS의 값)의 최적해&lt;/b&gt;가 된다는 사실이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JgVHI/btq9hzmTYFe/BOAVzo9ssiRRRBmEpIQuH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JgVHI/btq9hzmTYFe/BOAVzo9ssiRRRBmEpIQuH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JgVHI/btq9hzmTYFe/BOAVzo9ssiRRRBmEpIQuH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJgVHI%2Fbtq9hzmTYFe%2FBOAVzo9ssiRRRBmEpIQuH0%2Fimg.png&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 첫 번째 원소부터 생각해보면, 당연히 10이라는 값 자체를 dp[1]에 대입해주면된다. 그렇다면 테이블의 정의에 따라 1번째 원소에서 채워진 원소의 총 길이는 1로 LIS의 길이와 같고, 뒤에 조사할 수들이 부분 수열의 길이를 늘릴 가능성이 있는 정보를 제공해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;410&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjmdcF/btq9hyuNHWT/XMu6L3gEEol5jMLa9HoSHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjmdcF/btq9hyuNHWT/XMu6L3gEEol5jMLa9HoSHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjmdcF/btq9hyuNHWT/XMu6L3gEEol5jMLa9HoSHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjmdcF%2Fbtq9hyuNHWT%2FXMu6L3gEEol5jMLa9HoSHK%2Fimg.png&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;410&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음으로 두 번째 원소를 생각해보자. 2번째 위치에서 LIS의 값은 2이기 때문에, dp[2]는 20을 채우는 것이 당연할 것이다. 또한 이 값들이 이후 3 ~ 6번째 원소의 부분 수열의 길이를 늘릴 가능성이 있는지 파악할 정보가 된다는 것을 기억하라.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;422&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddlbMv/btq9fXVEWAv/gbaAvqcWoq9ObTZBPkbTW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddlbMv/btq9fXVEWAv/gbaAvqcWoq9ObTZBPkbTW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddlbMv/btq9fXVEWAv/gbaAvqcWoq9ObTZBPkbTW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddlbMv%2Fbtq9fXVEWAv%2FgbaAvqcWoq9ObTZBPkbTW1%2Fimg.png&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;422&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;세 번째 원소부터가 중요하다. 우선, 우리가 아는 바로는 3번째 원소의 위치에서 LIS는 2가 되어야한다. 왜냐하면, &lt;b&gt;3번째 위치에서 전체적으로 가질 수 있는 LIS의 최대 값은 이전에 10, 20으로 구성된 부분 수열의 길이를 저장&lt;/b&gt;하면 되기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;따라서, dp의 원소는 따로 조작할 필요가 없어보인다. 대신,&amp;nbsp;&lt;b&gt;dp에 구성된 원소는 다음 원소가 부분 수열의 길이를 늘릴 가능성이 있는 정보를 제공&lt;/b&gt;한다고 하였다. 우선 이해가 잘 안되겠지만, 현재 위치의 원소의 값이 dp에 저장된 값들 보다 같거나 작은 값이 있다면, 해당 값들 중 가장 작은 값의 위치와 원소를 교환하고 다음 과정을 진행한다고 알아두고 넘어가자.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZFnfC/btq9lTrbtgQ/0D9Vj1qX6nbkBcYGEwi2qK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZFnfC/btq9lTrbtgQ/0D9Vj1qX6nbkBcYGEwi2qK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZFnfC/btq9lTrbtgQ/0D9Vj1qX6nbkBcYGEwi2qK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZFnfC%2Fbtq9lTrbtgQ%2F0D9Vj1qX6nbkBcYGEwi2qK%2Fimg.png&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음은 네 번째 원소이다. 우선, 4번째 위치에서 가질 수 있는 LIS는 3임을 알 수 있다(10, 20, 30으로 부분 수열이 구성됨). 따라서, &lt;b&gt;dp[3]에 30이라는 값이 추가되는 것이 자연스러울 것인데 여기서부터는 어떤 규칙을 바탕으로 dp테이블에 원소를 넣는지 이해&lt;/b&gt;해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;420&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sbN83/btq9gA7Lfcf/Jf6caXj8XYpMR9zZBStafk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sbN83/btq9gA7Lfcf/Jf6caXj8XYpMR9zZBStafk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sbN83/btq9gA7Lfcf/Jf6caXj8XYpMR9zZBStafk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsbN83%2Fbtq9gA7Lfcf%2FJf6caXj8XYpMR9zZBStafk%2Fimg.png&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;420&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선 우리는 지금까지 &lt;b&gt;Arr 배열에 주목하여 30이 부분 수열의 길이를 늘릴 수 있는지 판단&lt;/b&gt;하였다. 하지만 앞서 말했듯이 &lt;b&gt;뭔지는 모르겠지만 dp 테이블의 원소들의 값은 30이 부분 수열의 길이를 늘릴 수 있는지 판단할 정보를 제공&lt;/b&gt;하고 있다고 하였다. 우리가&lt;b&gt; Arr 배열을 보면서 판단한 정보는 부분 수열 10, 20이 현재 가장 긴 LIS를 갖는 수열&lt;/b&gt;임을 확인했을 것이다. 그런데 확인해보면 &lt;b&gt;dp 배열에도 10, 20의 값이 저장되어 있음&lt;/b&gt;을 알 수 있다. 우리는 이 정보로부터 30이라는 숫자가 부분 수열의 길이를 늘릴 가능성이 있음을 파악할 수 있다. 그런데 여기서 주의할 점은, &lt;u&gt;&lt;b&gt;dp 배열에 저장된 값들이 현재까지 원소들을 조사하며 만들어진 LIS 배열 그 자체라고 생각하면 안된다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 5번째 원소에 대하여 dp배열을 계속 추가해보자. 마찬가지로, 해당 위치에서 가질 수 있는 LIS는 4일 것이고, 앞에서 구성된 부분 수열 중 가장 긴 부분 수열은 10, 20, 30으로 구성된 것으로 보아 dp[4]에 50이라는 값을 추가해주면 된다는 것을 알 수 있다. &lt;b&gt;dp 배열에 저장된 원소를 확인해보면, 50이라는 값이 dp 배열에 저장된 모든 원소보다 큼&lt;/b&gt;을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;423&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfbLn3/btq9gYN0E7R/E9K4foSKi5bwl9Gr8sd1n1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfbLn3/btq9gYN0E7R/E9K4foSKi5bwl9Gr8sd1n1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfbLn3/btq9gYN0E7R/E9K4foSKi5bwl9Gr8sd1n1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfbLn3%2Fbtq9gYN0E7R%2FE9K4foSKi5bwl9Gr8sd1n1%2Fimg.png&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;423&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;마지막으로 6번째 원소인 20을 다시 살펴보자. 이번에는 &lt;b&gt;dp 배열을 참고해보았을 때, 저장된 값들 모두에 대하여 20이 크다는 보장이 없다.&amp;nbsp;&lt;/b&gt;3번째 원소때와 마찬가지로 현재 위치의 원소의 값이 dp에 저장된 값들 보다 같거나 작은 값이 있다면, 해당 값들 중 가장 작은 값의 위치와 원소를 교환하는 작업을 진행해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;408&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBzWSX/btq9gA0XQLP/qrxjsqqgJFCMoaM4T6dLS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBzWSX/btq9gA0XQLP/qrxjsqqgJFCMoaM4T6dLS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBzWSX/btq9gA0XQLP/qrxjsqqgJFCMoaM4T6dLS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBzWSX%2Fbtq9gA0XQLP%2FqrxjsqqgJFCMoaM4T6dLS0%2Fimg.png&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;408&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;자, 어떻게든 이 과정을 따라오며 dp 테이블을 갱신하는 과정을 진행해보았고 결론적으로 dp에 구성된 원소의 길이는 4로, 우리가 구하고자 했던 LIS의 값 4와 일치한다는 것을 확인할 수 있다. 그런데 왜 이런일이 가능한 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) dp 테이블에 최적의 수 조합을 저장한다?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;앞 과정은 우선 dp 테이블을 갱신하는 과정이 어떻게 진행되는지 무지성으로 따라하며 보여준 것이고, 이번에는 테스트 케이스를 달리하여 이해해보도록하자. 아래 그림을 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;410&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OUAi5/btq9fxJHoff/GkH7qHRS1HT2PlZrmlwag1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OUAi5/btq9fxJHoff/GkH7qHRS1HT2PlZrmlwag1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OUAi5/btq9fxJHoff/GkH7qHRS1HT2PlZrmlwag1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOUAi5%2Fbtq9fxJHoff%2FGkH7qHRS1HT2PlZrmlwag1%2Fimg.png&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;410&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;앞서 갱신한 논리를 바탕으로 2번째 원소까지 dp 테이블을 갱신하면, 다음과 같은 값들을 저장함을 알 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;그렇다면 바로 세 번째 원소 50에 대하여 갱신을 진행해보자.&amp;nbsp;&lt;b&gt;앞선 논리를 바탕으로 한다면, dp에 저장된 모든 원소에 대하여 작은 부분 중 가장 작은 값의 위치와 해당 값을 바꿔줘야 하므로, 다음과 같이 갱신이될 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDZQ1C/btq9gXuMeyQ/WwBK7KB11ut3JhM5op1hW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDZQ1C/btq9gXuMeyQ/WwBK7KB11ut3JhM5op1hW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDZQ1C/btq9gXuMeyQ/WwBK7KB11ut3JhM5op1hW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDZQ1C%2Fbtq9gXuMeyQ%2FWwBK7KB11ut3JhM5op1hW1%2Fimg.png&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;네 번째 원소도 마찬가지로 갱신하면 다음과 같이 갱신이 될 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;425&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxzcWI/btq9mlA0bu3/kE5wBFCECK6A4nsQqdsvsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxzcWI/btq9mlA0bu3/kE5wBFCECK6A4nsQqdsvsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxzcWI/btq9mlA0bu3/kE5wBFCECK6A4nsQqdsvsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxzcWI%2Fbtq9mlA0bu3%2FkE5wBFCECK6A4nsQqdsvsk%2Fimg.png&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;425&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;만일 이러한 갱신이 진행되지 않는다면 어떻게 될까? 우선 직관적으로 보았을 때,&amp;nbsp;&lt;b&gt;해당 수열에서 최종 LIS 배열은 {10, 15, 20, 30}으로 구성될 것&lt;/b&gt;을 알 수 있다.&amp;nbsp;&lt;b&gt;그리고 우리는 dp 배열 만을 바탕으로 현재 위치의 수가 부분 수열의 길이를 늘릴 가능성이 있는지 파악하겠다&lt;/b&gt;고 하였다. 하지만&amp;nbsp;&lt;b&gt;앞선 갱신과정이 진행되지 않는다면, 2번째 원소의 위치에는 100이라는 값이 저장되어 있을 것이고 뒤에오는 수인 15, 20, 30은 dp 배열만 보았을 때 부분 수열의 길이를 늘릴 여지가 없음&lt;/b&gt;을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;또 반대로 &lt;b&gt;이런 갱신이 이루어 졌다면 2번째 원소의 위치는 위 그림과 같이 15로 갱신이 될 것이고, 그 뒤에 오는 수인 20, 30이 dp 배열만 보고도 부분 수열의 길이를 늘릴 여지가 있다는 것을 확인&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;445&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhog2U/btq9gpdlw0h/u5GMrar5bAiQabsfhXAry0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhog2U/btq9gpdlw0h/u5GMrar5bAiQabsfhXAry0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhog2U/btq9gpdlw0h/u5GMrar5bAiQabsfhXAry0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhog2U%2Fbtq9gpdlw0h%2Fu5GMrar5bAiQabsfhXAry0%2Fimg.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;445&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgKSt8/btq9gRgmaon/U9Rtdzef6FcKihivLAhDIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgKSt8/btq9gRgmaon/U9Rtdzef6FcKihivLAhDIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgKSt8/btq9gRgmaon/U9Rtdzef6FcKihivLAhDIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgKSt8%2Fbtq9gRgmaon%2FU9Rtdzef6FcKihivLAhDIK%2Fimg.png&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;따라서 이런 갱신을 진행해주는 것이다. 다만 이때 주의할 것은&amp;nbsp;&lt;b&gt;저장된 원소가 LIS 배열 그 자체를 의미하지는 않는다&lt;/b&gt;고 하였다. 예를 들어 아래 수열을 바탕으로 LIS를 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;428&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdKHfN/btq9gXBzAAf/rdZ9ILzVpct917CbucqCMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdKHfN/btq9gXBzAAf/rdZ9ILzVpct917CbucqCMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdKHfN/btq9gXBzAAf/rdZ9ILzVpct917CbucqCMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdKHfN%2Fbtq9gXBzAAf%2FrdZ9ILzVpct917CbucqCMK%2Fimg.png&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;428&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그림에서 확인해보면 LIS 배열은 {10, 20, 30}이 되는 것을 확인할 수 있는데, dp 배열에 저장된 수들과 일치하지 않음을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(4) 이게 왜 되는겨..?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;아무튼 이 과정들을 진행하면 &lt;b&gt;최종적으로 dp 배열에 채워진 원소의 값들이 LIS 배열 자체를 의미하지는 않더라도, dp 배열의 길이 자체는 LIS의 길이가 됨&lt;/b&gt;을 &lt;b&gt;경험적으로 확인&lt;/b&gt;할 수 있었다. 계속해서 강조하지만,&amp;nbsp;&lt;b&gt;해당 배열의 길이는 LIS를 의미하지만 구성된 원소는 다음 원소가 부분 수열의 길이를 늘릴 수 있는 가능성을 보여줄 최적화된 정보&lt;/b&gt;라고 하였다. 이 사실을 잊지 말고 최근에 본 예시를 바탕으로 수열을 추가해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;416&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EvFuI/btq9nDVIvro/bYNSyVDNzCxlqyYJNxFdtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EvFuI/btq9nDVIvro/bYNSyVDNzCxlqyYJNxFdtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EvFuI/btq9nDVIvro/bYNSyVDNzCxlqyYJNxFdtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEvFuI%2Fbtq9nDVIvro%2FbYNSyVDNzCxlqyYJNxFdtK%2Fimg.png&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;416&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위에 제시한 예시에서, 마지막에 20이라는 수가 추가되었다면 같은 논리에 의하여 dp[3]의 값은 20으로 교체될 것이다. 여기서 우리는&amp;nbsp;&lt;b&gt;교체 된다는 사실에 주목&lt;/b&gt;하여야 한다. 우선 &lt;b&gt;어차피 '교체'가 일어난다면, 해당 dp 원소의 최종 길이(= LIS = 3)는 변화가 없을 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;두 번째는 정보 제공의 문제이다. 이 '교체'로 인하여 이후 추가될 원소들에게 부분 수열의 길이가 늘어날 가능성이 있는지 정보를 제공&lt;/b&gt;해주었다! 아래 그림을 참고하면 이해하기 쉬울 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;432&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh4ysz/btq9nB4FyOL/MXzXyc8SFVWrjxXp2Hh3h0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh4ysz/btq9nB4FyOL/MXzXyc8SFVWrjxXp2Hh3h0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh4ysz/btq9nB4FyOL/MXzXyc8SFVWrjxXp2Hh3h0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh4ysz%2Fbtq9nB4FyOL%2FMXzXyc8SFVWrjxXp2Hh3h0%2Fimg.png&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;432&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;우리는 지금까지 {10, 20, 30}이라는 부분 수열을 생각하고 있었지만 &lt;b&gt;해당 갱신으로 인하여 자연스럽게 {10, 15, 20}이라는 부분 수열이 이후 부분 수열의 길이를 늘릴 때 더 최적의 정보를 제공한다는 것&lt;/b&gt;을 알게 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;즉,&amp;nbsp;&lt;u&gt;가장 작은 증가 폭을 갖는 부분 수열을 시시각각 갱신해주는 것&lt;/u&gt;&lt;/b&gt;이 이후 부분 수열의 길이를 늘릴 때 유용할 것이고&amp;nbsp;&lt;u&gt;&lt;b&gt;어차피 교체가 일어나는 과정에서 LIS의 길이는 변화하지 않기 때문&lt;/b&gt;&lt;/u&gt;에 dp에 구성된 원소를 기준에 맞게 갱신하는 것은 상관없다는 것이다. 어떻게 이런 아이디어를 생각해 낸 것일까..? 난 못할듯..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 부분 문제의 관계를 생각하며 점화식을 도출한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;자, 앞의 규칙성을 이해하였다면 점화식을 도출하는 것은 역시 간단하다. 우선,&amp;nbsp;&lt;b&gt;원소를 추가할 때 마다 현재까지 저장된 dp를 탐색하며 해당 원소보다 큰 값을 갖는 원소가 있는지 탐색&lt;/b&gt;한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이때 &lt;b&gt;그런 값을 찾았다면, 그런 값들 중 가장 작은 값과 해당 원소의 위치를 교체&lt;/b&gt;해주고,&amp;nbsp;&lt;b&gt;그런 값을 찾지 못했다면, dp 배열에 채워진 원소의 가장 마지막 부분에 해당 원소를 추가해주는 작업&lt;/b&gt;을&lt;b&gt; 반복적으로 진행&lt;/b&gt;해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;이때, dp 에 저장된 원소들은 '오름차순'으로 정렬되어 있다는 사실을 알 수 있고 이 때문에&amp;nbsp;&lt;u&gt;초기에 고려했던 앞 부분을 탐색하는 과정을 '이분 탐색'을 바탕으로 O(LogN)으로 줄일 수&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt; 있다.&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;따라서, 해당 알고리즘을 사용하면 시간 복잡도는 모든 원소(N개)에 대하여 탐색하는 과정을 O(LogN)만큼 반복하므로 총 O(NLogN)을 가진다는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 점화식을 바탕으로 dp 테이블을 갱신하면서 최종적으로 전체 문제를 해결한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;초기에 설정한 바와 같이&amp;nbsp;&lt;b&gt;최종 dp 테이블에 채워진 원소의 길이 = LIS&lt;/b&gt;임을 확인할 수 있다. 따라서 dp테이블에 실질적으로 저장된 원소의 값들의 길이를 출력해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이 논리는 이해하기도 힘들고, 또 구현하는 과정에서 이분 탐색을 활용해야하기 때문에 구현하는 과정도 기존 dp에 비하여 간단하지 않다. 아래 코드를 참고하도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1625991377068&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class LIS_DP2 {
	static int N;
	static int[] arr, dp;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		arr = new int[N];
		for (int i = 0; i &amp;lt; N; i++) {
			arr[i] = sc.nextInt();
		}

		// dp에 실질적으로 저장된 원소의 길이 = LIS인 1차원 dp테이블을 만든다.
		// 해당 dp에 저장된 원소(0이 아닌 값)들은 이후 조사하는 원소들이 부분 수열을 늘릴 수 있을지에 대한 정보를 제공한다.
		dp = new int[N];
		// 처음에 저장된 원소는 없으므로, LIS = 0이다.
		int LIS = 0;

		// 첫 번째 원소부터 N번째 원소까지 dp 테이블의 값을 채워 나간다.
		for (int i = 0; i &amp;lt; N; i++) {
			// 이분 탐색을 활용하여 dp테이블에 저장된 원소를 탐색하며 현재 선택된 숫자가 dp테이블의 어떤 위치에 포함될지 파악한다.
			int idx = BinarySearch(arr[i], 0, LIS, LIS + 1);
			
			// 찾지 못한 경우
			if(idx == -1) {
				// 가장 마지막 위치에 원소를 삽입하고 LIS의 길이를 늘린다.
				dp[LIS++] = arr[i];
			}
			// 찾은 경우
			else {
				// 해당 위치에 현재 값을 삽입하여 갱신한다.
				dp[idx] = arr[i];
			}
		}
		
		// LIS의 길이를 출력한다.
		System.out.println(LIS);

		sc.close();
	}

	private static int BinarySearch(int num, int start, int end, int size) {
		int res = 0;
		while (start &amp;lt;= end) {
			// 중앙 값을 찾는다.
			int mid = (start + end) / 2;

			// 만일 현재 선택된 원소가 해당 원소보다 작거나 같다면, 앞 부분을 탐색한다.
			if (num &amp;lt;= dp[mid]) {
				// 해당 원소의 위치를 기억해둔다.
				res = mid;
				end = mid - 1;
			}
			// 만일 현재 선택된 원소가 해당 원소보다 크다면, 뒷 부분을 탐색한다.
			else {
				start = mid + 1;
			}
		}

		// dp테이블에서 삽입될 위치를 찾지 못한 경우(즉, 모든 수들보다 큰 경우).
		if (start == size) {
			return -1;
		}
		// dp테이블에서 삽입될 위치를 찾은 경우.
		else {
			return res;
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;해당 문제의 최대 수열의 크기가 N이기 때문에 시간에서 큰 차이가 나지 않아보이지만, 입력 값이 클 수록 그 차이는 더 확연해 질 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;61&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxCsF3/btq9f5mCgSj/3vA2fj3p7eMzYXdxctooSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxCsF3/btq9f5mCgSj/3vA2fj3p7eMzYXdxctooSk/img.png&quot; data-alt=&quot;1번 풀이 : 아래, 2번 풀이 : 위&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxCsF3/btq9f5mCgSj/3vA2fj3p7eMzYXdxctooSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxCsF3%2Fbtq9f5mCgSj%2F3vA2fj3p7eMzYXdxctooSk%2Fimg.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;61&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1번 풀이 : 아래, 2번 풀이 : 위&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 여기까지가 &lt;b&gt;다이나믹 프로그래밍의 대표적인 예제인 LIS에 관한 설명&lt;/b&gt;이다. 오히려 Knapsack Problem보다 2번째 풀이에서는 격이 다른 어려움을 느꼈을지도 모른다. 계속해서 얘기하지만 당연하다. 사실 나도 잘 이해를 못하겠다 어떻게 이런 생각을 하는지.. 아무튼 이 문제로 부터는&amp;nbsp;&lt;b&gt;정보를 어떻게 저장할 것이고, 그 정보를 어떻게 활용할 수 있느냐&lt;/b&gt;에 대한 인싸이트를 얻어볼 수 있다.&lt;/p&gt;</description>
      <category>Algorithm/동적 계획법</category>
      <category>boj 11053</category>
      <category>LIS</category>
      <category>Longest Increasing Subsequence</category>
      <category>가장 긴 증가하는 부분 수열</category>
      <category>백준 11053</category>
      <category>최장 증가 부분 수열</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/89</guid>
      <comments>https://sskl660.tistory.com/89#entry89comment</comments>
      <pubDate>Sun, 11 Jul 2021 17:19:06 +0900</pubDate>
    </item>
    <item>
      <title>[Java]배낭 문제(Knapsack Problem)</title>
      <link>https://sskl660.tistory.com/88</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*배낭 문제(Knapsack Problem)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;&lt;b&gt;배낭 문제&lt;/b&gt;는&amp;nbsp;&lt;b&gt;조합 최적화&lt;/b&gt;의 유명한 문제로, 배낭에 담을 수 있는&amp;nbsp;&lt;b&gt;무게의 최댓값이 정해져 있는 경우&lt;/b&gt;, &lt;b&gt;'일정 가치'와 '무게'가 있는 짐&lt;/b&gt;들을 배낭에 넣을 때 &lt;b&gt;가치의 합이 최대가 되로록 짐을 고르는 방법&lt;/b&gt;을 찾는 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;※ 조합 최적화란 쉽게 말해 모든 조합의 경우의 수를 고려하지 않고, 최적화하여 조합의 경우의 수를 줄이는 것을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;배낭 문제는 두 가지로 나눌 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(1) 분할가능 배낭문제(Fractional Knapsack Problem)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;짐을 쪼갤 수 있다는 가정을 둔다. 예를 들어, 물건이 4kg이고 가치가 8이라면 물건을 2kg으로 나눠 가치가 4인 경우로 분할 해 배낭에 담을 수 있다고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;해당 문제는&amp;nbsp;&lt;b&gt;그리디 알고리즘&lt;/b&gt;을 활용하여 해결할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(2) 0-1 배낭문제(0-1 Knapscak Problem)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;짐을 쪼갤 수 없다는 가정을 둔다. 예를 들어, 물건이 4kg이고 가치가 8이라면 물건은 분할 불가능하고 그 무게와 가치 그대로 배낭에 담을 수 있다고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;해당 문제는&amp;nbsp;&lt;b&gt;동적 계획법&lt;/b&gt;을 활용하여 해결할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*0-1 배낭 문제(0-1 Knapsack Problem)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;앞서 설명한 바와 같이 물건을 쪼갤 수 없는 경우를 가정하고 배낭에 물건을 담아 얻을 수 있는 최대 가치를 구하는 문제이다. 즉, 물건을 넣거나(1) 빼거나(0)라는 의미를 강조하기 위해 0-1 배낭 문제라는 이름이 붙었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;※ &lt;b&gt;0-1 배낭 문제와 다이나믹 프로그래밍&amp;nbsp;&lt;/b&gt;: 앞서 설명한 바와 같이 0-1 배낭 문제는 동적 계획법을 활용하여 문제를 해결할 수 있다. 여기서는 백준의 Gold5 12865 평범한배낭 문제를 예로 들어 알고리즘을 설명하도록 하겠다. 해당 문제 자체가 0-1 배낭 문제를 나타낸다고 보면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;※ 문제 주소 : &lt;a href=&quot;https://www.acmicpc.net/problem/12865&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/12865&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625928008975&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;12865번: 평범한 배낭&quot; data-og-description=&quot;첫 줄에 물품의 수 N(1 &amp;le; N &amp;le; 100)과 준서가 버틸 수 있는 무게 K(1 &amp;le; K &amp;le; 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 &amp;le; W &amp;le; 100,000)와 해당 물건의 가치 V(0 &amp;le; V &amp;le; 1,000)&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/12865&quot; data-og-url=&quot;https://www.acmicpc.net/problem/12865&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sC7Kp/hyKQuOyXMn/HpcaGJbVyz8VuKCMZYlz2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/12865&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/12865&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sC7Kp/hyKQuOyXMn/HpcaGJbVyz8VuKCMZYlz2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;12865번: 평범한 배낭&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫 줄에 물품의 수 N(1 &amp;le; N &amp;le; 100)과 준서가 버틸 수 있는 무게 K(1 &amp;le; K &amp;le; 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 &amp;le; W &amp;le; 100,000)와 해당 물건의 가치 V(0 &amp;le; V &amp;le; 1,000)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*백 트래킹을 활용한 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;동적 계획법을 활용하기 전에, 가장 일반적으로 생각해볼 수 있는 방법은 백트래킹 패러다임을 적용해보는 것이다.&amp;nbsp;&lt;b&gt;물건이 들어있거나, 들어 있지 않거나(부분 집합의 논리)&lt;/b&gt;를 바탕으로 모든 경우를 탐색해서 문제를 해결할 수 있다. 아래 코드를 참고해보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625929004301&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class KnapSack_BackTracking {
	static int N, K;
	static int[][] items;
	static int max;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		K = sc.nextInt();
		// 물건 당 첫 번째 열에는 물건의 무게를, 두 번째 열에는 물건의 가치를 저장한다.
		items = new int[N][2];
		for (int i = 0; i &amp;lt; N; i++) {
			items[i][0] = sc.nextInt();
			items[i][1] = sc.nextInt();
		}
		max = 0;

		// DFS 탐색을 활용하여 모든 경우를 고려해본다.
		dfs(0, 0, 0);
		System.out.println(max);
		sc.close();
	}

	private static void dfs(int depth, int weight, int val) {
		// 모든 물건을 확인하였으면 최종 물건의 가치를 확인하고 재귀를 종료한다.
		if (depth == N) {
			// 현재까지의 최대 가치보다 크다면 값 갱신.
			max = Math.max(max, val);
			return;
		}
		// 물건을 포함할 수 있는 경우 포함하고 재귀를 진행한다.
		if (weight + items[depth][0] &amp;lt;= K) {
			dfs(depth + 1, weight + items[depth][0], val + items[depth][1]);
		}
		// 물건을 포함하지 않고 재귀를 진행한다.
		if (weight &amp;lt;= K) {
			dfs(depth + 1, weight, val);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;주어진 테스트 케이스를 적용해보면, 가방에 조합이 가능한 모든 경우를 고려해보면서 재귀가 진행되는 것을 확인할 수 있을 것이다. 또한, 모든 경우를 고려하였기 때문에&amp;nbsp;&lt;b&gt;시간이 충분하다면&lt;/b&gt; 정확한 결과를 도출할 것이다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;하지만 문제는 당연히 시간이다. 이 방식의 경우 &lt;b&gt;물건을 선택하거나, 선택하지 않는 부분 집합의 논리를 사용하기 때문&lt;/b&gt;에&amp;nbsp;&lt;b&gt;O(2^N)의 지수 시간 복잡도&lt;/b&gt;를 갖는다. 즉, 문제에서 주어진 것 처럼 N이 100인 경우에는 2^100번 정도의 연산을 진행해야만 문제를 해결할 수 있다! 따라서 코드를 제출해보면 시간 초과가 발생하는 것을 확인할 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*동적 계획법을 활용한 풀이(2차원 dp 테이블 사용)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이번에는 동적 계획법을 사용하여 문제를 풀이해보자. 해당 블로그에 포스팅한 &lt;b&gt;'동적 계획법 접근 방식'&lt;/b&gt;을 바탕으로 문제에 접근해보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 참고 : &lt;a href=&quot;https://sskl660.tistory.com/87&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sskl660.tistory.com/87&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625929470873&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java]동적 계획법(Dynamic Programming)&quot; data-og-description=&quot;*동적 계획법(Dynamic Programming) -&amp;gt;동적 계획법이란&amp;nbsp;특정 범위까지의 최적해(상위 문제)를 구하기 위하여&amp;nbsp;다른 범위까지의 최적해(하위 문제)를 이용하여 효율적으로 해를&amp;nbsp;구하는&amp;nbsp;알고리즘 설계 &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/87&quot; data-og-url=&quot;https://sskl660.tistory.com/87&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cZJTCW/hyKQnWF2e2/kpUEIFYBkDMojmNapWEkkK/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/cDcdDj/hyKQwlL58j/VmWrix5ezCZWMCkYW6ZO5K/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/i48vd/hyKQsp8uy8/bhK8NmLJDEqWg29K3Ltr8K/img.png?width=952&amp;amp;height=627&amp;amp;face=0_0_952_627&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/87&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/87&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cZJTCW/hyKQnWF2e2/kpUEIFYBkDMojmNapWEkkK/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/cDcdDj/hyKQwlL58j/VmWrix5ezCZWMCkYW6ZO5K/img.png?width=678&amp;amp;height=269&amp;amp;face=0_0_678_269,https://scrap.kakaocdn.net/dn/i48vd/hyKQsp8uy8/bhK8NmLJDEqWg29K3Ltr8K/img.png?width=952&amp;amp;height=627&amp;amp;face=0_0_952_627');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java]동적 계획법(Dynamic Programming)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*동적 계획법(Dynamic Programming) -&amp;gt;동적 계획법이란&amp;nbsp;특정 범위까지의 최적해(상위 문제)를 구하기 위하여&amp;nbsp;다른 범위까지의 최적해(하위 문제)를 이용하여 효율적으로 해를&amp;nbsp;구하는&amp;nbsp;알고리즘 설계&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문제를 특정한 부분 문제로 생각해보고, 해당 문제를 저장할 dp 테이블을 정의해본다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 물건 1개를 넣을 때, 각 무게(1 ~ K)당 가질 수 있는 최대 가치는 무엇일까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 물건은 한 개만 존재한다고 가정해보고, &lt;b&gt;각 무게당 넣을 수 있는 물건의 최대 가치를 생각해보는 것&lt;/b&gt;이다. 예를 들어 테스트 케이스에서 주어진 물건 중 무게가 6이고 가치가 13인 물건에 대해서만 생각해보면 아래 테이블과 같이 생각해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;158&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYgMaY/btq9fwKt0hO/VrLZJhxPjjTw77u9QUwnY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYgMaY/btq9fwKt0hO/VrLZJhxPjjTw77u9QUwnY1/img.png&quot; data-alt=&quot;1부터 7까지의 무게에서, 무게는 6이고 가치는 13인 물건을 넣을 때 각 무게에서의 최대 가치는?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYgMaY/btq9fwKt0hO/VrLZJhxPjjTw77u9QUwnY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYgMaY%2Fbtq9fwKt0hO%2FVrLZJhxPjjTw77u9QUwnY1%2Fimg.png&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;158&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1부터 7까지의 무게에서, 무게는 6이고 가치는 13인 물건을 넣을 때 각 무게에서의 최대 가치는?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 무게가 1인 경우, 해당 물건을 넣을 수 없으므로 다음과 같이 테이블을 채울 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;168&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oNJyx/btq9e0ZGL3q/IgLXxgsqzX12J1NSgR4Ze0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oNJyx/btq9e0ZGL3q/IgLXxgsqzX12J1NSgR4Ze0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oNJyx/btq9e0ZGL3q/IgLXxgsqzX12J1NSgR4Ze0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoNJyx%2Fbtq9e0ZGL3q%2FIgLXxgsqzX12J1NSgR4Ze0%2Fimg.png&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;168&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;다음으로 무게가 2인 경우도 마찬가지로 물건을 넣을 수 없으므로 다음과 같이 테이블을 채울 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;146&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DKfSH/btq9fxJq8q3/fZqEIx3HEVQEh8zTQPXtY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DKfSH/btq9fxJq8q3/fZqEIx3HEVQEh8zTQPXtY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DKfSH/btq9fxJq8q3/fZqEIx3HEVQEh8zTQPXtY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDKfSH%2Fbtq9fxJq8q3%2FfZqEIx3HEVQEh8zTQPXtY1%2Fimg.png&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;146&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;같은 방식으로 무게가 5인 경우까지 0으로 채울 수 있고, 무게가 6이 되는 순간 물건을 넣을 수 있으므로 무게가 6인 경우는 가질 수 있는 최대 가치가 13이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;151&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIYj8A/btq9kPWh8az/k4pZMaDoy9cEwAbgbaIKH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIYj8A/btq9kPWh8az/k4pZMaDoy9cEwAbgbaIKH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIYj8A/btq9kPWh8az/k4pZMaDoy9cEwAbgbaIKH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIYj8A%2Fbtq9kPWh8az%2Fk4pZMaDoy9cEwAbgbaIKH0%2Fimg.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;151&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다음으로 무게가 7인 경우 역시, 해당 물건을 넣을 수 있으므로 13으로 채워짐을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;146&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YGCEs/btq9iBxrtW2/QWdz7Ct1KJGQOdKUlMkMyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YGCEs/btq9iBxrtW2/QWdz7Ct1KJGQOdKUlMkMyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YGCEs/btq9iBxrtW2/QWdz7Ct1KJGQOdKUlMkMyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYGCEs%2Fbtq9iBxrtW2%2FQWdz7Ct1KJGQOdKUlMkMyk%2Fimg.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;146&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;자, 그러면 이 데이터에서 어떠한 규칙성을 발견할 수 있을까? 물건이 단 한 개만 존재하는 경우에는 단순히&amp;nbsp;&lt;b&gt;물건을 넣을 수 있으면 가치를 넣고, 넣을 수 없으면 가치를 0으로 두는 규칙&lt;/b&gt;을 사용하여 dp 테이블을 완성할 수 있다. 이제 이러한 느낌을 바탕으로 여러 물건이 주어진 경우를 고려해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 물건을 1 ~ N개를 넣을 때, 각 무게(1 ~ K)당 가질 수 있는 최대 가치는 무엇일까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이번에는 편의상 이해를 돕기 위해, 무게가 3이고 가치가 6인 물건과 무게가 4이고 가치가 8인 문제를 먼저 넣는다는 가정하에 테이블을 갱신해보자. 우선, 무게가 3이고 가치가 6인 물건은 앞의 논리대로 테이블을 채웠다고 생각한다. 그렇다면 아래와 같은 상태일 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;337&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tIw0j/btq9kPvez2T/jzAAFAa2OgOiXQgpepJpP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tIw0j/btq9kPvez2T/jzAAFAa2OgOiXQgpepJpP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tIw0j/btq9kPvez2T/jzAAFAa2OgOiXQgpepJpP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtIw0j%2Fbtq9kPvez2T%2FjzAAFAa2OgOiXQgpepJpP1%2Fimg.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;337&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이제, 무게가 4이고 가치가 8인 물건을 앞선 방식으로 넣어보자. 우선 무게가 1인 경우 물건을 담을 수 없으므로 가치는 0일 것이다. 이는 무게가 3인 경우까지 반복 될 것이다. &lt;u&gt;&lt;b&gt;그런데 무게가 3이 되는 지점에 0을 채우는 것이 과연 맞을까?&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;342&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EBpw8/btq9gQIhF6Q/4hzFDYadhgGNtUCEX64Ee1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EBpw8/btq9gQIhF6Q/4hzFDYadhgGNtUCEX64Ee1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EBpw8/btq9gQIhF6Q/4hzFDYadhgGNtUCEX64Ee1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEBpw8%2Fbtq9gQIhF6Q%2F4hzFDYadhgGNtUCEX64Ee1%2Fimg.png&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;342&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;해당 테이블에 값을 저장하는 기준&lt;/b&gt;이 무엇이었는가? 답은 &lt;b&gt;N번째 물건까지 고려할 때, 해당 위치에서 가질 수 있는 최대 가치를 해당 위치에 저장&lt;/b&gt;해두는 것이었다. 그렇다면 &lt;b&gt;해당 위치에는 2번째 물건까지 고려했을때, 무게 3에서의 최대 가치가 저장&lt;/b&gt;되어 있어야 하는데,&lt;b&gt; 그 값은 0이 아닌 1번째 물건을 넣어서 얻은 6임을 알 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;331&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dV25BW/btq9kPWjv9W/WEIWabYsbqGPfWFmetrviK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dV25BW/btq9kPWjv9W/WEIWabYsbqGPfWFmetrviK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dV25BW/btq9kPWjv9W/WEIWabYsbqGPfWFmetrviK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdV25BW%2Fbtq9kPWjv9W%2FWEIWabYsbqGPfWFmetrviK%2Fimg.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;331&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, 기존에 사용하던 물건을 넣을 수 있으면 가치를 넣고, 넣을 수 없으면 가치를 0으로 두는 규칙은 활용할 수 없다는 것을 알 수 있다. 따라서 다른 규칙을 생각해보아야 한다.&amp;nbsp;&lt;b&gt;우선 여기서는, 해당 위치에 물건을 넣을 수 없다면, 이전에 구한 해당 무게에서의 최대 가치를 그대로 가져오면 된다는 것을 파악&lt;/b&gt;하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;345&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m77Hp/btq9gYzUyY5/WFkxkGBzKuGd5jrrNJwSX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m77Hp/btq9gYzUyY5/WFkxkGBzKuGd5jrrNJwSX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m77Hp/btq9gYzUyY5/WFkxkGBzKuGd5jrrNJwSX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm77Hp%2Fbtq9gYzUyY5%2FWFkxkGBzKuGd5jrrNJwSX1%2Fimg.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;345&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-&amp;gt;다음으로, 무게가 4인&lt;/b&gt; &lt;b&gt;경우&lt;/b&gt;역시 중요하다. 이번에는 무게가 3인 경우와 달리&amp;nbsp;&lt;b&gt;2번째 물건을 넣을 수 있다. &lt;/b&gt;즉, 이 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에는 &lt;b&gt;현재 물건의 가치와 이전 물건까지 저장했던 해당 무게에서의 가치를 비교하여 더 큰 값을 저장&lt;/b&gt;하면 된다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;348&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NLh3d/btq9gXudLvF/GegJAq8gJCUnC8SUXMW0E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NLh3d/btq9gXudLvF/GegJAq8gJCUnC8SUXMW0E1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NLh3d/btq9gXudLvF/GegJAq8gJCUnC8SUXMW0E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNLh3d%2Fbtq9gXudLvF%2FGegJAq8gJCUnC8SUXMW0E1%2Fimg.png&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;348&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;마찬가지 방식으로 하면 무게 6까지 같은 방식으로 비교하며 값을 채워나갈 수 있음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;334&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZyHwP/btq9hzfA310/glxn0xVyeeuWxOsCo68lSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZyHwP/btq9hzfA310/glxn0xVyeeuWxOsCo68lSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZyHwP/btq9hzfA310/glxn0xVyeeuWxOsCo68lSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZyHwP%2Fbtq9hzfA310%2Fglxn0xVyeeuWxOsCo68lSk%2Fimg.png&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;334&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-&amp;gt;자, 이제 무게가 7인 경우가 관건&lt;/b&gt;이다. 앞선 방식을 활용한다면 해당 위치에는 8이라는 가치가 들어가야 할 것이다. 하지만 우리는 직관적으로 무게가 7인 경우 첫 번째 물건과 두 번째 물건을 모두 넣을 수 있으므로 해당 위치에는 14라는 가치가 들어가야 한다는 것을 알고 있다. 즉, &lt;b&gt;기존에 사용하던 규칙에서 조금 수정이 필요함&lt;/b&gt;을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;동적 계획법은 이전에 구한 최적해를 활용하여 다른 부분 문제의 최적해를 구하는 과정&lt;/b&gt;이라고 하였다. 우리는&amp;nbsp;&lt;b&gt;첫 번째로 한 개의 물건이 존재하는 경우 최적해를 구하는 과정을 살펴보았지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;해당 규칙은 각 부분 문제의 연관성이 없었다.&lt;/u&gt;&lt;/b&gt;&amp;nbsp;&lt;b&gt;두 번째로 설정한 규칙에서는 이전 물건에서 구했던 최적해를 활용하여, 현재 물건의 현재 위치에서의 최적해를 구하는데 참고하였지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;예외가 발생&lt;/u&gt;&lt;/b&gt;하였다. 따라서, 이전 최적해를 어떻게 사용할 지 다시 생각해보아야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;343&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btL3Ts/btq9hzUdH7l/UzPMxFGsbsJ45myr5sie7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btL3Ts/btq9hzUdH7l/UzPMxFGsbsJ45myr5sie7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btL3Ts/btq9hzUdH7l/UzPMxFGsbsJ45myr5sie7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtL3Ts%2Fbtq9hzUdH7l%2FUzPMxFGsbsJ45myr5sie7k%2Fimg.png&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;343&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;현재 무게를 포함 시키지 않는다면 가방에 수용할 수 있는 무게는 3임을 알 수 있다. 그렇다면 &lt;b&gt;무게가 3인 경우의 최적해를 활용해 볼 수 있지 않을까?&lt;/b&gt;라는 물음을 던져볼 수 있을 것이다. 즉, 우리가 비교할 것은&amp;nbsp;&lt;b&gt;바로 자신의 값이 아닌, 이전 물건까지 고려했던 최적해의 값에 현재 가치를 더한 값과, 이전에 구했던 무게에서의 최적해를 비교하여 최대 값을 구하는 것&lt;/b&gt;이다. 아래 그림을 통해 이해해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;331&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zRGQT/btq9kQnoBcX/sUT3TKwggL4pLXqkPQfjcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zRGQT/btq9kQnoBcX/sUT3TKwggL4pLXqkPQfjcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zRGQT/btq9kQnoBcX/sUT3TKwggL4pLXqkPQfjcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzRGQT%2Fbtq9kQnoBcX%2FsUT3TKwggL4pLXqkPQfjcK%2Fimg.png&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;331&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;결론부터 말하자면 이게 0-1 KnapSack을 푸는 규칙과 저장할 테이블 배열이다. 나머지 부분은 방금 규칙을 바탕으로 채울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 부분 문제의 관계를 생각하며 점화식을 도출한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;위 규칙을 따라 테이블을 완성하면 다음과 같아짐을 확인할 수 있다. 사실 위의 과정에서 규칙성을 파악했다면, 점화식은 그냥 도출되는 것임을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;329&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSL1NP/btq9hPI73cZ/DJAomb6bqpGsls3dScDKz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSL1NP/btq9hPI73cZ/DJAomb6bqpGsls3dScDKz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSL1NP/btq9hPI73cZ/DJAomb6bqpGsls3dScDKz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSL1NP%2Fbtq9hPI73cZ%2FDJAomb6bqpGsls3dScDKz0%2Fimg.png&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;329&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;구체적으로 점화식을 생각해본다면 테이블의 이름을 dp라고하고, 행을 i, 열을 j로 표시한다면 다음과 같을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;187&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDQAaU/btq9kQgC4yU/A5MUiRbbJOQxkk0Rf2dwR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDQAaU/btq9kQgC4yU/A5MUiRbbJOQxkk0Rf2dwR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDQAaU/btq9kQgC4yU/A5MUiRbbJOQxkk0Rf2dwR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDQAaU%2Fbtq9kQgC4yU%2FA5MUiRbbJOQxkk0Rf2dwR0%2Fimg.png&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;187&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;여기에서 W는 현재 고려하는 물건의 무게를 의미하고, V는 현재 고려하는 물건의 가치를 의미한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 점화식을 바탕으로 dp 테이블을 갱신하면서 최종적으로 전체 문제를 해결한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 &lt;b&gt;해당 점화식을 적용하기 위해 기저 조건이 필요&lt;/b&gt;하고 이 때문에&amp;nbsp;&lt;b&gt;2차원 dp테이블을 정의 할 때, 인덱스가 0인 경우 패딩을 주어 기저 조건을 만들어 준다. &lt;/b&gt;이&amp;nbsp;정보들을 바탕으로 테이블을 완성해보면 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;389&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H6lZW/btq9fkRxP7T/GA1DHAKdf3dKqXMrxmaou0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H6lZW/btq9fkRxP7T/GA1DHAKdf3dKqXMrxmaou0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H6lZW/btq9fkRxP7T/GA1DHAKdf3dKqXMrxmaou0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH6lZW%2Fbtq9fkRxP7T%2FGA1DHAKdf3dKqXMrxmaou0%2Fimg.png&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;389&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, &lt;b&gt;물건을 넣지 않은 경우를 생각하여 첫 번째 물건을 담을 때 기저 조건(최적해)을 바탕으로 테이블을 갱신할 수 있도록 설정해주는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;아무튼 초기 dp 테이블의 정의에 따라 dp[4][7]의 값은 4번째 물건까지 고려했을때, 무게 7에서의 최대 가치를 의미한다는 것을 알 수 있다. 결론적으로 이 값이 해당 문제&lt;b&gt;(전체 문제)&lt;/b&gt;의 &lt;b&gt;최종 해&lt;/b&gt;임을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;위 로직을 이해하였다면 구현은 그냥 하면 된다. 로직이 어려운 것이지, 대부분 동적 계획법 코드는 생각만 해내면 점화식을 바탕으로 구현하기 때문에 코드가 깔끔한 장점이 있다!&lt;/p&gt;
&lt;pre id=&quot;code_1625934792847&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class KnapSack_DP1 {
	static int N, K;
	static int[][] items;
	static int max;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		K = sc.nextInt();
		// 물건 당 첫 번째 열에는 물건의 무게를, 두 번째 열에는 물건의 가치를 저장한다.
		// 물건이 없는 경우도 고려하여 인덱스가 0인 경우(패딩)를 추가해준다.
		items = new int[N + 1][2];
		for (int i = 1; i &amp;lt;= N; i++) {
			items[i][0] = sc.nextInt();
			items[i][1] = sc.nextInt();
		}
		max = 0;

		// 먼저 i번째 물건의 j번째 무게에서 가질 수 있는 최댓값을 저장할 수 있는 2차원 dp테이블을 정의한다.
		// 이때, 기저 조건을 위해 dp테이블에 인덱스가 0인 경우(패딩)를 추가해준다.
		int[][] dp = new int[N + 1][K + 1];

		// 1번째 물건부터 N번째 물건까지 모두 고려한다.
		for (int i = 1; i &amp;lt;= N; i++) {
			// 무게가 1인 경우부터 무게가 K인 경우까지 모두 고려한다.
			for (int j = 1; j &amp;lt;= K; j++) {
				// 해당 위치에 물건을 넣을 수 없는 경우.
				if (items[i][0] &amp;gt; j) {
					// i - 1번째 물건까지 고려했을때 무게 j에서의 최대 가치(최적해)를 그대로 가져온다.
					dp[i][j] = dp[i - 1][j];
				}
				// 해당 위치에 물건을 넣을 수 있는 경우.
				else {
					// i - 1번째 물건까지 고려했을때 무게 j에서의 최대 가치(최적해)와,
					// i - 1번째 물건까지 고려했을때 무게 j - items[i][0](현재 무게)의 최대 가치(최적해) + items[i][1](현재 가치) 중에서
					// 더 큰 값을 선택한다!
					dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - items[i][0]] + items[i][1]);
				}
			}
		}
		
		// dp[N][K]를 출력한다(dp테이블의 정의에 따르면 N가지 물건을 모두 고려했을때 K무게에서의 최대 가치를 출력하는 것!).
		System.out.println(dp[N][K]);
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이렇게&amp;nbsp;&lt;b&gt;상황에 따라서 dp테이블을 2차원으로 정의해주어야 할 수도 있다!&lt;/b&gt; 또, 구현하는 과정에서 이렇게 규칙성을 찾고 테이블의 종류를 고려한다는 것이 만만치 않은 일임을 몸소 체감할 수 있었을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*동적 계획법을 활용한 풀이(1차원 dp 테이블 사용)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;앞의 방식으로도 머리가 아프겠지만, 조금 더 나아가서&amp;nbsp;&lt;b&gt;dp 테이블을 1차원으로 줄여볼 수는 없을까?&lt;/b&gt;라는 물음을 바탕으로 코드를 구현해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;1. 테이블을 갱신하는 과정에서 테이블에서 활용되지 않는 정보는 무엇인가?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;이전 테이블을 다시 참고해본다면, 해당 테이블에서&amp;nbsp;&lt;b&gt;바로 이전 행(i - 1)을 제외한 그 이전 행들의 정보(1 ~ i - 2)들은 활용되지 않음&lt;/b&gt;을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;376&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZw51m/btq9gAe2XbY/VxgW2eG8eeSBwKo0S2Bzck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZw51m/btq9gAe2XbY/VxgW2eG8eeSBwKo0S2Bzck/img.png&quot; data-alt=&quot;단계를 진행할 때 마다, 바로 이전 행만을 참고하고 있음을 알 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZw51m/btq9gAe2XbY/VxgW2eG8eeSBwKo0S2Bzck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZw51m%2Fbtq9gAe2XbY%2FVxgW2eG8eeSBwKo0S2Bzck%2Fimg.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;376&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;단계를 진행할 때 마다, 바로 이전 행만을 참고하고 있음을 알 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;2. 그렇다면 이전 행들을 잘 기억해둔다면, 굳이 2차원 테이블을 만들지 않아도 되지 않을까?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;해당 가정을 기반으로 &lt;b&gt;1차원 dp 테이블을 만들고&lt;/b&gt;&amp;nbsp;&lt;b&gt;이전 행들을 단순히 기억하면서 다음 행을 갱신&lt;/b&gt;해보자. 우선 이 문제를 고려하기 위해서는 물건을 넣어보는 순서를 조금 바꿔주어야 한다. 위의 예시에서 첫 번째 물건과 두 번째 물건을 넣는 순서를 바꿔서 생각해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;우선 첫 번째 물건을 넣는 경우이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;286&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xBGHX/btq9jwbtqRH/4FWUTDkSgzDmrzePFnv7Bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xBGHX/btq9jwbtqRH/4FWUTDkSgzDmrzePFnv7Bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xBGHX/btq9jwbtqRH/4FWUTDkSgzDmrzePFnv7Bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxBGHX%2Fbtq9jwbtqRH%2F4FWUTDkSgzDmrzePFnv7Bk%2Fimg.png&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;286&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&amp;nbsp;애초에 2차원 배열이었다면,&amp;nbsp;&lt;b&gt;빨간색 화살표와 같이 단순히 그 값을 참고하면서 현재 값을 갱신&lt;/b&gt;하였을 것이다. 하지만&amp;nbsp;&lt;b&gt;현재는 dp 테이블이 1차원 배열이기 때문에, 파란색 화살표와 같이&amp;nbsp;&lt;u&gt;실시간으로 그 값이 갱신될 때 마다 갱신된 값을 참고하면서 값이 변할 것&lt;/u&gt;&lt;/b&gt;이다. 일단, 이 단계에서는 딱히 문제가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;그럼 두 번째 물건을 넣는 경우를 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;279&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVYKGd/btq9fl3Zej8/NlkCU6RXwSBR42Grx7fkK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVYKGd/btq9fl3Zej8/NlkCU6RXwSBR42Grx7fkK1/img.png&quot; data-alt=&quot;&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVYKGd/btq9fl3Zej8/NlkCU6RXwSBR42Grx7fkK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVYKGd%2Fbtq9fl3Zej8%2FNlkCU6RXwSBR42Grx7fkK1%2Fimg.png&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;279&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지로 2차원 배열이었따면, 빨간색 화살표와 같이 그 값을 참고하면서 현재 값을 갱신하였을 것이다. 하지만 현재는 dp 테이블이 1차원 배열이기 때문에, 파란색 화살표와 같이 실시간으로 갱신된 값을 참고하며 그 값이 갱신되는데, 이때&amp;nbsp;&lt;b&gt;2차원 배열일 때 이전 배열의 인덱스 3에서의 값&lt;/b&gt;과&amp;nbsp;&lt;b&gt;1차원 배열일 때 인덱스 3의 값&lt;/b&gt;이 &lt;u&gt;&lt;b&gt;다르다는 것&lt;/b&gt;&lt;/u&gt;을 확인할 수 있다. 이것이 &lt;b&gt;다르다는 것의 의미&lt;/b&gt;는&amp;nbsp;&lt;b&gt;참고하는 값이 예기치 못한 이유로 변화되었다는 것&lt;/b&gt;을 의미하고, 이것은 &lt;b&gt;해당 위치가 이전에 우리가 정의했던 dp 테이블의 정의(해당 위치에서 갖는 최대 가치,&amp;nbsp; 최적해)를 따른다는 것을 보장할 수 없다&lt;/b&gt;는 것을 의미한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;3. 이전 행들을 잘 기억하면... 되지 않을까..?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;일단 일반적인 방식으로 &lt;b&gt;무작정 1차원 배열을 갱신하며 기억하면 안된다는 것을 확인&lt;/b&gt;하였다. 그렇다면 어떻게 1차원 배열에 그 값을 잘 저장하면 이 문제를 해결할 수 있지 않을까? 결론부터 말하자면&amp;nbsp;&lt;u&gt;&lt;b&gt;값을 뒤에서 부터 갱신하는 방법&lt;/b&gt;&lt;/u&gt;을 사용하면 문제를 해결할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;앞선 과정을 똑같이 진행해보자. 우선, 첫 번째 물건을 넣는 경우를 생각해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;268&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WTEUM/btq9iBdfiqc/uJVKA8khiZYZo8MGBRCII0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WTEUM/btq9iBdfiqc/uJVKA8khiZYZo8MGBRCII0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WTEUM/btq9iBdfiqc/uJVKA8khiZYZo8MGBRCII0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWTEUM%2Fbtq9iBdfiqc%2FuJVKA8khiZYZo8MGBRCII0%2Fimg.png&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;268&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다음과 같이 &lt;b&gt;무게를 7부터 시작하여, 앞 배열을 참고해도 결과는 달라지지 않는다는 것&lt;/b&gt;을 확인할 수 있다. 어차피 이전 배열은 최적해를 보장하고 있기 때문에, 앞에서 부터 참고하든 뒤에서 부터 참고하든 그 결과는 같다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;똑같이 두 번째 물건을 넣는 경우를 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;288&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GV8hH/btq9flJGnMl/1jYuu2QgN1hDOglYXquZl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GV8hH/btq9flJGnMl/1jYuu2QgN1hDOglYXquZl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GV8hH/btq9flJGnMl/1jYuu2QgN1hDOglYXquZl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGV8hH%2Fbtq9flJGnMl%2F1jYuu2QgN1hDOglYXquZl1%2Fimg.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;288&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해를 돕기 위해 무게 7부터 차근차근 생각해보겠다. 마찬가지로 2차원 배열을 사용하는 방식이었다면, 빨간색 화살표와 같이 값을 참고할 것이고, 1차원 배열을 사용하는 방식이라면 파란색 화살표와 같이 값을 참고할 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;288&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nFxyr/btq9f5fkhvD/fUJAJLZpIU2zwjxqfbiJ60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nFxyr/btq9f5fkhvD/fUJAJLZpIU2zwjxqfbiJ60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nFxyr/btq9f5fkhvD/fUJAJLZpIU2zwjxqfbiJ60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnFxyr%2Fbtq9f5fkhvD%2FfUJAJLZpIU2zwjxqfbiJ60%2Fimg.png&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;288&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지로 &amp;nbsp;2차원 배열을 사용하는 방식이었다면, 빨간색 화살표와 같이 값을 참고할 것이고, 1차원 배열을 사용하는 방식이라면 파란색 화살표와 같이 값을 참고할 것인데, 앞선 방식과는 다르게&amp;nbsp;&lt;b&gt;인덱스가 3인 지점이 아직 갱신이 일어나지 않았으므로, 2차원 배열에서 값을 참고하는 것과 같은 상태로 유지되고 있음&lt;/b&gt;을 알 수 있다. 즉,&amp;nbsp;&lt;b&gt;인덱스 6인 지점에 현재까지의 최대 가치인 8이 적절히 들어가는 것을 확인&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;위 로직을 이해하였다면 역시 구현은 그냥 하면 된다. 아래 코드를 참고해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1625938007760&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class KnapSack_DP2 {
	static int N, K;
	static int[][] items;
	static int max;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		K = sc.nextInt();
		// 물건 당 첫 번째 열에는 물건의 무게를, 두 번째 열에는 물건의 가치를 저장한다.
		// 물건이 없는 경우도 고려하여 인덱스가 0인 경우(패딩)를 추가해준다.
		items = new int[N + 1][2];
		for (int i = 1; i &amp;lt;= N; i++) {
			items[i][0] = sc.nextInt();
			items[i][1] = sc.nextInt();
		}
		max = 0;

		// 먼저 i번째 물건의 j번째 무게에서 가질 수 있는 최댓값을 저장할 수 있는 1차원 dp테이블을 정의한다.
		// 이때, 기저 조건을 위해 dp테이블에 무게가 0인 경우(패딩)를 추가해준다.
		int[] dp = new int[K + 1];

		// 1번째 물건부터 N번째 물건까지 모두 고려한다.
		for (int i = 1; i &amp;lt;= N; i++) {
			// 무게가 K인 경우부터 무게가 items[i][0]인 경우까지 모두 고려한다.
			for (int j = K; j &amp;gt;= items[i][0]; j--) {
				// 해당 위치에 물건을 넣을 수 없는 경우, 1차원 테이블이 딱히 갱신이 되지 않는다.
				// 따라서 2차원 dp 테이블을 사용하는 경우와 달리 분기문이 사라진다.
				
				// 해당 위치에 물건을 넣을 수 있는 경우.
				// i - 1번째 물건까지 고려했을때 무게 j에서의 최대 가치(최적해)와,
				// i - 1번째 물건까지 고려했을때 무게 j - items[i][0](현재 무게)의 최대 가치(최적해) + items[i][1](현재 가치) 중에서
				// 더 큰 값을 선택한다!
				dp[j] = Math.max(dp[j], dp[j - items[i][0]] + items[i][1]);
			}
		}

		// dp[N][K]를 출력한다(dp테이블의 정의에 따르면 N가지 물건을 모두 고려했을때 K무게에서의 최대 가치를 출력하는 것!).
		System.out.println(dp[K]);
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;여기서 주의할 점은 &lt;b&gt;1차원 배열을 이용함으로써 물건을 넣을 수 없는 경우 물건을 그대로 가져오는 코드를 생략할 수 있다는 것&lt;/b&gt;이고, 또한 그로인해&amp;nbsp;&lt;b&gt;물건을 넣고 빼는 조건을 제거하였으므로 물건의 무게는 현재 고려하는 물건의 무게를 넣을 수 있는 부분까지만(j &amp;gt;= items[i][0]) 고려해야 한다는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;당연하겠지만, 1차원 배열을 사용하기 때문에 메모리의 사용이 적다는 것을 확인할 수 있다. 또한 모든 무게를 고려하지 않는 조건 때문인지 시간도 줄었음을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;102&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCDC06/btq9f6ebJcz/sNUSk4Hfl7kXGvwO5YdYyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCDC06/btq9f6ebJcz/sNUSk4Hfl7kXGvwO5YdYyk/img.png&quot; data-alt=&quot;위 : 1차원 배열 사용, 아래 : 2차원 배열 사용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCDC06/btq9f6ebJcz/sNUSk4Hfl7kXGvwO5YdYyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCDC06%2Fbtq9f6ebJcz%2FsNUSk4Hfl7kXGvwO5YdYyk%2Fimg.png&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;102&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위 : 1차원 배열 사용, 아래 : 2차원 배열 사용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이처럼&amp;nbsp;&lt;b&gt;몇 가지 로직을 바탕으로 값을 기억하는 방식을 적절히 조절할 수 있다면, dp 테이블은 다양하게 정의할 수 있음&lt;/b&gt;을 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 여기까지가 &lt;b&gt;다이나믹 프로그래밍의 정석 예제 중 하나인 0-1 배낭 문제&lt;/b&gt;에 대한 설명이다. 어려운게 너무너무너무 당연하기 때문에.. 잘 이해가 안되더라도 주눅들지 말고 끝까지 연습해 보도록 하자. 다음에는 &lt;b&gt;다이나믹 프로그래밍의 또 다른 정석 예제인 LIS와 LCS&lt;/b&gt;에 대해서 포스팅하도록 하겠다.&lt;/p&gt;</description>
      <category>Algorithm/동적 계획법</category>
      <category>0-1 Knapsack Problem</category>
      <category>0-1 배낭 문제</category>
      <category>boj 12865</category>
      <category>Dynamic Programming</category>
      <category>Knapsack Problem</category>
      <category>다이나믹 프로그래밍</category>
      <category>동적 계획법</category>
      <category>배낭 문제</category>
      <category>백준 12865</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/88</guid>
      <comments>https://sskl660.tistory.com/88#entry88comment</comments>
      <pubDate>Sun, 11 Jul 2021 02:32:49 +0900</pubDate>
    </item>
    <item>
      <title>[Java]동적 계획법(Dynamic Programming)</title>
      <link>https://sskl660.tistory.com/87</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;*동적 계획법(Dynamic Programming)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;동적 계획법이란&amp;nbsp;&lt;b&gt;특정 범위까지의 최적해(상위 문제)&lt;/b&gt;를 구하기 위하여&amp;nbsp;&lt;b&gt;다른 범위까지의 최적해(하위 문제)&lt;/b&gt;를 이용하여 &lt;u&gt;&lt;b&gt;효율적으로 해를&lt;/b&gt;&lt;b&gt;&amp;nbsp;구하는&lt;/b&gt;&lt;/u&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;알고리즘 설계 기법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;쉽게 말해,&amp;nbsp;&lt;b&gt;이전에 구한 값&lt;/b&gt;을 기반으로&amp;nbsp;&lt;b&gt;규칙성을 파악&lt;/b&gt;하여&amp;nbsp;&lt;b&gt;다음 값을 구하는 것&lt;/b&gt;이라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;알고리즘 설계 기법(패러다임) &lt;/b&gt;중 하나이다.&amp;nbsp;&lt;u&gt;&lt;b&gt;하위 문제의 최적해를 적절히 사용하여 상위 문제를 해결&lt;/b&gt;&lt;/u&gt;함으로써, 불필요한 계산을 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 어떤 문제를 해결할 때, 기본적인 방법은 &lt;b&gt;모든 경우의 수를 고려하는 것(완전 탐색)&lt;/b&gt;이다. 어떤 문제를 해결할 때, 그 문제에 대한 모든 경우의 수를 고려할 수 있는 설계가 가능하다면, 그 문제는&amp;nbsp;&lt;b&gt;시간과 자원이 매우 많이 들지는 몰라도 언젠가 반드시 정확한 결과를 도출할 것&lt;/b&gt;이다. 다만&amp;nbsp;&lt;b&gt;시공간적 자원의 한계&lt;/b&gt;로 인하여&amp;nbsp;&lt;b&gt;분할 정복, 그리디, 백트래킹 등&lt;/b&gt;과 같은 알고리즘 설계 기법이 등장한 것이고 동적 계획법 역시 그러한 한계를 해결하기 위해 설계된 알고리즘 패러다임인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 동적 계획법(Dynamic Programming)이라는 이름은 딱히 해당 알고리즘의 패러다임을 이해하는데 직관적이지 않은 편이다. 동적 계획법의 고안자인 벨만이 연구소에서 펀딩을 받기 위해서 이름을 최대한 간지나게 지을려다보니 Dynamic이라는 용어를 사용하게 됐다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(참고 : &lt;a href=&quot;https://namu.wiki/w/%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95#toc&quot;&gt;https://namu.wiki/w/%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95#toc&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;*적용 가능한 문제&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;동적 계획법은&amp;nbsp;&lt;b&gt;아래 두 조건을 만족&lt;/b&gt;하는 경우 해당 패러다임을 적용하여 문제를 해결하는데 유용하다고 알려져있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1)&amp;nbsp;최적 부분 문제 구조(Optimal Substructure)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;쉽게 말해 앞서 정의한 바와 같이 &lt;b&gt;이전에 구한 최적해(부분 문제)를 바탕으로 다음 문제의 최적해(전체 문제)를 구할 수 있는 구조&lt;/b&gt;여야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다시 말해 &lt;b&gt;부분 문제가 전체 문제의 최적해라는 보장&lt;/b&gt;이 있는 구조를&amp;nbsp;&lt;b&gt;최적 부분 문제 구조&lt;/b&gt;라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 최적 부분 문제 구조를 갖는 경우&lt;/b&gt; : 최적 부분 문제 구조를 갖는 경우는 대표적으로 어떤 경유지를 거쳐서 목적지로 가는 문제가 있다. 아래 그림을 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;269&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ouWRu/btq9gATn1zi/w5H6gR0rKUKkquoZQwukXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ouWRu/btq9gATn1zi/w5H6gR0rKUKkquoZQwukXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ouWRu/btq9gATn1zi/w5H6gR0rKUKkquoZQwukXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FouWRu%2Fbtq9gATn1zi%2Fw5H6gR0rKUKkquoZQwukXk%2Fimg.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;269&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그림에서 서울에서 부산으로 가는 최단 경로를 구하는 문제&lt;b&gt;(전체 문제)&lt;/b&gt;를 생각해보자. 그런데 그림에서 서울에서 부산으로 가는 최단 경로는 서울에서 대전으로 가는 최단 경로&lt;b&gt;(부분 문제)&lt;/b&gt;와 서울에서 부산으로가는 최단 경로&lt;b&gt;(부분 문제이자 전체 문제)&lt;/b&gt;로 나누어 생각할 수 있다. 또한, 서울에서 대전으로가는 최단 경로 200km&lt;b&gt;(최적해)&lt;/b&gt;는 이후 대전에서 부산으로가는 최단 경로 150km와(여기에서 150km는 최적해를 의미하지 않는다. 부분 문제의 해라고 보기 힘들기 때문이다)&amp;nbsp;적절히 조합하여&amp;nbsp;&lt;b&gt;전체 문제를 해결 가능함&lt;/b&gt;을 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 최적 부분 문제 구조를 갖지 않는 경우&amp;nbsp;&lt;/b&gt;: 위 그림에서 조건을 몇가지 살짝 바꿔보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;245&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sx9i3/btq9gzAcXJf/TQOamX6X5y60iZKAScbf00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sx9i3/btq9gzAcXJf/TQOamX6X5y60iZKAScbf00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sx9i3/btq9gzAcXJf/TQOamX6X5y60iZKAScbf00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSx9i3%2Fbtq9gzAcXJf%2FTQOamX6X5y60iZKAScbf00%2Fimg.png&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;245&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그림에서 서울에서 부산으로 가는 최소 비용을 구하는 문제&lt;b&gt;(전체 문제)&lt;/b&gt;를 생각해보자. 앞 선 문제와 비슷하지만, 여기에는&amp;nbsp;'서울에서 대전을 경유해서 바로 부산으로 가는 경우의 비용은 33000원'이라는 조건이 하나 더 추가 되었다.&amp;nbsp;&lt;b&gt;이 조건으로 인해, 앞서 나누었던 부분 문제(서울에서 대전)는 전체 문제를 해결하는 최적해라는 보장이 사라져 버린다!&lt;/b&gt; 즉, &lt;u&gt;&lt;b&gt;동적 계획법을 잘 활용하려면 부분 문제를 어떻게 설정해야지 최적 부분 문제 구조를 갖는지 잘 파악해야 함&lt;/b&gt;&lt;/u&gt;을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 중복 부분 문제 구조(Overlapping Subproblems)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;말 그대로&amp;nbsp;&lt;b&gt;부분 문제들이 반복되는 경향이 존재한다는 것을 의미&lt;/b&gt;한다. 쉽게 말해서&amp;nbsp;&lt;u&gt;&lt;b&gt;부분 문제를 분할해가는 과정에서, 그 각 상위 문제와 하위 문제의 관계가 반복되는 경향이 존재&lt;/b&gt;&lt;/u&gt;한다는 것을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;위의 예시를 바탕으로 아래 그림을 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;394&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JKQsy/btq9gSeUzdy/hQBXldDDpeec4txIlkeIE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JKQsy/btq9gSeUzdy/hQBXldDDpeec4txIlkeIE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JKQsy/btq9gSeUzdy/hQBXldDDpeec4txIlkeIE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJKQsy%2Fbtq9gSeUzdy%2FhQBXldDDpeec4txIlkeIE0%2Fimg.png&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;394&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지로 서울에서 부산으로 가는 최단 경로&lt;b&gt;(전체 문제)&lt;/b&gt;를 해결한다고 생각해보자. 그래서 우선&amp;nbsp;&lt;b&gt;서울에서 대전으로 가는 최단경로(부분 문제)는 무엇일까?&lt;/b&gt;라는 질문을 출발하여&amp;nbsp;&lt;b&gt;서울에서 경기로 가는 최단경로(최하위 부분 문제)&lt;/b&gt;&lt;b&gt;는 무엇일까?&lt;/b&gt;라는 질문까지 내려갔다. 이 구조에서&amp;nbsp;&lt;b&gt;부분 문제의 구조가 '각 위치 까지의 최단 경로는 무엇인가?'로 반복&lt;/b&gt;된다는 것을 알 수 있다. 그냥 쉽게 말해 이런 구조를 갖는 것이 중복 부분 문제 구조를 갖는다라고 이해해두면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 결국 이 그림이 동적 계획법의 사고 진행 과정이 어떤 방식으로 진행되는지 단편적으로 이해하는데 도움이 될 수 있을 것이다. &lt;b&gt;전체 문제를 부분 문제&lt;/b&gt;로 나누고, 그 &lt;b&gt;부분 문제를 작은 문제부터 해결&lt;/b&gt;(서울에서 경기, 서울에서 대전, 서울에서 부산)해 나아가고, &lt;b&gt;각 단계에서 구한 해를 다음 문제에서 재사용&lt;/b&gt;함으로써 &lt;b&gt;전체 문제를 해결&lt;/b&gt;하는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;*vs 분할 정복 패러다임&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;동적 계획법과 분할 정복 패러다임 모두 &lt;b&gt;전체 문제를 부분 문제로 나누어 생각한다는 점&lt;/b&gt;에서 그 차이점을 느끼기 어려울 수 있다. 이를 구분하기 가장 좋은 것은 &lt;b&gt;동적 계획법은 부분 문제 사이에 연관성이 존재&lt;/b&gt;하고,&amp;nbsp;&lt;b&gt;분할 정복은 부분 문제 사이에 연관성이 존재하지 않는다&lt;/b&gt;는 점을 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;예를 들어 병합 정렬(Merge Sort)을 생각해보자. 병합 정렬의 경우 모든 배열을 각각 분할&lt;b&gt;(부분 문제)&lt;/b&gt;하고, 최종적으로 분할된 배열부터 각 배열을 합치며 정렬하는 과정을 반복&lt;b&gt;(단순히 부분 문제를 큰 문제로 결합하며 해결)&lt;/b&gt;하는 것이다. 즉,&amp;nbsp;&lt;b&gt;부분 문제 사이에 딱히 별 연관성이 없음&lt;/b&gt;을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;*구현 방식&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;동적 계획법은 특성상&amp;nbsp;&lt;b&gt;Top-down 방식&lt;/b&gt;과 &lt;b&gt;Bottom-up 방식&lt;/b&gt;으로 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;사실&amp;nbsp;&lt;b&gt;어떤 문제를 푸느냐&lt;/b&gt;에 따라서&amp;nbsp;Top-down 방식으로 구현하든 Bottom-up 방식으로 구현하든 &lt;b&gt;각 방식이 압도적으로 우위를 가지는 장단점은 명확하지 않다&lt;/b&gt;고 한다. 따라서, 장단점의 경우에는 보통 이러하다더라~ 정도로 이해하면 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) Top-down 구현 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;전체 문제&lt;/b&gt;부터 시작하여,&amp;nbsp;&lt;b&gt;가장 작은 문제(기저 문제)&lt;/b&gt;까지&amp;nbsp;&lt;b&gt;호출&lt;/b&gt;한 뒤,&amp;nbsp;&lt;b&gt;작은 문제에서 해결한 값을 저장 및 기억(Memoization)&lt;/b&gt;하면서 해당 결과 값을&amp;nbsp;&lt;b&gt;재활용&lt;/b&gt;하면서 문제를 해결하는 구현 방식을 말한다. 이러한 문제 해결의 특성상&amp;nbsp;&lt;b&gt;재귀 호출을 사용&lt;/b&gt;하는 특징이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;재귀 호출을 사용하기 때문에&amp;nbsp;&lt;b&gt;Stack Overflow 등의 문제가 발생&lt;/b&gt;할 수 있지만,&amp;nbsp;&lt;b&gt;전체 문제부터 시작하여 작은 문제로 내려가는 직관적인 구조&lt;/b&gt;이기 때문에&amp;nbsp;&lt;b&gt;이해하기 쉬운 장점&lt;/b&gt;이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) Bottom-up 구현 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;가장 작은 문제(기저 문제)&lt;/b&gt;부터 시작하여,&amp;nbsp;&lt;b&gt;작은 문제를 해결하여 그 값을 저장(Tabulation)&lt;/b&gt;하고, 이 값들을 기반으로&amp;nbsp;&lt;b&gt;다음 문제를 순차적으로 해결하며 전체 문제까지 해결&lt;/b&gt;하는 구현 방식을 말한다. 이러한 문제 해결의 특성상&amp;nbsp;&lt;b&gt;반복문을 사용&lt;/b&gt;하는 특징이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;반복문을 사용하기 때문에&amp;nbsp;&lt;b&gt;Top-down 방식에 비하여 효율성이 좋다&lt;/b&gt;고 알려져 있지만, 앞서 말한대로 문제 및 오버헤드, 설계에 따라서 Case by Case라고 한다. 또한&amp;nbsp;&lt;b&gt;직관적인 구조가 아니기 때문에 구현이 어려울 수 있는 단점&lt;/b&gt;이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ Tabulation? : Tabulation의 사전적 정의는 '도표 작성'이다. 문제 해결 방식이 표를 채워나가는 것과 유사하다고 하여 붙여진 이름이다. 따라서 Bottom-up방식을 사용하는 경우는 Memoization이라고 부르지 않고 Tabulation을 활용하여 값을 재활용한다고 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;*피보나치 수열과 다이나믹 프로그래밍&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다이나믹 프로그래밍을 설명할 때, 가장 기본적이고 자주 사용되는 문제는&amp;nbsp;&lt;b&gt;피보나치 수열의 값을 구하는 문제&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 피보나치 수열이란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;첫째 항과 둘째 항이 1의 값을 가지고, 그 뒤의 모든 항은 바로 앞 두 항의 합으로 구성된 수열을 말한다. 예를 들면, 다음과 피보나치 수열은 다음과 같이 진행된다. 1, 1, 2, 3, 5, 8, 13, 21...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;즉, 피보나치 수열을 Fn이라고 한다면, 피보나치 수열은 다음과 같이 수학적으로 정의할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;71&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d6z5a1/btq9jvKjuFd/St63lOH2izftq9Wgij1kC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d6z5a1/btq9jvKjuFd/St63lOH2izftq9Wgij1kC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d6z5a1/btq9jvKjuFd/St63lOH2izftq9Wgij1kC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd6z5a1%2Fbtq9jvKjuFd%2FSt63lOH2izftq9Wgij1kC1%2Fimg.png&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;71&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 피보나치 수열의 일반항의 값을 구하는 프로그램을 작성해보자(단순 재귀 호출).&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;재귀를 사용하면, 피보나치 수열을 구하는 일반적인 프로그램을 작성하는 것은 쉽다. 코드로 작성하면 아래와 같을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1625920737025&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class FibonacciNumber {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		
		// n번째 피보나치 수를 구하고 출력하라.
		System.out.println(Fibonacci(n));
		sc.close();
	}

	private static long Fibonacci(int n) {
		// 기저 조건(피보나치 수열의 초항).
		if(n == 1 || n == 2) {
			return 1;
		}
		// 점화식.
		return Fibonacci(n - 1) + Fibonacci(n - 2);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;하지만 해당 프로그램은 효율적으로 동작할까? 당장 100만 입력해봐도 결과를 도출하는데 매우 오랜 시간이 걸릴 것임을 알 수 있다. 그 이유는 아래 호출 구조를 보면서 파악해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;852&quot; data-origin-height=&quot;518&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KS1dF/btq9gXgzebh/0epvX0kyjbeCbD2y3Orbp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KS1dF/btq9gXgzebh/0epvX0kyjbeCbD2y3Orbp1/img.png&quot; data-alt=&quot;일반적인 재귀를 사용한 경우 재귀 호출 구조도와 반복되는 부분 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KS1dF/btq9gXgzebh/0epvX0kyjbeCbD2y3Orbp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKS1dF%2Fbtq9gXgzebh%2F0epvX0kyjbeCbD2y3Orbp1%2Fimg.png&quot; data-origin-width=&quot;852&quot; data-origin-height=&quot;518&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;일반적인 재귀를 사용한 경우 재귀 호출 구조도와 반복되는 부분 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그림과 같이 호출이 반복될 때 마다, 이미 구했던 값임에도 불구하고 다음 재귀에서 반복해서 재귀 호출이 발생하는 것을 확인할 수 있다. 이 경우&amp;nbsp;&lt;b&gt;시간 복잡도는 O(2^N)&lt;/b&gt;이라고 한다. 즉, 연산의 횟수가 N이 늘어남에 따라 지수배 만큼 늘어나기 때문에 효율적인 구현이라고 볼 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) Top-down 구현 방식으로 피보나치 수열의 일반항의 값을 구해보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이제 앞에서 학습한 다이나믹 프로그래밍의 구현 방식 중 하나인 Top-down 구현 방식을 활용하여 코드를 작성해보자.&amp;nbsp;&lt;b&gt;일반적으로 재귀를 사용하는 구조는 같지만, 부분 문제에서 구한 값을 기억(Memoization)하면서 다음 재귀에서 재활용하는 과정을 추가&lt;/b&gt;해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1625922116561&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class FibonacciNumber_TopDown {
	// Memoization을 적용할 배열.
	static long[] dp;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		dp = new long[n + 1];

		// n번째 피보나치 수를 구하고 출력하라.
		System.out.println(Fibonacci(n));
		sc.close();
	}

	private static long Fibonacci(int n) {
		// 기저 조건(피보나치 수열의 초항).
		if (n == 1 || n == 2) {
			return dp[n] = 1;
		}
		// 만일, 저장된 값이 존재하는 경우 기억된 값을 바로 넘겨준다.
		if (dp[n] != 0) {
			return dp[n];
		}
		// 그렇지 않은 경우, 기저 조건까지 내려가서 구해진 값을 저장하면서 재귀를 전이한다.
		else {
			return dp[n] = Fibonacci(n - 1) + Fibonacci(n - 2);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이렇게 부분 문제에서 해결한 값을 저장(Memoization)하면서 문제를 해결하는 경우&amp;nbsp;&lt;b&gt;불필요한 계산 과정을 줄여주기 때문에 엄청난 속도 향상&lt;/b&gt;&lt;b&gt;을 보임&lt;/b&gt;을 알 수 있다! 이 경우&amp;nbsp;&lt;b&gt;시간 복잡도는 O(N)&lt;/b&gt;을 갖는다고 한다.&amp;nbsp;아래 호출 구조를 참고해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;627&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IBl77/btq9fEvjitV/FfdoyqxPkImUG5QEZI7fR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IBl77/btq9fEvjitV/FfdoyqxPkImUG5QEZI7fR0/img.png&quot; data-alt=&quot;값을 그때마다 기억하고, 적절하게 호출하면서 불 필요한 계산 과정을 줄일 수 있다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IBl77/btq9fEvjitV/FfdoyqxPkImUG5QEZI7fR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIBl77%2Fbtq9fEvjitV%2FFfdoyqxPkImUG5QEZI7fR0%2Fimg.png&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;627&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;값을 그때마다 기억하고, 적절하게 호출하면서 불 필요한 계산 과정을 줄일 수 있다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(4) Top-down 구현 방식으로 피보나치 수열의 일반항의 값을 구해보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;그럼 이번에는 앞에서 학습한 다이나믹 프로그래밍의 구현 방식 중 다른 하나인 Bottom-down 구현 방식을 활용하여 코드를 작성해보자. Bottom-up 구현 방식은 &lt;b&gt;가장 작은 문제(기저 문제)&lt;/b&gt;부터 시작하여,&amp;nbsp;&lt;b&gt;작은 문제를 해결하여 그 값을 저장(Tabulation)&lt;/b&gt;하고, 이 값들을 기반으로&amp;nbsp;&lt;b&gt;다음 문제를 순차적으로 해결하며 전체 문제까지 해결&lt;/b&gt;하는 구현 방식이라고 하였다. 즉, 기저 조건(1항, 2항의 값은 1)을 기반으로 다음 값을 구하면서 테이블을 채워가는 방식으로 반복문을 구현하면 된다. 아래 코드를 참고하자.&lt;/p&gt;
&lt;pre id=&quot;code_1625923161748&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class FibonacciNumber_BottomUp {
	// Tabulation을 적용할 배열.
	static long[] dp;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		dp = new long[n + 1];
		// 기저 조건을 바탕으로 초항을 먼저 초기화 해둔다.
		dp[1] = 1;
		dp[2] = 1;

		// n번째 피보나치 수를 구하고 출력하라.
		System.out.println(Fibonacci(n));
		sc.close();
	}

	private static long Fibonacci(int n) {
		// 기저 조건을 기반으로 테이블을 채워나간다(Tabulation).
		for(int i = 3; i &amp;lt;= n; i++) {
			// 점화식을 이용하여 쉽게 구할 수 있다.
			dp[i] = dp[i - 1] + dp[i - 2];
		}
		
		return dp[n];
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;마찬가지로 이렇게 부분 문제에서 해결한 값을 저장(Tabulation)하면서 문제를 해결하는 경우 &lt;b&gt;불필요한 계산 과정을 줄여주기 때문에 엄청난 속도 향상&lt;/b&gt;&lt;b&gt;을 보임&lt;/b&gt;을 알 수 있다! 이 경우 역시&amp;nbsp;&lt;b&gt;시간 복잡도는 O(N)&lt;/b&gt;을 갖는다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 사실&amp;nbsp;&lt;b&gt;Tabulation을 사용하지 않더라도 단순 반복문을 이용하여 피보나치수의 일반항의 값을 구할 수 있음&lt;/b&gt;을 알 수 있을 것이다. 즉, 굳이 값을 저장하지 않더라도 반복문을 적용한다면 앞의 두 값만 기억하고 있다면 굳이 메모리 공간을 낭비하지 않더라도 결과를 계산할 수 있다는 말이다. 다만 전체적인 과정의 값을 모두 기억해가며 풀어가는 방식이 동적 계획법의 정석이기 때문에 이렇게 소개한 것 뿐이고, 이 경우와 마찬가지로 &lt;u&gt;&lt;b&gt;데이터를 어떤 방식으로 기억할 지(단순히 변수에 담을지, n차원 배열에 담을지, 트리 자료구조에 담을지...)는 문제에 따르게 다르게 생각하면 된다.&lt;/b&gt;&lt;/u&gt; 실제로 데이터를 어떤 방식으로 저장할지를 생각하는 것이 동적 계획법의 출발이고, 알고리즘 실력을 가르는 중요한 요소임을 많은 문제 풀이를 하며 이해할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ Top-down 방식과 달리 기저 조건부터 출발해 전체 문제를 해결하는 것을 확인할 수 있다. 이를 바탕으로 Top-down방식과 Bottom-up방식의 차이점을 이해할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;*동적 계획법 문제 접근 방식&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;해당 글을 잘 이해하였다면 동적 계획법은 이러하다..는 대략적인 느낌은 이해했을 것이라 생각한다. 다만, 실전 DP문제를 마주하면 나의 알고리즘 실력에 자괴감이 들때가 많을 것이다.&amp;nbsp;&lt;b&gt;그 만큼 동적 계획법은 난이도가 있는 알고리즘 패러다임&lt;/b&gt;이고,&amp;nbsp;&lt;b&gt;당연한 것&lt;/b&gt;이기 때문에... 꾸준히 연습하는 것 밖에 답이 없어보인다...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;다음은 일반적인 동적 계획법 문제 접근 방식이다. 물론 접근 방식을 알고 있다고해도 쉽게 적용하긴 힘들 것이다...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(1) 문제를 특정한 부분문제로 나누고, 해당 부분 문제의 최적해들을 저장할 dp 테이블을 정의해본다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;이를 테면 앞의 서울에서 부산까지 가는 최단 경로를 구하는 예시를 기준으로 생각해보면, 'n번째 지역까지 가는데 필요한 최단 경로'라는 부분 문제를 생각해볼 수 있고, 이를 1차원 배열에 저장하면 되겠다는 생각을 해볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-&amp;gt;쉽게 말해 부분 문제를 무엇으로 둘거고, 그걸 어떻게 저장해볼까?를 생각하는 단계이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(2) 부분 문제의 관계를 생각하며 점화식을 도출한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이를 테면 앞의 서울에서 부산까지 가는 최단 경로를 구하는 예시를 기준으로 생각해보면 'dp[n] = dp[n - 1] + (n - 1지역에서 n으로 가는 최단 거리)' 라는 점화식을 세울 수 있음을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;쉽게 말해 해당 부분 문제의 규칙성을 파악해보고, 점화식과 기저 조건을 정의하는 단계이다. 물론... 규칙성을 찾는것이 말 처럼 쉽지는 않을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 점화식을 바탕으로 dp 테이블을 갱신하면서 최종적으로 전체 문제를 해결한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이를 테면 앞의 서울에서 부산까지 가는 최단 경로를 구하는 예시를 기준으로 생각해보면 결국 dp[n]의 값이 최종 답이 되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;사실 이 단계는 확인하는 단계이다.&amp;nbsp;&lt;b&gt;데이터를 저장할 dp테이블 설계&lt;/b&gt;와&amp;nbsp;&lt;b&gt;각 데이터간의 연관성을 바탕으로 점화식을 잘 정의&lt;/b&gt;하였다면 올바른 답이 도출되는 것을 확인할 수 있을 것이다.&lt;/p&gt;</description>
      <category>Algorithm/동적 계획법</category>
      <category>bottom-up</category>
      <category>Dynamic Programming</category>
      <category>memoization</category>
      <category>tabulation</category>
      <category>Top-down</category>
      <category>동적 계획법</category>
      <category>메모이제이션</category>
      <category>중복 부분문제 구조</category>
      <category>최적 부분문제 구조</category>
      <category>피보나치 수열</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/87</guid>
      <comments>https://sskl660.tistory.com/87#entry87comment</comments>
      <pubDate>Sat, 10 Jul 2021 22:37:02 +0900</pubDate>
    </item>
    <item>
      <title>[Java]삽입 정렬(Insertion Sort)</title>
      <link>https://sskl660.tistory.com/81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*삽입 정렬(Insertion Sort)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;삽입 정렬이란&amp;nbsp;&lt;b&gt;2번째 원소부터 n번째 원소까지 차례로 해당 원소가 위치할 인덱스에 원소를 삽입하는 방식&lt;/b&gt;을 사용하는 정렬 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;2번째 원소부터 n번째 원소부터 차례로 각 원소가 맞는 위치에 '삽입'하는 방식을 사용하며 배열을 정렬하기 때문에 삽입 정렬이라고 이름지었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※사람에게 어떤 대상을 정렬하라고 한다면 무의식적으로 수행하는 정렬 방식이라고 한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*삽입 정렬의 이해&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;어떤 대상을 '오름차순'으로 정렬할 때 삽입 정렬은&amp;nbsp;&lt;b&gt;2번째 원소부터 앞의 원소와 비교하는 과정을 통해 적절한 위치에 삽입&lt;/b&gt;하고,&amp;nbsp;&lt;b&gt;n번째 원소까지 이 방식을 반복&lt;/b&gt;함으로써 정렬을 진행할 수 있다. 예를 들어 [6, 2, 3, 4, 1]이라는 배열을 삽입 정렬을 이용하여 오름차순 정렬을 해보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edGvSO/btq75tggAPo/MoC82lUSuG870jFlZyEOu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edGvSO/btq75tggAPo/MoC82lUSuG870jFlZyEOu1/img.png&quot; data-alt=&quot;초기 배열 상태. Array[CurIndex]는 임시 변수에 저장하여 값을 기억해둔다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edGvSO/btq75tggAPo/MoC82lUSuG870jFlZyEOu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedGvSO%2Fbtq75tggAPo%2FMoC82lUSuG870jFlZyEOu1%2Fimg.png&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초기 배열 상태. Array[CurIndex]는 임시 변수에 저장하여 값을 기억해둔다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;현재 선택된 원소의 앞 원소와 비교를 하며&amp;nbsp;현재 원소의 적절한 위치를 찾는 방식&lt;/b&gt;이기 때문에, 우선 Array[0]와 Array[CurIndex]를 비교를 하게 된다. 이때, &lt;b&gt;Array[0] &amp;gt; Array[CurIndex]이므로 0번째 인덱스의 원소를 뒤로 미뤄버린다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;204&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzd5ow/btq7ZPyxUQ6/7dWwXx9BdqBmysswH9LIik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzd5ow/btq7ZPyxUQ6/7dWwXx9BdqBmysswH9LIik/img.png&quot; data-alt=&quot;현재 대상 원소인 Array[CurIndex]의 값보다 Array[0]의 값이 크기 때문에, 해당 값을 다음 인덱스인 1로 미뤄버린다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzd5ow/btq7ZPyxUQ6/7dWwXx9BdqBmysswH9LIik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzd5ow%2Fbtq7ZPyxUQ6%2F7dWwXx9BdqBmysswH9LIik%2Fimg.png&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;204&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;현재 대상 원소인 Array[CurIndex]의 값보다 Array[0]의 값이 크기 때문에, 해당 값을 다음 인덱스인 1로 미뤄버린다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M2viL/btq755zqkbn/9Ynl6twumkyrqUwTnRlXJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M2viL/btq755zqkbn/9Ynl6twumkyrqUwTnRlXJ1/img.png&quot; data-alt=&quot;그렇다면 다음과 같은 상태가 되어 있을 것이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M2viL/btq755zqkbn/9Ynl6twumkyrqUwTnRlXJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM2viL%2Fbtq755zqkbn%2F9Ynl6twumkyrqUwTnRlXJ1%2Fimg.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그렇다면 다음과 같은 상태가 되어 있을 것이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이때&amp;nbsp;&lt;b&gt;가장 앞 원소까지 탐색이 종료되었으므로, 최종적으로 미뤄졌던 인덱스에 현재 인덱스의 값을 '삽입'한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;195&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btkISx/btq7541BKJ3/6nUy7BhPdpsv8EiWpJuaF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btkISx/btq7541BKJ3/6nUy7BhPdpsv8EiWpJuaF0/img.png&quot; data-alt=&quot;0번째 인덱스에서 미뤄지는 것이 종료되었으므로, 해당 위치에 초기에 선택했던 값을 삽입한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btkISx/btq7541BKJ3/6nUy7BhPdpsv8EiWpJuaF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtkISx%2Fbtq7541BKJ3%2F6nUy7BhPdpsv8EiWpJuaF0%2Fimg.png&quot; data-origin-width=&quot;427&quot; data-origin-height=&quot;195&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;0번째 인덱스에서 미뤄지는 것이 종료되었으므로, 해당 위치에 초기에 선택했던 값을 삽입한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;205&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dARsv3/btq74iT3eBL/2oShv32nSPy0TadtCqtpB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dARsv3/btq74iT3eBL/2oShv32nSPy0TadtCqtpB1/img.png&quot; data-alt=&quot;그렇다면 다음과 같은 상태가 되어 있을 것이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dARsv3/btq74iT3eBL/2oShv32nSPy0TadtCqtpB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdARsv3%2Fbtq74iT3eBL%2F2oShv32nSPy0TadtCqtpB1%2Fimg.png&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;205&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그렇다면 다음과 같은 상태가 되어 있을 것이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;2번째 원소에 대한 탐색이 종료되었으므로, 이번에는 3번째 원소에 대한 값을 기준으로 위 과정을 똑같이 반복해준다. 즉 초기 상태는 아래와 같아질 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;195&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CX2TB/btq74EbBCqP/OtNVJGTLggNAidwXVqcTj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CX2TB/btq74EbBCqP/OtNVJGTLggNAidwXVqcTj0/img.png&quot; data-alt=&quot;초기 배열 상태. 마찬가지로 Array[CurIndex]의 값은 임시 변수에 저장하여 값을 기억해둔다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CX2TB/btq74EbBCqP/OtNVJGTLggNAidwXVqcTj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCX2TB%2Fbtq74EbBCqP%2FOtNVJGTLggNAidwXVqcTj0%2Fimg.png&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;195&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초기 배열 상태. 마찬가지로 Array[CurIndex]의 값은 임시 변수에 저장하여 값을 기억해둔다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지로 현재 원소의 앞의 원소만을 탐색하기 때문에, Array[1]과 Array[CurIndex]의 값을 비교하게 될 것이다. 이때, Array[1] &amp;gt; Array[CurIndex]이므로 해당 원소의 위치를 뒤로 미뤄버린다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;194&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mngaN/btq74peHWoT/tL6a7HdrtgNqXx1dmzBx0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mngaN/btq74peHWoT/tL6a7HdrtgNqXx1dmzBx0K/img.png&quot; data-alt=&quot;해당 원소를 뒤로 미뤄버린다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mngaN/btq74peHWoT/tL6a7HdrtgNqXx1dmzBx0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmngaN%2Fbtq74peHWoT%2FtL6a7HdrtgNqXx1dmzBx0K%2Fimg.png&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;194&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;해당 원소를 뒤로 미뤄버린다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vwSGi/btq72jGg7lG/QiZi4nGq2wSqwYkU8Ks7K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vwSGi/btq72jGg7lG/QiZi4nGq2wSqwYkU8Ks7K0/img.png&quot; data-alt=&quot;따라서 다음과 같은 상태가 되어 있을 것이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vwSGi/btq72jGg7lG/QiZi4nGq2wSqwYkU8Ks7K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvwSGi%2Fbtq72jGg7lG%2FQiZi4nGq2wSqwYkU8Ks7K0%2Fimg.png&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;207&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;따라서 다음과 같은 상태가 되어 있을 것이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다음으로 Array[0]와 Array[CurIndex]를 비교해보면 Array[CurIndex]의 값이 더 크기 때문에, 탐색을 종료한다.&amp;nbsp;&lt;b&gt;탐색을 종료한 지점이 1이므로, 해당 위치에 임시로 저장해두었던 Array[CurIndex]의 값을 삽입&lt;/b&gt;해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zO8ZX/btq74bOvjvX/qRkYJGlEupeLhg0cGo5r50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zO8ZX/btq74bOvjvX/qRkYJGlEupeLhg0cGo5r50/img.png&quot; data-alt=&quot;Array[0] &amp;amp;amp;lt; Array[CurIndex]이므로, 1번째 원소에서 탐색이 종료되고 해당위치에 기억해두었던 값을 삽입해주면된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zO8ZX/btq74bOvjvX/qRkYJGlEupeLhg0cGo5r50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzO8ZX%2Fbtq74bOvjvX%2FqRkYJGlEupeLhg0cGo5r50%2Fimg.png&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[0] &amp;lt; Array[CurIndex]이므로, 1번째 원소에서 탐색이 종료되고 해당위치에 기억해두었던 값을 삽입해주면된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이러한 과정을 n번째 원소까지 반복해준다면 정렬이 완료된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*삽입 정렬의 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;쉽게 말해 2번째 원소부터 시작하여, n번째 원소까지 해당 원소의 앞 원소들과 비교하여 해당 원소가 위치해야할 자리를 찾는 과정을 구현해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1624552019961&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package sort;

import java.util.Arrays;

public class InsertionSort {
	static int[] nums;

	public static void main(String[] args) {
		nums = new int[10];
		for (int i = 0; i &amp;lt; 10; i++) {
			nums[i] = (int) (Math.random() * 10);
		}
		System.out.println(&quot;&amp;lt;정렬 전&amp;gt;&quot;);
		System.out.println(Arrays.toString(nums));
		
		for(int i = 1; i &amp;lt; nums.length; i++) {
			// 현재 선택된 원소의 값을 임시 변수에 저장해준다.
			int temp = nums[i];
			// 현재 원소를 기준으로 이전 원소를 탐색하기 위한 index 변수.
			int prev = i - 1;
			// 현재 선택된 원소가 이전 원소보다 작은 경우까지만 반복. 단, 0번째 원소까지만 비교한다.
			while(prev &amp;gt;= 0 &amp;amp;&amp;amp; nums[prev] &amp;gt; temp) {
				// 현재 선택된 원소가 현재 탐색중인 원소보다 작다면, 해당 원소는 다음 인덱스로 미뤄버린다.
				nums[prev + 1] = nums[prev];
				// 다음 대상 원소를 탐색한다.
				prev--;
			}
			// 탐색이 종료된 지점에 현재 선택되었던 변수의 값을 삽입해준다.
			nums[prev + 1] = temp;
		}
		
		System.out.println(&quot;&amp;lt;정렬 후&amp;gt;&quot;);
		System.out.println(Arrays.toString(nums));
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*삽입 정렬의 시간 복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;예를들어 [5, 4, 3, 2, 1]과 같은 최악의 경우에는 &lt;b&gt;각각의 탐색에서 무조건 앞의 모든 원소를 뒤로 미뤄버리는 작업을 해야하기 때문에, 시간 복잡도는 O(n^2)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;이렇게&amp;nbsp;&lt;b&gt;탐색을 진행하면서 원소를 뒤로 미뤄버리는 방식을 사용&lt;/b&gt;하기 때문에&amp;nbsp;&lt;b&gt;자료구조에 따라 다른 성능을 보일 수 있다.&lt;/b&gt; 다만, &lt;b&gt;정렬하고자 하는 대상의 원소 수가 적다면 일반적으로 빠르다고 알려진 알고리즘보다 좋은 성능&lt;/b&gt;을 가지고 있다고한다. 따라서 고성능 알고리즘에서는 배열의 사이즈가 큰 경우에는 O(nlogn)정렬을 사용하다가 정렬해야 하는 부분이 작아지면 삽입 정렬로 전환하는 방식을 사용한다고도 한다. 일반적인 경우 탐색을 제외하면 삽입 정렬의 방식이 오버헤드가 매우 적기 때문이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※참고 : &lt;a href=&quot;https://namu.wiki/w/%EC%A0%95%EB%A0%AC%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98#s-2.1.3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://namu.wiki/w/%EC%A0%95%EB%A0%AC%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98#s-2.1.3&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;앞 부분에서 삽입해야할 위치를 찾는 경우, 앞 부분은 이미 정렬되어 있다는 점을 활용&lt;/b&gt;하여,&amp;nbsp;&lt;b&gt;위치를 찾는 방법에 이진 탐색을 활용&lt;/b&gt;해볼 수 있다. 이 경우&amp;nbsp;&lt;b&gt;최선의 경우 O(nlogn)의 시간 복잡도&lt;/b&gt;를 갖는다.&lt;/p&gt;</description>
      <category>Algorithm/정렬</category>
      <category>Insertion Sort</category>
      <category>삽입 정렬</category>
      <category>정렬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/81</guid>
      <comments>https://sskl660.tistory.com/81#entry81comment</comments>
      <pubDate>Fri, 25 Jun 2021 01:38:02 +0900</pubDate>
    </item>
    <item>
      <title>[Java]선택 정렬(Selection Sort)</title>
      <link>https://sskl660.tistory.com/80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*선택 정렬(Selection Sort)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;선택 정렬이란 &lt;b&gt;한 번의 배열 탐색에서 가장 작은 원소의 '위치'를 찾고, 그 위치와 배열의 가장 첫 번째 원소부터 차례로 바꿔주는 방식&lt;/b&gt;을 사용(오름 차순으로 정렬하는 경우)하는 정렬 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※가장 큰 원소의 위치를 찾고, 배열의 가장 마지막 원소부터 차례로 바꿔주는 방식을 사용해도 된다. 다만 반복문을 구현할 때 작은 원소의 값을 찾는 방식이 조금 더 구현하기 편하기 때문에 작은 원소를 찾는 방법을 주로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;말 그대로 큰 원소나 작은 원소를 선택하고 그 위치를 바꿔주기 때문에 선택 정렬이라는 이름을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*선택 정렬의 이해&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;어떤 대상을 '오름차순'으로 정렬할 때 선택 정렬은&amp;nbsp;&lt;b&gt;원소를 처음부터 탐색하면서, 작은 수를 찾고 그 수를 배열의 앞쪽과 차례로 보내는 방식을 사용&lt;/b&gt;한다. 예를 들어 [3, 1, 5, 7, 10]이라는 배열을 선택 정렬을 이용하여 오름차순 정렬을 해보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;193&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TYhaM/btq73ctjZmb/tc6wOJ82xbZlzcq5SVyeMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TYhaM/btq73ctjZmb/tc6wOJ82xbZlzcq5SVyeMk/img.png&quot; data-alt=&quot;초기 배열 상태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TYhaM/btq73ctjZmb/tc6wOJ82xbZlzcq5SVyeMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTYhaM%2Fbtq73ctjZmb%2Ftc6wOJ82xbZlzcq5SVyeMk%2Fimg.png&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;193&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초기 배열 상태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;우선, 첫 번째 원소의 값을 기억해두고 1번째 인덱스부터 4번째 인덱스까지 더 작은 값이 나올때마다 해당 위치의 인덱스를 기억해둔다. 따라서 우선 Array[MinIndex]에 대하여 Array[1]의 값을 비교하면 Array[1]의 값이 작기 때문에 Array[1]의 인덱스인 1을 기억해둔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byL6w2/btq73cz5hjq/N1FI5XBGRO1HEXP5eGWF70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byL6w2/btq73cz5hjq/N1FI5XBGRO1HEXP5eGWF70/img.png&quot; data-alt=&quot;Array[MinIndex] &amp;amp;amp;gt; Array[1]이므로, MinIndex = 1로 갱신해준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byL6w2/btq73cz5hjq/N1FI5XBGRO1HEXP5eGWF70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyL6w2%2Fbtq73cz5hjq%2FN1FI5XBGRO1HEXP5eGWF70%2Fimg.png&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[MinIndex] &amp;gt; Array[1]이므로, MinIndex = 1로 갱신해준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지로 2번째 인덱스와 현재 Array[MinIndex]의 값을 비교해준다. 이때, Array[MinIndex]의 값이 더 작기 때문에 MinIndex의 값이 따로 갱신되지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;220&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRhTTE/btq74n8YhIk/1eFpv2DNzvEi6PJENaehS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRhTTE/btq74n8YhIk/1eFpv2DNzvEi6PJENaehS1/img.png&quot; data-alt=&quot;Array[MinIndex] &amp;amp;amp;lt; Array[2]이므로 MinIndex는 따로 갱신되지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRhTTE/btq74n8YhIk/1eFpv2DNzvEi6PJENaehS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRhTTE%2Fbtq74n8YhIk%2F1eFpv2DNzvEi6PJENaehS1%2Fimg.png&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;220&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[MinIndex] &amp;lt; Array[2]이므로 MinIndex는 따로 갱신되지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;3, 4번째 인덱스 역시 현재 Array[MinIndex]의 값보다 크기 때문에 MinIndex의 값은 따로 갱신이 일어나지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRvOb0/btq75DJZKpv/96gifAp8gMLU2NlTNTGGN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRvOb0/btq75DJZKpv/96gifAp8gMLU2NlTNTGGN0/img.png&quot; data-alt=&quot;Array[MinIndex] &amp;amp;amp;lt; Array[3], Array[MinIndex] &amp;amp;amp;lt; Array[4] 이므로 MinIndex는 따로 갱신되지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRvOb0/btq75DJZKpv/96gifAp8gMLU2NlTNTGGN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRvOb0%2Fbtq75DJZKpv%2F96gifAp8gMLU2NlTNTGGN0%2Fimg.png&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;191&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[MinIndex] &amp;lt; Array[3], Array[MinIndex] &amp;lt; Array[4] 이므로 MinIndex는 따로 갱신되지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;이렇게 한 번의 탐색이 완료되었을 때&amp;nbsp;&lt;b&gt;최종적으로 해당 배열에서 가장 작은 값은 1번째 인덱스에 있는 값임을 알 수 있다. 따라서, 해당 값을 배열의 0번째 원소와 바꾸어 준다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;184&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cId9KK/btq74o7PTCO/onldIB2DakNmaUk0qC5aW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cId9KK/btq74o7PTCO/onldIB2DakNmaUk0qC5aW0/img.png&quot; data-alt=&quot;해당 배열에서 가장 작은 수는 1번째 원소이므로, 해당 값을 0번째 원소와 바꾸어준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cId9KK/btq74o7PTCO/onldIB2DakNmaUk0qC5aW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcId9KK%2Fbtq74o7PTCO%2FonldIB2DakNmaUk0qC5aW0%2Fimg.png&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;184&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;해당 배열에서 가장 작은 수는 1번째 원소이므로, 해당 값을 0번째 원소와 바꾸어준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그리고 다음 반복해서는 &lt;b&gt;초기 값을 1번째 인덱스부터 시작&lt;/b&gt;하여 마찬가지로 가장 작은 값을 앞으로 보내준다면 오름차순으로 정렬이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*선택 정렬의 구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1624549181529&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package sort;

import java.util.Arrays;

public class SelectionSort {
	static int[] nums;

	public static void main(String[] args) {
		nums = new int[10];
		for (int i = 0; i &amp;lt; 10; i++) {
			nums[i] = (int) (Math.random() * 10);
		}
		System.out.println(&quot;&amp;lt;정렬 전&amp;gt;&quot;);
		System.out.println(Arrays.toString(nums));
		
		for(int i = 0; i &amp;lt; nums.length - 1; i++) {
			// 현재 탐색에서 가장 앞의 원소를 초기 값으로 설정해둔다.
			int MinIndex = i;
			// 탐색을 진행하며, 가장 작은 값을 찾는다.
			for(int j = i + 1; j &amp;lt; nums.length; j++) {
				if(nums[MinIndex] &amp;gt; nums[j])
					MinIndex = j;
			}
			// 탐색이 완료되면 가장 작은 값을 가장 앞의 원소와 가장 작은 원소의 위치를 바꾸어준다.
			int temp = nums[MinIndex];
			nums[MinIndex] = nums[i];
			nums[i] = temp;
		}
		
		System.out.println(&quot;&amp;lt;정렬 후&amp;gt;&quot;);
		System.out.println(Arrays.toString(nums));
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;78&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPafye/btq73cfRtIs/Nx14hND4hwqoU3wUI0jkhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPafye/btq73cfRtIs/Nx14hND4hwqoU3wUI0jkhk/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPafye/btq73cfRtIs/Nx14hND4hwqoU3wUI0jkhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPafye%2Fbtq73cfRtIs%2FNx14hND4hwqoU3wUI0jkhk%2Fimg.png&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;78&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*선택 정렬의 시간 복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;버블 정렬과 마찬가지로 총 반복 횟수 = n(n-1)/2가 된다. 따라서, 선택 정렬의&amp;nbsp;&lt;b&gt;시간 복잡도는 O(n^2)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;선택 정렬은 어떤 정렬이 오더라도 비교하는 방식이 같기 때문에, 일반적인 상황에서 비슷한 성능을 보유한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;버블 정렬과 마찬가지로 직관적으로 이해가 편하고, 불필요하게 원소들을 교체하는 작업이 없기 때문에 버블 정렬보다 '일반적인 상황'에서 빠른 성능을 보이지만 여전히 시간 복잡도가 O(n^2)이기 때문에 실전에서 사용하기 힘든 정렬이다.&lt;/p&gt;</description>
      <category>Algorithm/정렬</category>
      <category>Selection Sort</category>
      <category>선택 정렬</category>
      <category>정렬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/80</guid>
      <comments>https://sskl660.tistory.com/80#entry80comment</comments>
      <pubDate>Fri, 25 Jun 2021 00:44:27 +0900</pubDate>
    </item>
    <item>
      <title>[Java]버블 정렬(Bubble Sort)</title>
      <link>https://sskl660.tistory.com/79</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*버블 정렬(Bubble Sort)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;버블 정렬이란&amp;nbsp;&lt;b&gt;인접한 두 원소를 비교&lt;/b&gt;하며, &lt;b&gt;큰 수를 계속하여 뒤로 보내 정렬하는 방식&lt;/b&gt;을 사용(오름 차순으로 정렬하는 경우)하는 정렬 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;원소들이 거품이 올라오는 것처럼 보여 거품 정렬(Bubble Sort)이라고 이름지었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*버블 정렬의 이해&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;어떤 대상을 '오름차순'으로 정렬할 때 버블 정렬은 &lt;b&gt;원소를 처음부터 탐색하면서, 큰 수를 계속하여 뒤로 밀어내는 방식을 사용&lt;/b&gt;한다. 예를 들어 [5, 3, 1, 10, 7]이라는 배열을 버블 정렬을 이용하여 오름차순 정렬을 해보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;171&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqiJzU/btq7599IQDA/lkgzDA9ir8gHgnE1bVHKj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqiJzU/btq7599IQDA/lkgzDA9ir8gHgnE1bVHKj1/img.png&quot; data-alt=&quot;초기 배열 상태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqiJzU/btq7599IQDA/lkgzDA9ir8gHgnE1bVHKj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqiJzU%2Fbtq7599IQDA%2FlkgzDA9ir8gHgnE1bVHKj1%2Fimg.png&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;171&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초기 배열 상태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;먼저, Array[0]와 Array[1]을 비교해보자. Array[0]가 Array[1]보다 크기 때문에, 이 두 배열의 원소의 위치를 바꾸어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lBR6H/btq759Pq1TR/IZ2KMsPkbeaS17kiWHKyfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lBR6H/btq759Pq1TR/IZ2KMsPkbeaS17kiWHKyfk/img.png&quot; data-alt=&quot;Array[0]와 Array[1]을 비교하고, 앞의 원소가 더 크다면 두 원소의 자리를 바꾸어준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lBR6H/btq759Pq1TR/IZ2KMsPkbeaS17kiWHKyfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlBR6H%2Fbtq759Pq1TR%2FIZ2KMsPkbeaS17kiWHKyfk%2Fimg.png&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[0]와 Array[1]을 비교하고, 앞의 원소가 더 크다면 두 원소의 자리를 바꾸어준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;156&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBPnJs/btq74oz0Zxb/GHbw3PclU0JW44n7Bkp0ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBPnJs/btq74oz0Zxb/GHbw3PclU0JW44n7Bkp0ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBPnJs/btq74oz0Zxb/GHbw3PclU0JW44n7Bkp0ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBPnJs%2Fbtq74oz0Zxb%2FGHbw3PclU0JW44n7Bkp0ak%2Fimg.png&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;156&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;다음으로 Array[1]과 Array[2]를 비교해보자. 마찬가지로 Array[1]이 Array[2]보다 크기 때문에, 이 두 배열의 원소의 위치를 바꾸어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;149&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAAGmM/btq75DXwK9t/F9JIhm3RDeb8EDtNFd3Ka0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAAGmM/btq75DXwK9t/F9JIhm3RDeb8EDtNFd3Ka0/img.png&quot; data-alt=&quot;Array[1]과 Array[2]를 비교하고, 앞의 원소가 더 크다면 두 원소의 자리를 바꾸어준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAAGmM/btq75DXwK9t/F9JIhm3RDeb8EDtNFd3Ka0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAAGmM%2Fbtq75DXwK9t%2FF9JIhm3RDeb8EDtNFd3Ka0%2Fimg.png&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;149&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[1]과 Array[2]를 비교하고, 앞의 원소가 더 크다면 두 원소의 자리를 바꾸어준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;155&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nqdFh/btq74izHmXN/gr48Kc2SR5tNKDH79lGuv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nqdFh/btq74izHmXN/gr48Kc2SR5tNKDH79lGuv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nqdFh/btq74izHmXN/gr48Kc2SR5tNKDH79lGuv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnqdFh%2Fbtq74izHmXN%2Fgr48Kc2SR5tNKDH79lGuv0%2Fimg.png&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;155&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;다음으로 Array[2]와 Array[3]을 비교해보자. 이때, Array[2]는 Array[3]보다 작기 때문에 두 원소의 자리를 바꾸지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;140&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rt455/btq74bt64sl/60YkeeyAiNAdBorMUeuQR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rt455/btq74bt64sl/60YkeeyAiNAdBorMUeuQR1/img.png&quot; data-alt=&quot;Array[2]은 Array[3]보다 크기 않으므로, 자리를 교체하지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rt455/btq74bt64sl/60YkeeyAiNAdBorMUeuQR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frt455%2Fbtq74bt64sl%2F60YkeeyAiNAdBorMUeuQR1%2Fimg.png&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;140&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[2]은 Array[3]보다 크기 않으므로, 자리를 교체하지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Array[3]과 Array[4]를 비교해보자. Array[3]은 Array[4]보다 크기 때문에, 두 원소의 자리를 바꾸어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;145&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEQTyO/btq745mpCq8/kk393VRMHRcKNDhJjXK5ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEQTyO/btq745mpCq8/kk393VRMHRcKNDhJjXK5ak/img.png&quot; data-alt=&quot;Array[3]은 Array[4]보다 크기 때문에, 두 원소의 자리를 교체해준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEQTyO/btq745mpCq8/kk393VRMHRcKNDhJjXK5ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEQTyO%2Fbtq745mpCq8%2Fkk393VRMHRcKNDhJjXK5ak%2Fimg.png&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;145&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Array[3]은 Array[4]보다 크기 때문에, 두 원소의 자리를 교체해준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;161&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d73mmt/btq72jMZyJX/9FBac3CE2AkuK97HdK1dK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d73mmt/btq72jMZyJX/9FBac3CE2AkuK97HdK1dK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d73mmt/btq72jMZyJX/9FBac3CE2AkuK97HdK1dK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd73mmt%2Fbtq72jMZyJX%2F9FBac3CE2AkuK97HdK1dK1%2Fimg.png&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;161&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;이렇게&amp;nbsp;&lt;b&gt;순차적으로 한 번의 자리 교체가 완료되면,&amp;nbsp;&lt;u&gt;가장 큰 수가 배열의 가장 뒤로 보내진 것을 확인할 수 있다.&lt;/u&gt;&amp;nbsp;&lt;/b&gt;따라서 이러한 점을 이용하여, 이 과정을 (배열의 크기 - 1)번 반복해주면&amp;nbsp;&lt;b&gt;한 번의 반복마다 순차적으로 큰 수가 뒤로 밀리는 것을 보장&lt;/b&gt;할 수 있다. 즉, 모든 반복이 완료되면 배열의 모든 수는 오름차순으로 정렬이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*버블 정렬의 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다만 이 과정에서&amp;nbsp;&lt;b&gt;이미 뒤로 보내진 수들은 다시 정렬 여부를 확인할 필요가 없기 때문에, 한 번의 반복마다 교체를 확인하는 인덱스를 1씩 줄여주며 반복을 하는 구현 방법을 주로 사용&lt;/b&gt;한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1624546975404&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package sort;

import java.util.Arrays;

public class BubbleSort {
	static int[] nums;

	public static void main(String[] args) {
		nums = new int[10];
		for (int i = 0; i &amp;lt; 10; i++) {
			nums[i] = (int) (Math.random() * 10);
		}
		System.out.println(&quot;&amp;lt;정렬 전&amp;gt;&quot;);
		System.out.println(Arrays.toString(nums));
		
		// 한 번의 반복이 완료될 때 마다 가장 큰 수는 배열의 가장 마지막 부분으로 밀리는 것이 보장된다.
		for(int i = nums.length - 1; i &amp;gt; 0; i--) {
			// 따라서, 한 번의 반복마다 가장 뒤의 인덱스는 비교하지 않도록 반복문을 설계할 수 있다.
			for(int j = 0; j &amp;lt; i; j++) {
				// 만일, 앞의 수가 뒤의 수보다 더 크다면 swap 연산을 진행해준다.
				if(nums[j] &amp;gt; nums[j + 1]) {
					int temp = nums[j];
					nums[j] = nums[j + 1];
					nums[j + 1] = temp;
				}
			}
		}
		
		System.out.println(&quot;&amp;lt;정렬 후&amp;gt;&quot;);
		System.out.println(Arrays.toString(nums));
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;81&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvF8eq/btq74pyVRfa/MhF815ZhPKLcnp3t2c7Sg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvF8eq/btq74pyVRfa/MhF815ZhPKLcnp3t2c7Sg1/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvF8eq/btq74pyVRfa/MhF815ZhPKLcnp3t2c7Sg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvF8eq%2Fbtq74pyVRfa%2FMhF815ZhPKLcnp3t2c7Sg1%2Fimg.png&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;81&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*버블 정렬의 시간 복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;위의 구현을 따르면 n - 1번의 교체작업부터 순차적으로 1번의 교체작업까지 반복하므로, 총 반복 횟수 = 1 + 2 + ... + (n - 1)의 형태를 가질 것이다. 즉, 총 반복 횟수 = n(n- 1)/2가 될 것이다. 따라서, 버블 정렬의 &lt;b&gt;시간 복잡도는 O(n^2)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;가장 큰 수를 뒤로 보내는 방식을 사용하기 때문에, 이미 정렬하고자 하는 배열이 어느정도 정렬이 되어 있는 상태 일수록 최선의 성능을 낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;직관적으로 이해가 쉬운 정렬로 구현하기 쉽지만 일반적으로 O(n^2)의 시간복잡도를 갖기 때문에 실전에서는 거의 사용할 일이 없다. 다만 버블 정렬에 사용되는 Swap연산이 중요하기 때문에 초기 프로그래밍시 자주 사용되는 예제 중 하나이다.&lt;/p&gt;</description>
      <category>Algorithm/정렬</category>
      <category>Bubble sort</category>
      <category>거품 정렬</category>
      <category>버블 정렬</category>
      <category>정렬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/79</guid>
      <comments>https://sskl660.tistory.com/79#entry79comment</comments>
      <pubDate>Fri, 25 Jun 2021 00:08:41 +0900</pubDate>
    </item>
    <item>
      <title>GitHub Desktop(Pull, Push)</title>
      <link>https://sskl660.tistory.com/78</link>
      <description>&lt;p&gt;&lt;b&gt;깃(Git)&lt;/b&gt;은&amp;nbsp;&lt;b&gt;컴퓨터 파일의 변경사항을 추적&lt;/b&gt;하고,&amp;nbsp;&lt;b&gt;여러 사용자간 협업&lt;/b&gt;을 위한&amp;nbsp;&lt;b&gt;분산 버전 관리 시스템&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기본적으로 Git은 버전 관리, 백업, 협업 등 매우 다양하지만 심오한 개념을 가지고있고 GUI를 이용한 방식, CLI를 이용한 방식이 있지만 CLI는 초보자가 바로 능숙하게 다루기엔 다소 어려운 부분들이 존재한다.&lt;/p&gt;
&lt;p&gt;이 글에서는 GUI방식을 기반으로 개발된&lt;b&gt; GitHub DeskTop 프로그램&lt;/b&gt;의 &lt;b&gt;Pull을 이용하여 GitHub 서버에서 자료를 가져오는 방법&lt;/b&gt;과 &lt;b&gt;Push를 이용하여 서버로 자료를 보내는 방법&lt;/b&gt;만 매우 담백하게 작성하였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*Clone&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; Clone은 쉽게 말해 GitHub(Server)에 저장된 내용을 내 컴퓨터(Local)로 가져오는 작업이다.&lt;/p&gt;
&lt;p&gt;(1) 먼저, 아래 그림과 같이 GitHub DeskTop의 파일 탭에서 Clone repositor를 선택한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbgbUP/btq4o8VJLst/A4jnP5LllVr1G5VN21IMZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbgbUP/btq4o8VJLst/A4jnP5LllVr1G5VN21IMZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbgbUP/btq4o8VJLst/A4jnP5LllVr1G5VN21IMZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbgbUP%2Fbtq4o8VJLst%2FA4jnP5LllVr1G5VN21IMZ0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;(2) 나타나는 창에서 URL을 클릭하고, 1번 영역에는 자료를 가져올 GitHub의 주소를, 2번 영역에는 해당 파일을 내 컴퓨터에 저장할 경로를 입력한다. 이때, GitHub의 주소는 해당 프로젝트 우측 상단에서 아래와 같이 복사해오면 된다. 작성을 완료했으면, Clone 버튼을 누른다. 내 컴퓨터에 자료가 다운로드 된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mCKMW/btq4s3rLQgm/w8KIgTuD6I9JY01K6KYYy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mCKMW/btq4s3rLQgm/w8KIgTuD6I9JY01K6KYYy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mCKMW/btq4s3rLQgm/w8KIgTuD6I9JY01K6KYYy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmCKMW%2Fbtq4s3rLQgm%2Fw8KIgTuD6I9JY01K6KYYy0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yh7rx/btq4oOQCP8r/lTlBrrE5YNNd6lOFIrKkK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yh7rx/btq4oOQCP8r/lTlBrrE5YNNd6lOFIrKkK0/img.png&quot; data-alt=&quot;원하는 프로젝트의 좌상단에 위치한 녹색 버튼을 누르고 나타나는 주소를 복사한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yh7rx/btq4oOQCP8r/lTlBrrE5YNNd6lOFIrKkK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYh7rx%2Fbtq4oOQCP8r%2FlTlBrrE5YNNd6lOFIrKkK0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;원하는 프로젝트의 좌상단에 위치한 녹색 버튼을 누르고 나타나는 주소를 복사한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*Pull&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 이후 해당 주소에서 변경된 자료들은 Repository 탭의 Pull을 이용하여 내 컴퓨터로 간편하게 가져올 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCaUcG/btq4p30H852/gcw8pbDcE48IAYDtkTjC01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCaUcG/btq4p30H852/gcw8pbDcE48IAYDtkTjC01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCaUcG/btq4p30H852/gcw8pbDcE48IAYDtkTjC01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCaUcG%2Fbtq4p30H852%2Fgcw8pbDcE48IAYDtkTjC01%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*Push&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; Push는 반대로 내 컴퓨터에서 변경된 사항을 GitHub에 업로드 하는 작업이다. 협업을 하는 경우는 여러 제약 조건이 붙겠지만, 여기서는 그냥 GitHub에 업로드하는 방법만 서술하였다.&lt;/p&gt;
&lt;p&gt;(1) 기본적으로 내 컴퓨터에서 GitHub와 연동된 폴더에서 변화가 일어나면, 좌측의 Change에 변경된 내용이 표시된다. History의 경우, 해당 서버에서 변경된 내용을 모두 추적할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGNICx/btq4uIOl0Vz/MLzKMaQT9Q5IEmYBUSb7SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGNICx/btq4uIOl0Vz/MLzKMaQT9Q5IEmYBUSb7SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGNICx/btq4uIOl0Vz/MLzKMaQT9Q5IEmYBUSb7SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGNICx%2Fbtq4uIOl0Vz%2FMLzKMaQT9Q5IEmYBUSb7SK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;(2) 내 컴퓨터에서 변경된 사항을 최종적으로 확정(Commit)하는 단계이다. 1번 영역에는 변경 사항을 요약하는 제목을, 2번 영역에는 변경사항에 대한 설명을 작성해준다. 작성을 완료하였으면, Commit to main버튼을 눌러 변경 사항을 확정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VyezW/btq4pzS7A4k/X0vOkenxoMrgYiXKkYsw0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VyezW/btq4pzS7A4k/X0vOkenxoMrgYiXKkYsw0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VyezW/btq4pzS7A4k/X0vOkenxoMrgYiXKkYsw0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVyezW%2Fbtq4pzS7A4k%2FX0vOkenxoMrgYiXKkYsw0K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;(3) Commit이 완료 되었으면, 아래 그림과 같이 Push버튼이 활성화된다. Push 버튼을 누르면 서버에 내가 변경한 사항이 업로드 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0A1do/btq4p3l7rf6/CIKoKuKXAe71MoSWqlNz01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0A1do/btq4p3l7rf6/CIKoKuKXAe71MoSWqlNz01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0A1do/btq4p3l7rf6/CIKoKuKXAe71MoSWqlNz01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0A1do%2Fbtq4p3l7rf6%2FCIKoKuKXAe71MoSWqlNz01%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Git/GitHub</category>
      <category>clone</category>
      <category>git</category>
      <category>github desktop</category>
      <category>pull</category>
      <category>Push</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/78</guid>
      <comments>https://sskl660.tistory.com/78#entry78comment</comments>
      <pubDate>Sat, 8 May 2021 22:53:57 +0900</pubDate>
    </item>
    <item>
      <title>[Java]누적 합(Prefix Sum , Cumulative Sum)</title>
      <link>https://sskl660.tistory.com/77</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*누적 합(Prefix Sum, &lt;b&gt;Cumulative Sum&lt;/b&gt;)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;누적 합&lt;/b&gt;이란, 말 그대로&amp;nbsp;&lt;b&gt;나열된 수의 누적된 합&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 조금 더 엄밀히 말하면, 수열 An에 대해서, 구간 [1, 1]의 합, 구간 [1, 2]의 합, 구간 [1, 3]의 합, ..., [1, n]의 합을 누적 합이라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;163&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pikBu/btq3cyNHvGc/0ZjVU7HgkgBGtkvNaa0YyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pikBu/btq3cyNHvGc/0ZjVU7HgkgBGtkvNaa0YyK/img.png&quot; data-alt=&quot;자연수를 나타내는 수열 An의 5항까지의 누적 합&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pikBu/btq3cyNHvGc/0ZjVU7HgkgBGtkvNaa0YyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpikBu%2Fbtq3cyNHvGc%2F0ZjVU7HgkgBGtkvNaa0YyK%2Fimg.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;163&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;자연수를 나타내는 수열 An의 5항까지의 누적 합&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 따라서 Prefix Sum의 각 요소는 해당 해당 인덱스까지의&amp;nbsp;&lt;b&gt;부분 합(Partial Sum)&lt;/b&gt;을 의미한다. 부분 합은 급수에서 말하는 그 부분합의 의미가 맞다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*누적 합의 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 누적 합은 그 목적에 따라 &lt;b&gt;다양한 문제에 활용이 가능&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 대표적으로 누적 합을 사용하는 문제는&amp;nbsp;&lt;b&gt;카운팅 정렬(Counting Sort), 구간 합 구하기&lt;/b&gt;가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*단순 반복을 이용한 구간 합 구하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이 글의 핵심 목적이다. 일반적으로 구간의 합을 구하는 경우에는 다음과 같이 모든 구간의 값을 더해주는 방법을 생각해볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1619064372784&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class PrefixSum {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
		int[] arr2 = {1, 5, 8, 10, 24, 3, 5, 100, 99, 7};
		int a = sc.nextInt();
		int b = sc.nextInt();
		int sum1 = 0;
		int sum2 = 0;
		for(int i = a; i &amp;lt;= b; i++) {
			sum1 += arr[i];
			sum2 += arr2[i];
		}
		System.out.println(sum1);
		System.out.println(sum2);
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;41&quot; data-origin-height=&quot;54&quot; width=&quot;100&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byB90m/btq3cyAece2/A4SVtneG6PCB3RNtqbtBBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byB90m/btq3cyAece2/A4SVtneG6PCB3RNtqbtBBK/img.png&quot; data-alt=&quot;3번 ~ 5번 인덱스의 구간합&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byB90m/btq3cyAece2/A4SVtneG6PCB3RNtqbtBBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyB90m%2Fbtq3cyAece2%2FA4SVtneG6PCB3RNtqbtBBK%2Fimg.png&quot; data-origin-width=&quot;41&quot; data-origin-height=&quot;54&quot; width=&quot;100&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3번 ~ 5번 인덱스의 구간합&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;하지만 이렇게&amp;nbsp;&lt;b&gt;모든 입력마다 구간합을 일일히 구해주는 경우&lt;/b&gt;에는 &lt;b&gt;구간의 길이가 M이라고 하면&lt;/b&gt; &lt;b&gt;매 구간합을 구할 때&lt;span&gt; 마다 &lt;/span&gt;&lt;/b&gt;&lt;b&gt;O(M)&lt;/b&gt;이라는 시간이 걸리게 된다. 즉,&lt;b&gt; N개의 구간 에 대해 구간의 길이가 M인 구간합을 구하는 경우 O(NM)&lt;/b&gt;의 시간이 걸리는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;예를 들어, 자연수 구간 [1, 200,000]에서 각 자연수를 시작점으로 구간의 길이가 10000인 구간합을 모두 구하라는 문제를 생각해보면 해당 연산을 바탕으로 모든 구간합을 구하는 경우 총 20억번 가량의 연산을 진행&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하여야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*누적 합을 이용한 구간 합 구하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이러한&amp;nbsp;문제를 개선하기 위해&amp;nbsp;&lt;b&gt;누적 합을 이용하여 구간 합&lt;/b&gt;&lt;b&gt;을 구하는 방법&lt;/b&gt;을 사용한다면,&amp;nbsp;&lt;b&gt;시간 복잡도를 O(N + M)&lt;/b&gt;까지 줄일 수 있다. 이 방법은 수열의 부분 합 관련 문제를 풀 때 많이 사용하던 아이디어를 가져오면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 일반적으로 수열 An에서 구간 [i, j]까지의 구간 합을 구하는 경우를 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;241&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOqsjy/btq3ghYUJLB/YqEQ18Xl0LA9hdokvSpLLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOqsjy/btq3ghYUJLB/YqEQ18Xl0LA9hdokvSpLLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOqsjy/btq3ghYUJLB/YqEQ18Xl0LA9hdokvSpLLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOqsjy%2Fbtq3ghYUJLB%2FYqEQ18Xl0LA9hdokvSpLLk%2Fimg.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;241&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그림과 같이 n항 까지의 합을 Sn이라고 정의한다면, &lt;b&gt;구간 [i, j]의 구간합은 Sj와 Si-1을 뺀 값을 구하여 바로 구할 수 있다. &lt;/b&gt;즉,&lt;b&gt; Sn까지의 구간합을 모두 구해 놓기만 한다면(O(M)) 구간 합을 구하는 연산 자체는 O(1)&lt;/b&gt;&lt;b&gt;의 시간이면 구할 수 있기 때문에 결론적으로 O(N + M)의 시간 복잡도&lt;/b&gt;를 갖는 구간 합을 구하는 연산을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 결론적으로&amp;nbsp;&lt;b&gt;누적 합을 구하고, 그 누적합을 이용하여 주어진 구간의 합을 구하는 로직&lt;/b&gt;을 이용하여 구간 합을 더 빠르게 계산할 수 있다. 아래는 위와 같은 입력 값을 바탕으로 누적 합을 이용한 구간 합을 구하는 로직을 구현해 보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1619066597924&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class PrefixSum {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
		int[] arr2 = { 1, 5, 8, 10, 24, 3, 5, 100, 99, 7 };
		int a = sc.nextInt();
		int b = sc.nextInt();

		// 누적 합 구하기
		// 배열의 크기를 + 1하는 이유는, 0번 인덱스 ~ n번 인덱스의 구간합도 구할 수 있게 만들기 위함이다.
		int[] prefix_sum = new int[11];
		int[] prefix_sum2 = new int[11];
		for (int i = 1; i &amp;lt; arr.length; i++) {
			prefix_sum[i] += prefix_sum[i - 1] + arr[i];
			prefix_sum2[i] += prefix_sum2[i - 1] + arr2[i];
		}
		
		// 구간 합 구하기
		System.out.println(prefix_sum[b] - prefix_sum[a - 1]);
		System.out.println(prefix_sum2[b] - prefix_sum2[a - 1]);
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100&quot; height=&quot;NaN&quot; data-origin-width=&quot;41&quot; data-origin-height=&quot;54&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byB90m/btq3cyAece2/A4SVtneG6PCB3RNtqbtBBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byB90m/btq3cyAece2/A4SVtneG6PCB3RNtqbtBBK/img.png&quot; data-alt=&quot;3번 ~ 5번 인덱스의 구간합&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byB90m/btq3cyAece2/A4SVtneG6PCB3RNtqbtBBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyB90m%2Fbtq3cyAece2%2FA4SVtneG6PCB3RNtqbtBBK%2Fimg.png&quot; width=&quot;100&quot; height=&quot;NaN&quot; data-origin-width=&quot;41&quot; data-origin-height=&quot;54&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3번 ~ 5번 인덱스의 구간합&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 주석에도 언급해 두었지만,&amp;nbsp;&lt;b&gt;0번째 인덱스 ~ n번째 인덱스의 구간 합도 구할 수 있게 만들기 위해&lt;/b&gt;서는 배열의 크기를 하나 늘려서 앞에 0이라는 값을 추가해주어야 0번째 인덱스에 대한 구간 합도 구할 수 있다.&lt;/p&gt;</description>
      <category>Algorithm/수학&amp;amp;기타</category>
      <category>Cumulative Sum</category>
      <category>Partial Sum</category>
      <category>Prefix sum</category>
      <category>구간 합</category>
      <category>누적 합</category>
      <category>부분 합</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/77</guid>
      <comments>https://sskl660.tistory.com/77#entry77comment</comments>
      <pubDate>Thu, 22 Apr 2021 13:46:17 +0900</pubDate>
    </item>
    <item>
      <title>[Java]거듭 제곱의 계산</title>
      <link>https://sskl660.tistory.com/76</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*거듭 제곱의 계산&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 거듭 제곱을 구현하는 방법은 간단하다. 기본적으로는&amp;nbsp;&lt;b&gt;그 정의 그대로 어떤 수를 n번 곱하여 거듭제곱을 구현 가능&lt;/b&gt;하다. 하지만&amp;nbsp;&lt;b&gt;n번 곱하기 때문에 시간복잡도는 O(n)이 걸린다는 것&lt;/b&gt;을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;75&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cANkFk/btq22Fz3tKy/cvMkSKpTjEJPZm604t8II1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cANkFk/btq22Fz3tKy/cvMkSKpTjEJPZm604t8II1/img.png&quot; data-alt=&quot;거듭제곱의 정의를 이용한 거듭 제곱&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cANkFk/btq22Fz3tKy/cvMkSKpTjEJPZm604t8II1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcANkFk%2Fbtq22Fz3tKy%2FcvMkSKpTjEJPZm604t8II1%2Fimg.png&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;75&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;거듭제곱의 정의를 이용한 거듭 제곱&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*개선된 거듭 제곱의 계산&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이러한 거듭 제곱은&amp;nbsp;&lt;b&gt;분할 정복&lt;/b&gt;을 기반으로&amp;nbsp;&lt;b&gt;시간복잡도를 O(logN)까지 줄일 수 있다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 기본적인 아이디어는 다음과 같다. 예를 들어 5^10을 계산한다고 생각하였을 때, 아래와 같은 과정을 거쳐서 그 값을 구하는 것 이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;131&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NyBbN/btq24HxlQvq/c2KOF0X6FLXTyWphX7krb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NyBbN/btq24HxlQvq/c2KOF0X6FLXTyWphX7krb1/img.png&quot; data-alt=&quot;거듭 제곱을 반으로 나눠, 한 값을 구하고 거듭 제곱이 짝수냐, 홀수냐에 따라 다르게 합치는 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NyBbN/btq24HxlQvq/c2KOF0X6FLXTyWphX7krb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNyBbN%2Fbtq24HxlQvq%2Fc2KOF0X6FLXTyWphX7krb1%2Fimg.png&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;131&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;거듭 제곱을 반으로 나눠, 한 값을 구하고 거듭 제곱이 짝수냐, 홀수냐에 따라 다르게 합치는 방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 따라서, 재귀를 이용하여 다음과 같은 거듭제곱을 구현할 수 있음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;169&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnFxjV/btq27gZSKgj/oMWIjb1X4QHj4HozwNx9DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnFxjV/btq27gZSKgj/oMWIjb1X4QHj4HozwNx9DK/img.png&quot; data-alt=&quot;거듭 제곱 계산&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnFxjV/btq27gZSKgj/oMWIjb1X4QHj4HozwNx9DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnFxjV%2Fbtq27gZSKgj%2FoMWIjb1X4QHj4HozwNx9DK%2Fimg.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;169&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;거듭 제곱 계산&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 점화식도 구하였으니 그대로 구현하기만 해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1618906616505&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Exponentiation {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long a = sc.nextInt(); // 밑
		long b = sc.nextInt(); // 지수

		System.out.println(pow(a, b));
		sc.close();
	}

	private static long pow(long a, long b) {
		// 지수가 0인 경우(종료 조건).
		if (b == 0) {
			return 1;
		}

		// 반으로 나눈 거듭제곱 계산.
		long res = pow(a, b / 2);

		// 지수가 짝수인 경우.
		if (b % 2 == 0) {
			return res * res;
		}
		// 지수가 홀수인 경우
		else {
			return res * res * a;
		}
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/수학&amp;amp;기타</category>
      <category>java</category>
      <category>거듭 제곱</category>
      <category>고속 거듭 제곱</category>
      <category>분할 정복</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/76</guid>
      <comments>https://sskl660.tistory.com/76#entry76comment</comments>
      <pubDate>Tue, 20 Apr 2021 17:17:25 +0900</pubDate>
    </item>
    <item>
      <title>페르마의 소정리(Fermat's Little Theorem)</title>
      <link>https://sskl660.tistory.com/74</link>
      <description>&lt;p&gt;&lt;b&gt;*페르마의 소정리(Fermat's Little Theorem)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 우선 페르마의 소정리를 활용하기 위해서는 기본적으로&amp;nbsp;&lt;b&gt;모듈러 산술(연산)과 합동식에 대한 이해&lt;/b&gt;가 선행되어야 한다. 다음 포스팅을 참고하도록 하자. &lt;a href=&quot;https://sskl660.tistory.com/75&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/75&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618845346086&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;모듈러 산술(Modular Arithmetic)&quot; data-og-description=&quot;*모듈러 산술(Modular Arithmetic) -&amp;gt; 모듈러 산술(모듈러 연산)은 정수의 합과 곱을 어떤 주어진 수의 나머지를 이용하여 정의하는 방법을 말한다. -&amp;gt; 쉽게 말해&amp;nbsp;나머지를 이용한 산술 연산이라고 생&quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/75&quot; data-og-url=&quot;https://sskl660.tistory.com/75&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/6AEgJ/hyJWwlZ7Tr/tn8Fu4XGUn2Qe0mXwf9LHK/img.png?width=800&amp;amp;height=86&amp;amp;face=0_0_800_86,https://scrap.kakaocdn.net/dn/cxNfv2/hyJWEdgOSw/oQcNI1peCiMwq1NtfMBZSk/img.png?width=800&amp;amp;height=86&amp;amp;face=0_0_800_86&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/75&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/75&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/6AEgJ/hyJWwlZ7Tr/tn8Fu4XGUn2Qe0mXwf9LHK/img.png?width=800&amp;amp;height=86&amp;amp;face=0_0_800_86,https://scrap.kakaocdn.net/dn/cxNfv2/hyJWEdgOSw/oQcNI1peCiMwq1NtfMBZSk/img.png?width=800&amp;amp;height=86&amp;amp;face=0_0_800_86');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;모듈러 산술(Modular Arithmetic)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;*모듈러 산술(Modular Arithmetic) -&amp;gt; 모듈러 산술(모듈러 연산)은 정수의 합과 곱을 어떤 주어진 수의 나머지를 이용하여 정의하는 방법을 말한다. -&amp;gt; 쉽게 말해&amp;nbsp;나머지를 이용한 산술 연산이라고 생&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;페르마의 소정리&lt;/b&gt;는&amp;nbsp;&lt;u&gt;&lt;b&gt;특정한 상황에서 어떤 수의 나머지를 빠르게 구할 때 사용이 가능&lt;/b&gt;&lt;/u&gt;하다. 특정한 상황은 아래 정리를 참고하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFMwpM/btq21pKkqWX/lQI4KALxDhkilyJYPLnxwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFMwpM/btq21pKkqWX/lQI4KALxDhkilyJYPLnxwk/img.png&quot; data-alt=&quot;페르마의 소정리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFMwpM/btq21pKkqWX/lQI4KALxDhkilyJYPLnxwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFMwpM%2Fbtq21pKkqWX%2FlQI4KALxDhkilyJYPLnxwk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;페르마의 소정리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;쉽게 말해 &lt;b&gt;a^(p - 1)과 1을 p로 나눈 나머지는 같다&lt;/b&gt;, 즉, &lt;b&gt;a^(p - 1)의 나머지는 1이다&lt;/b&gt;라는 말이다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 예를 들어, 97이라는 소수가 있고 5는 97의 배수가 아니기 때문에 5^(97 - 1) &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv; 1 (mod 97)이 성립한다는 것을 위 정리를 통해 알 수 있다. 여기에서&amp;nbsp;&lt;b&gt;합동 관계의 거듭 제곱에 관련된 성질&lt;/b&gt;&lt;b&gt;을 이용&lt;/b&gt;하면,&amp;nbsp;&lt;b&gt;어마어마하게 큰 수의 나머지도 간단하게 구할 수 있는 경우&lt;/b&gt;가 존재함을 알 수 있게된다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/수학&amp;amp;기타</category>
      <category>Fermat's little theorem</category>
      <category>모듈러 산술</category>
      <category>페르마의 소정리</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/74</guid>
      <comments>https://sskl660.tistory.com/74#entry74comment</comments>
      <pubDate>Tue, 20 Apr 2021 00:36:20 +0900</pubDate>
    </item>
    <item>
      <title>모듈러 산술(Modular Arithmetic)</title>
      <link>https://sskl660.tistory.com/75</link>
      <description>&lt;p&gt;&lt;b&gt;*모듈러 산술(Modular Arithmetic)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; &lt;b&gt;모듈러 산술(모듈러 연산)&lt;/b&gt;은 &lt;b&gt;정수의 합과 곱을 어떤 주어진 수의 나머지를 이용하여 정의하는 방법&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 쉽게 말해&amp;nbsp;&lt;b&gt;나머지를 이용한 산술 연산&lt;/b&gt;이라고 생각하면 된다. 사칙 연산과 마찬가지로&amp;nbsp;&lt;b&gt;정수의 나머지에도 연산과 관련된 개념이 존재&lt;/b&gt;한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 모듈러 연산은 정수론, 컴퓨터 과학의 보안 등 여러 분야에서 유용하게 사용될 수 있다. &lt;u&gt;&lt;b&gt;알고 있다면 알고리즘 문제에서 몇몇 연산을 편하게 할 수 있는 방법을 생각하는 기반이 될 수 있다.&lt;/b&gt;&lt;/u&gt; 모듈러 연산 자체를 응용한 문제는 그렇게 많지 않지만, 이를 기반으로한 수학적 개념(정수론)의 기반이 되기 때문에 이해해두도록 하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*모듈러 산술 연산과 &lt;b&gt;합동(Congruent)&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;-&amp;gt; 모듈러 산술 연산&amp;nbsp;&lt;/b&gt;: 쉽게 말해&amp;nbsp;&lt;b&gt;나머지 연산&lt;/b&gt;&lt;b&gt;을 하는 것&lt;/b&gt;을 말한다. 보통 언어에서 사용하는 %연산과 비교하여 작성해보면 다음과 같다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9GbHL/btq226KL0MJ/0qx1yNqCKL6HwrCSHdZe7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9GbHL/btq226KL0MJ/0qx1yNqCKL6HwrCSHdZe7k/img.png&quot; data-alt=&quot;mod 연산의 정의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9GbHL/btq226KL0MJ/0qx1yNqCKL6HwrCSHdZe7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9GbHL%2Fbtq226KL0MJ%2F0qx1yNqCKL6HwrCSHdZe7k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;mod 연산의 정의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;-&amp;gt; 합동(Congruent)&amp;nbsp;&lt;/b&gt;: mod 연산은 합동 관계를 바탕으로 두 수의 관계를 정의하는 경우가 많이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKxOyr/btq2ZpqgFVU/7qRXKzagNj16t6kf2tHvgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKxOyr/btq2ZpqgFVU/7qRXKzagNj16t6kf2tHvgk/img.png&quot; data-alt=&quot;합동 관계의 정의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKxOyr/btq2ZpqgFVU/7qRXKzagNj16t6kf2tHvgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKxOyr%2Fbtq2ZpqgFVU%2F7qRXKzagNj16t6kf2tHvgk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;합동 관계의 정의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;※ m | (a - b)에서 | 의 의미는 (a - b)는 m으로 나누어 떨어진다는 의미이다. 쉽게 말해, 10은 2로 나누어 떨어진다는 것을 수학적으로 표현하면 2 | 10이다. 나누어 떨어지지 않는 경우는&lt;span&gt; ł 라는 기호를 이용하여 표현한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;※ 쉽게 말해 &lt;b&gt;a - b가 m이라는 정수로 나누어 떨어진다면, &lt;span&gt;a &amp;equiv;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;b (mod m)과 같이 표현하겠다&lt;/span&gt;&lt;/b&gt;&lt;span&gt;라는 의미라고 생각하면 된다.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;※ 이는 다르게 말하면, &lt;u&gt;&lt;b&gt;a와 b는 m에 의하여 나눠 졌을때의 나머지가 동일&lt;/b&gt;&lt;b&gt;하다&lt;/b&gt;&lt;b&gt;는 것을 의미&lt;/b&gt;&lt;/u&gt;한다. 이것을 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;조금 더 직관적으로 이해하기 위하여 예를 들어보면 어떤 수를 5로 나눌 때, 그 수의 나머지가 2인 것들을 모아서 생각해 보도록 하자. 그럼 아래와 같이 나열할 수 있을 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTOajP/btq2SMGlDfg/6kK9hxiudAdvheN9LkKt0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTOajP/btq2SMGlDfg/6kK9hxiudAdvheN9LkKt0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTOajP/btq2SMGlDfg/6kK9hxiudAdvheN9LkKt0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTOajP%2Fbtq2SMGlDfg%2F6kK9hxiudAdvheN9LkKt0K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이때, 나누어지는 수들의 관계를 분석해보면 &lt;b&gt;나누는 수 5&lt;/b&gt;&lt;b&gt;에 의하여 나누어지는 수들 중 나머지가 같은 수(2, 7, 12...)는 나누는 수 만큼의 차이가 존재한다는 것&lt;/b&gt;을 알 수 있다.&amp;nbsp;&lt;b&gt;즉, 5에 대한 나머지가 같은 수들의 집합&lt;/b&gt;&lt;b&gt;에서 임의의 두 수를 꺼내서 빼도 항상 그 뺀 차이는 5로 나누어 떨어진다는 것&lt;/b&gt;을 알 수 있다. 따라서 이러한 규칙성을 m | (a - b)라고 표현한 것 뿐이고, 그것을 수식으로 표현한 것이다 &lt;span&gt;a &amp;equiv;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;b (mod m)일 뿐이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;*모듈러 산술 연산의 특징&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;-&amp;gt; &lt;b&gt;모듈러 산술 연산&lt;/b&gt;은&amp;nbsp;&lt;b&gt;분배 법칙&lt;/b&gt;이 성립한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp1PSV/btq2ZoeyBr9/6P48jnjYhAkKorjykWuKK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp1PSV/btq2ZoeyBr9/6P48jnjYhAkKorjykWuKK1/img.png&quot; data-alt=&quot;덧셈, 뺄셈, 곱셈에 대한 모듈러 산술 연산 분배 법칙&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp1PSV/btq2ZoeyBr9/6P48jnjYhAkKorjykWuKK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp1PSV%2Fbtq2ZoeyBr9%2F6P48jnjYhAkKorjykWuKK1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;덧셈, 뺄셈, 곱셈에 대한 모듈러 산술 연산 분배 법칙&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;나눗셈의 경우 &lt;b&gt;곱셈의 역원&lt;/b&gt;을 이용하여 분배법칙을 적용시킬 수 있다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 예를 들면 (5 + 11) mod 7 = (5 mod 7 + 11 mod 7) + mod 7 = 2임을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;*합동식의 성질&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;사실상 이 글의 핵심&lt;/b&gt;으로,&amp;nbsp;&lt;b&gt;모듈러 산술을 적용하기 위한 기본 재료&lt;/b&gt;가 되는 개념들이다. 증명에 대해서 이해를 해두는 것도 좋지만, 이 글은 &lt;b&gt;알고리즘 문제에서 주로 사용되는 합동식의 성질 이해&lt;/b&gt;를&amp;nbsp;위주로 작성하겠다. 합동식의 성질에 대한 증명은 나무위키의 합동식 문서의 '성질' 문단에서 참고할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;&lt;a href=&quot;https://namu.wiki/w/%ED%95%A9%EB%8F%99%EC%8B%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;namu.wiki/w/%ED%95%A9%EB%8F%99%EC%8B%9D&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618836856941&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;합동식 - 나무위키&quot; data-og-description=&quot;1. d∤bd\nmid bd∤b인데 해가 존재한다고 가정하자. 그럼 적당한 정수 yyy에 대하여 ax+my=bax+my=bax+my=b가 성립한다. 그런데 d∣ax+my=bd\mid ax+my=bd∣ax+my=b이므로 d∣bd\mid bd∣b이다. 이는 가정에 모순되므&quot; data-og-host=&quot;namu.wiki&quot; data-og-source-url=&quot;https://namu.wiki/w/%ED%95%A9%EB%8F%99%EC%8B%9D&quot; data-og-url=&quot;https://namu.wiki/w/%ED%95%A9%EB%8F%99%EC%8B%9D&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://namu.wiki/w/%ED%95%A9%EB%8F%99%EC%8B%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://namu.wiki/w/%ED%95%A9%EB%8F%99%EC%8B%9D&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;합동식 - 나무위키&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;1. d∤bd\nmid bd∤b인데 해가 존재한다고 가정하자. 그럼 적당한 정수 yyy에 대하여 ax+my=bax+my=bax+my=b가 성립한다. 그런데 d∣ax+my=bd\mid ax+my=bd∣ax+my=b이므로 d∣bd\mid bd∣b이다. 이는 가정에 모순되므&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;namu.wiki&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;b&gt;(1) 덧셈, 뺄셈, 곱셈에 관련된 성질&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OP0C5/btq2TcZtZVl/ub0mvZPKqAFWZBzxy8IrXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OP0C5/btq2TcZtZVl/ub0mvZPKqAFWZBzxy8IrXk/img.png&quot; data-alt=&quot;덧셈, 뺄셈에 관련된 성질&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OP0C5/btq2TcZtZVl/ub0mvZPKqAFWZBzxy8IrXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOP0C5%2Fbtq2TcZtZVl%2Fub0mvZPKqAFWZBzxy8IrXk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;덧셈, 뺄셈에 관련된 성질&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 쉽게 말해 a와 b로 m으로 나눈 나머지가 같고 c와 d를 m으로 나눈 나머지가 같으면 &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;a &amp;plusmn; c 와 b &amp;plusmn; d 를 m으로 나눈 나머지도 같다는 의미이다. 예를 들면 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;49 &lt;/span&gt;&lt;span&gt;&amp;equiv; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; (mod 8)&lt;/span&gt;&lt;span&gt;이고&lt;/span&gt;&lt;span&gt; 37 &amp;equiv; 5 (&lt;/span&gt;&lt;span&gt;mod 8)일 때&lt;/span&gt;&lt;span&gt;&amp;nbsp;위의 성질에 의하여 &lt;/span&gt;&lt;span&gt;86 &lt;/span&gt;&lt;span&gt;&amp;equiv; 6 (mod 8)&lt;/span&gt;&lt;span&gt;임을 알 수 있다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cChheq/btq2OQJgRvQ/y7X6CCmu22WKCiKvgU95b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cChheq/btq2OQJgRvQ/y7X6CCmu22WKCiKvgU95b1/img.png&quot; data-alt=&quot;곱셈에 관련된 성질&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cChheq/btq2OQJgRvQ/y7X6CCmu22WKCiKvgU95b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcChheq%2Fbtq2OQJgRvQ%2Fy7X6CCmu22WKCiKvgU95b1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;곱셈에 관련된 성질&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt; 위의 성질과 별로 다른 점이 없다. 곱셈에 대해서도 똑같은 논리가 적용된다. 예를 들면 33 &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv; 5 (mod 7)이고 122 &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv;&lt;/span&gt; 17 (mod 7)일 때 위의 성질에 의하여 4026 &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv; 85 (mod 7)임을 알 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(2) 거듭 제곱에 관련된 성질&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2h2KI/btq2Rlh8VYW/vwl4yt7Vlajf7c1Wkzcxsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2h2KI/btq2Rlh8VYW/vwl4yt7Vlajf7c1Wkzcxsk/img.png&quot; data-alt=&quot;거듭 제곱에 관련된 성질&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2h2KI/btq2Rlh8VYW/vwl4yt7Vlajf7c1Wkzcxsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2h2KI%2Fbtq2Rlh8VYW%2Fvwl4yt7Vlajf7c1Wkzcxsk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;거듭 제곱에 관련된 성질&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt; 이 역시 쉽게 말하면, a와 b를 m으로 나눈 나머지가 동일 하다면, 각 숫자를 동일하게 거듭제곱한 숫자를 m으로 나눈 나머지도 동일하다는 의미를 갖는다. 예를 들면 77 &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv;&lt;/span&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;7 (mod 8)일 때, 77&lt;span&gt;^10&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;equiv; &lt;/span&gt;&lt;span&gt;7^10&lt;/span&gt;&lt;span&gt; (mod &lt;/span&gt;&lt;span&gt;8)도 성립한다는 것을 알 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;*합동식의 성질의 활용&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;-&amp;gt; 합동식의 성질을 활용하면 다음과 같이 일반적으로는 계산하기 힘든 문제도 간단하게 해결할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;※ 3&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;^333의 1의 자리수를 구하시오.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 1의 자리수를 구한다는 것은, 해당 숫자를 10으로 나눈 나머지를 구한다는 것과 같은 의미이다&lt;b&gt;(특정 자리수를 구하는 것은 대상 숫자를 10의 거듭제곱 중 하나로 나누어 구할 수 있다)&lt;/b&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 우선 &lt;b&gt;거듭 제곱에 관련된 모듈러 산술의 성질을 이용하여 접근하기 위해 작은 숫자부터 규칙성&lt;/b&gt;을 찾아보자. 3 ^ 4 &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv; 1 (mod 10)이고, 따라서 거듭 제곱의 성질을 적용하면 3 ^ 332 &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv; 1 ^ 83 (mod 10)임을 알 수 있다. 즉 이 식은 3 ^ 332 &lt;span style=&quot;color: #333333;&quot;&gt;&amp;equiv; 1 (mod 10)과 같고, &lt;b&gt;곱셈에 관련된 모듈러 산술의 성질을 이용&lt;/b&gt;하면 3 ^ 333 = 3 (mod 10)임을 알 수 있다. 따라서 3 ^333의 1의 자리수는 3임을 알 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 물론 1의 자리수가 반복되는 규칙성을 이용해서도 문제를 해결할 수 있지만, 해당 문제를 풀기 위해 사용한 모듈러 산술의 아이디어를 활용하면 1, 10, 100의 자리 등을 구할 수 있음을 알 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/수학&amp;amp;기타</category>
      <category>congruent</category>
      <category>MOD</category>
      <category>modular arithmetic</category>
      <category>나머지</category>
      <category>모듈러 산술</category>
      <category>모듈러 연산</category>
      <category>합동</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/75</guid>
      <comments>https://sskl660.tistory.com/75#entry75comment</comments>
      <pubDate>Mon, 19 Apr 2021 23:54:04 +0900</pubDate>
    </item>
    <item>
      <title>[Java]유클리드 호제법(Euclidean Algorithm)</title>
      <link>https://sskl660.tistory.com/73</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*유클리드 호제법(Euclidean Algorithm)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;유클리드 호제법&lt;/b&gt;은 &lt;u&gt;&lt;b&gt;두 개의 자연수 or 두 개의 다항식의 최대공약수를 구하는 방법&lt;/b&gt;&lt;/u&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;84&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz9ofF/btq21NDNLeK/ptgWs5BDanMeeZGqYRkxCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz9ofF/btq21NDNLeK/ptgWs5BDanMeeZGqYRkxCK/img.png&quot; data-alt=&quot;유클리드 호제법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz9ofF/btq21NDNLeK/ptgWs5BDanMeeZGqYRkxCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz9ofF%2Fbtq21NDNLeK%2FptgWs5BDanMeeZGqYRkxCK%2Fimg.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;84&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유클리드 호제법&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ a는 b의 피제수(즉, 나누어지는 수)이므로 a &amp;gt; b이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 따라서 수식의 q는 몫, r은 나머지를 의미한다(따라서 r은 0보다 같거나 크고 b보다는 작아야 한다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 유클리드 호제법은 &lt;/span&gt;&lt;b&gt;최대공약수를 구하는데 사용&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한다고 하였다. 최대공약수는 수학적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;두 수의 모든 약수를 나열한 뒤 공통되는 약수 중 최대를 선택&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하거나&amp;nbsp;&lt;/span&gt;&lt;b&gt;소인수 분해를 이용한 방법&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 있지만,&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;유클리드 호제법을 이용하면 더 빠른 시간 안에 최대공약수를 구할 수 있다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*유클리드 호제법의 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;u&gt;&lt;b&gt;피제수가 제수에 의해 나누어 떨어진다면, 그 피제수와 제수의 최대공약수는 제수이다.&lt;/b&gt;&lt;/u&gt;&lt;b&gt; &lt;/b&gt;이 명제를 응용하면&amp;nbsp;&lt;b&gt;몇 번의 반복된 연산을 이용하여&amp;nbsp;최대공약수를 구할 수 있다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 126과 45의 최대공약수를 구하는 &lt;/span&gt;아래 예시를 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;145&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7UCC/btq21BcsItw/m2mMi4TVLGVlpdi5XiJK2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7UCC/btq21BcsItw/m2mMi4TVLGVlpdi5XiJK2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7UCC/btq21BcsItw/m2mMi4TVLGVlpdi5XiJK2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7UCC%2Fbtq21BcsItw%2Fm2mMi4TVLGVlpdi5XiJK2K%2Fimg.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;145&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 126을 45로 나누면 그 몫은 대충 q라고 생각하고(최대공약수를 구한다면 굳이 생각하지 않아도 된다), 나머지는 36이 될 것이다. &lt;b&gt;126과 45의 최대공약수는 유클리드 호제법에 의하여 45와 36의 최대공약수와 같다&lt;/b&gt;고 하였으므로, 45에 대하여 36을 나누고 나머지를 구한다. 마찬가지 방법으로 &lt;b&gt;45와 36의 최대공약수는 유클리드 호제법에 의하여 36과 9의 최대공약수와 같다&lt;/b&gt;.&amp;nbsp;&lt;u&gt;&lt;b&gt;그런데 여기서, 36은 9로 나누어 떨어지므로 36과 9의 최대 공약수는 9임을 알 수 있다.&lt;/b&gt;&lt;/u&gt; 즉, &lt;b&gt;앞선 과정을 반복하여 피제수가 제수에 의해 나누어 떨어지는 순간이 되면, 초기 두 자연수 혹은 두 다항식의 최대공약수를 구할 수 있다.&amp;nbsp;&lt;/b&gt;아래 예시도 확인 해보자. 본인이 쉽게 최대공약수를 알 수 있는 두 수를 선택해서 해당 로직을 적용해보면 더욱 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;134&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D04Mc/btq2Xa7TCKE/I0KAHyP86wkKxTDv0oumAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D04Mc/btq2Xa7TCKE/I0KAHyP86wkKxTDv0oumAK/img.png&quot; data-alt=&quot;따라서, 510과 2의 최대공약수는 2임을 알 수 있고 이에 따라 1534와 1022의 최대 공약수도 2임을 알 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D04Mc/btq2Xa7TCKE/I0KAHyP86wkKxTDv0oumAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD04Mc%2Fbtq2Xa7TCKE%2FI0KAHyP86wkKxTDv0oumAK%2Fimg.png&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;134&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;따라서, 510과 2의 최대공약수는 2임을 알 수 있고 이에 따라 1534와 1022의 최대 공약수도 2임을 알 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*유클리드 호제법을 이용한 최대공약수를 구하는 방법 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 위의 로직을 정확히 이해하였다면 재귀 혹은 반복문을 이용하여 구현은 쉽게 할 수 있다. 아래 코드를 참고하도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1618823680432&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class EuclideanAlgorithm {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt(); // 제수
		int b = sc.nextInt(); // 피제수

		System.out.println(GCD(a, b));
		sc.close();
	}

	// 유클리드 호제법을 이용한 최대 공약수 구하기
	private static int GCD(int a, int b) {
		// 나머지가 0이라면 해당 수가 최종 최대 공약수이다.
		if (a % b == 0) {
			return b;
		}
		// 그렇지 않다면 제수를 다음 피제수로, 나머지를 다음 제수로 바꾸어 재귀를 진행한다.
		else {
			return GCD(b, a % b);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/수학&amp;amp;기타</category>
      <category>euclidean algorithm</category>
      <category>java</category>
      <category>유클리드 호제법</category>
      <category>최대공약수</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/73</guid>
      <comments>https://sskl660.tistory.com/73#entry73comment</comments>
      <pubDate>Mon, 19 Apr 2021 18:16:50 +0900</pubDate>
    </item>
    <item>
      <title>[Java]플로이드-워셜 알고리즘(Floyd-Warshall Algorithm)</title>
      <link>https://sskl660.tistory.com/61</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*플로이드-워셜 알고리즘(Floyd-Warshall Algorithm)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 플로이드-워셜 알고리즘은&amp;nbsp;&lt;u&gt;&lt;b&gt;음수 사이클이 없는 그래프내의 각 모든 정점에서 각 모든 정점에 까지의 최단거리를 모두 구할 수 있는 알고리즘&lt;/b&gt;&lt;/u&gt;이다. 다익스트라 알고리즘과는 다르게&amp;nbsp;&lt;b&gt;그&lt;u&gt;래프에 &lt;b&gt;음수 사이클만 존재하지 않으면, &lt;/b&gt;음의 가중치를 갖는 간선이 존재해도 상관이 없다는&lt;/u&gt;&lt;/b&gt;&lt;u&gt; &lt;b&gt;것&lt;/b&gt;&lt;/u&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※음수 사이클 : 사이클의 모든 경로를 지나 원래 지점으로 돌아 왔을때, 최종적인 비용이 음수가 되는 경우.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;377&quot; data-origin-height=&quot;362&quot; width=&quot;311&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yr1q5/btq01rcGWVV/xUqDDfiyK9QGULzcKD5b7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yr1q5/btq01rcGWVV/xUqDDfiyK9QGULzcKD5b7K/img.png&quot; data-alt=&quot;예를 들면, 위 그림에서 1번 노드에서 2번 노드로 갔다가, 2번 노드에서 1번 노드로 가면 최종적으로 -1의 비용으로 그래프를 방문하였으므로 음수 사이클이다. 아래 경우도 마찬가지이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yr1q5/btq01rcGWVV/xUqDDfiyK9QGULzcKD5b7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYr1q5%2Fbtq01rcGWVV%2FxUqDDfiyK9QGULzcKD5b7K%2Fimg.png&quot; data-origin-width=&quot;377&quot; data-origin-height=&quot;362&quot; width=&quot;311&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예를 들면, 위 그림에서 1번 노드에서 2번 노드로 갔다가, 2번 노드에서 1번 노드로 가면 최종적으로 -1의 비용으로 그래프를 방문하였으므로 음수 사이클이다. 아래 경우도 마찬가지이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*플로이드-워셜 알고리즘의 이해&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 플로이드-워셜 알고리즘은 &lt;b&gt;다이나믹 프로그래밍 기법을 사용한 알고리즘&lt;/b&gt;이고,&amp;nbsp;&lt;u&gt;&lt;b&gt;인접 행렬을 이용&lt;/b&gt;&lt;/u&gt;하여 각 노드간 최소 비용을 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 플로이드-워셜 알고리즘은 &lt;u&gt;&lt;b&gt;모든 노드에서, 모든 노드로 가는 최소 비용을 단계적으로 갱신하면서 진행되는 알고리즘&lt;/b&gt;&lt;/u&gt;이다. 여기서 '단계적으로 갱신한다'란, &lt;b&gt;&lt;u&gt;노드에서 노드로 가는 간선의 개수가 0개에서, N개(총 노드의 개수 만큼 간선을 선택)까지 몇 개의 간선을 거쳐서 해당 노드로 가는지를 모두 고려&lt;/u&gt;&lt;/b&gt;한다는 이야기이다. 아래 그래프를 바탕으로 이해해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;606&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHMfed/btq2C4OyBvv/h7fVvaGsFfeQxCVkh6gKxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHMfed/btq2C4OyBvv/h7fVvaGsFfeQxCVkh6gKxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHMfed/btq2C4OyBvv/h7fVvaGsFfeQxCVkh6gKxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHMfed%2Fbtq2C4OyBvv%2Fh7fVvaGsFfeQxCVkh6gKxk%2Fimg.png&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;606&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;우선,&amp;nbsp;&lt;b&gt;0개의 간선을 거쳐서 모든 노드에서 모든 노드로 가는 경우&lt;/b&gt;를 생각해보자.&amp;nbsp;&lt;b&gt;0개의 간선을 거쳐서 모든 노드에서 모든 노드로 가는 방법은 &lt;/b&gt;&lt;u&gt;&lt;b&gt;자기 자신에서 자기 자신의 노드로 가는 경우&lt;/b&gt;&lt;/u&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;밖에 없다. 따라서,&amp;nbsp;&lt;b&gt;&lt;u&gt;초기 인접 행렬의 값은 자기 자신에서 자기 자신으로 가는 경우(=0)를 제외하고는 다른 노드로 갈 수 있는 방법이 없으므로 모두 매우 큰값으로 초기화&lt;/u&gt;&lt;/b&gt;해준다(N개의 정점을 모두 거쳐서 해당 정점으로 가더라도 그것보다 더 큰 값을 초기화 해주어야 한다). 그렇다면 인접행렬은 아래와 같은 값을 가지게 될 것이다(편의상 큰 값은 INF로 표시하겠다).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;160&quot; data-origin-height=&quot;95&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4uqFc/btq2IhZLAO8/XaInIQiompkXKJO53llG5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4uqFc/btq2IhZLAO8/XaInIQiompkXKJO53llG5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4uqFc/btq2IhZLAO8/XaInIQiompkXKJO53llG5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4uqFc%2Fbtq2IhZLAO8%2FXaInIQiompkXKJO53llG5K%2Fimg.png&quot; data-origin-width=&quot;160&quot; data-origin-height=&quot;95&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그 다음은&amp;nbsp;&lt;b&gt;1개의 간선을 거쳐서 모든 노드에서 노드로 가는 경우&lt;/b&gt;를 생각해보자.&amp;nbsp;&lt;b&gt;1개의 간선을 거쳐서 모든 노드로 가는 방법은, 말 그대로 &lt;/b&gt;&lt;b&gt;&lt;u&gt;주어진 그래프의 간선의 연결상태를 고려하라는&lt;/u&gt;&lt;u&gt; 것&lt;/u&gt;&lt;/b&gt;이다. 물론 &lt;b&gt;노드에서 노드로가는 간선이 여러가지 인 경우&lt;/b&gt;가 존재한다면,&amp;nbsp;&lt;b&gt;그 간선 중 최소 비용인 것을 선택&lt;/b&gt;하면 된다.&amp;nbsp;&lt;b&gt;보통 여기까지가 플로이드 관련 알고리즘 문제에서 초기화 단계에 속한다.&lt;/b&gt; 즉, 위 그림 그대로 간선의 연결 상태를 고려하여 인접행렬을 초기화하면 다음과 같을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;126&quot; data-origin-height=&quot;104&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wfA0m/btq2C4uiK1w/mDoXmSPtJCb1HZpF1rSi9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wfA0m/btq2C4uiK1w/mDoXmSPtJCb1HZpF1rSi9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wfA0m/btq2C4uiK1w/mDoXmSPtJCb1HZpF1rSi9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwfA0m%2Fbtq2C4uiK1w%2FmDoXmSPtJCb1HZpF1rSi9k%2Fimg.png&quot; data-origin-width=&quot;126&quot; data-origin-height=&quot;104&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이렇게&amp;nbsp;&lt;b&gt;간선 0개를 거친 경우, 1개를 거친 경우, ..., N개를 거친 경우의 최소 거리 비용을 비교하면서 인접행렬(각 정점에서 정점까지의 거리 비용을 나타냄)을 갱신하는 것&lt;/b&gt;이 &lt;b&gt;플로이드 알고리즘의 매커니즘&lt;/b&gt;이다.&amp;nbsp;&lt;b&gt;&lt;u&gt;어차피 연결되어 있지 않는 노드는 초기에 매우 큰값(INF)으로 초기화되어 있을 것이고, 간선의 개수를 차례로 고려하면서 최소 비용이 고려될 것이므로 노드에서 노드로 가는 거리는 항상 최소인 상태를 유지할 것&lt;/u&gt;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그 다음은 &lt;b&gt;2개의 간선을 거쳐서 모든 노드에서 노드로 가는 경우&lt;/b&gt;를 생각해보자. 2개의 간선을 거쳐서 다른 노드로 가는 것을 고려하기 가장 쉬운 방법은 무엇일까? 여기에서 플로이드 알고리즘의 구현 아이디어를 얻을 수 있는데, 그것은 바로 &lt;b&gt;특정 노드을 거쳐서 해당 노드로 가는 것&lt;/b&gt;이다. 예를 들어 아래 그림처럼 0번 정점을 기준으로 2번 노드에 대해서 생각해보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q9LWW/btq2EhNufie/wrPrYaNkXhKuK7NbcKxGz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q9LWW/btq2EhNufie/wrPrYaNkXhKuK7NbcKxGz1/img.png&quot; data-alt=&quot;2번 노드에서 0번 노드를 거쳐서 0번 노드로 가는 방법(2개의 간선을 지난다). 이때 값은 7이므로, 기존 값과 다른점이 없으므로 갱신이 일어나지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q9LWW/btq2EhNufie/wrPrYaNkXhKuK7NbcKxGz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq9LWW%2Fbtq2EhNufie%2FwrPrYaNkXhKuK7NbcKxGz1%2Fimg.png&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2번 노드에서 0번 노드를 거쳐서 0번 노드로 가는 방법(2개의 간선을 지난다). 이때 값은 7이므로, 기존 값과 다른점이 없으므로 갱신이 일어나지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bifwaH/btq2Hw36csy/llAG57CCmLkaxt48viyJ7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bifwaH/btq2Hw36csy/llAG57CCmLkaxt48viyJ7k/img.png&quot; data-alt=&quot;2번 노드에서 0번 노드를 거쳐서 1번노드로 가는법. 이때 총 비용은 12이고, 기존의 비용은 3이므로 갱신이 일어나지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bifwaH/btq2Hw36csy/llAG57CCmLkaxt48viyJ7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbifwaH%2Fbtq2Hw36csy%2FllAG57CCmLkaxt48viyJ7k%2Fimg.png&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2번 노드에서 0번 노드를 거쳐서 1번노드로 가는법. 이때 총 비용은 12이고, 기존의 비용은 3이므로 갱신이 일어나지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fv8XI/btq2DFHOIgP/16j9NemaB7fbHgkWC8WIB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fv8XI/btq2DFHOIgP/16j9NemaB7fbHgkWC8WIB1/img.png&quot; data-alt=&quot;2번 노드에서 0번 노드를 거쳐서 2번노드로 가는법. 이때 총 비용은 14이고, 기존의 비용은 0이므로 갱신이 일어나지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fv8XI/btq2DFHOIgP/16j9NemaB7fbHgkWC8WIB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFv8XI%2Fbtq2DFHOIgP%2F16j9NemaB7fbHgkWC8WIB1%2Fimg.png&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2번 노드에서 0번 노드를 거쳐서 2번노드로 가는법. 이때 총 비용은 14이고, 기존의 비용은 0이므로 갱신이 일어나지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/70C5w/btq2JlN84oF/IARUg0tYbAb6KdF4jQDWzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/70C5w/btq2JlN84oF/IARUg0tYbAb6KdF4jQDWzK/img.png&quot; data-alt=&quot;2번 노드에서 0번 노드를 거쳐서 3번노드로 가는법. 이때 총 비용은 9이고, 기존의 비용은 10이므로 9로 갱신된다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/70C5w/btq2JlN84oF/IARUg0tYbAb6KdF4jQDWzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F70C5w%2Fbtq2JlN84oF%2FIARUg0tYbAb6KdF4jQDWzK%2Fimg.png&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2번 노드에서 0번 노드를 거쳐서 3번노드로 가는법. 이때 총 비용은 9이고, 기존의 비용은 10이므로 9로 갱신된다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L8F9v/btq2HIcdoN7/5a3eg31UdaeghUgByowpl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L8F9v/btq2HIcdoN7/5a3eg31UdaeghUgByowpl1/img.png&quot; data-alt=&quot;2번 노드에서 0번 노드를 거쳐서 4번노드로 가는법. 이때 총 비용은 8이고, 기존의 비용은 INF(갈수 없음)이므로 8로 갱신된다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L8F9v/btq2HIcdoN7/5a3eg31UdaeghUgByowpl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL8F9v%2Fbtq2HIcdoN7%2F5a3eg31UdaeghUgByowpl1%2Fimg.png&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;566&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2번 노드에서 0번 노드를 거쳐서 4번노드로 가는법. 이때 총 비용은 8이고, 기존의 비용은 INF(갈수 없음)이므로 8로 갱신된다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, 그림과 같은 방법을&amp;nbsp;&lt;b&gt;모든 노드에 대해서 똑같이 고려해주는 것&lt;/b&gt;이다.&lt;b&gt; 이렇게 N개의 간선, 즉, N개의 노드를 거쳐서 가는 경우까지 차례로 모두 고려해 준다면, &lt;u&gt;간선 0개 ~ N개를 거쳐서 해당 노드로 가는 비용 중 최솟값을 모두 고려가 가능&lt;/u&gt;&lt;/b&gt;하다는 것을 알 수 있다. 위의 그림을 바탕으로 2번 노드의 값들이 어떻게 갱신되었는지 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;106&quot; data-origin-height=&quot;96&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J1QPd/btq2Jzeu5xx/Sh2KRwwzdi1Z8UP7wjYiJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J1QPd/btq2Jzeu5xx/Sh2KRwwzdi1Z8UP7wjYiJk/img.png&quot; data-alt=&quot;당연히 나머지 노드도 마찬가지 방식으로 갱신된 것이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J1QPd/btq2Jzeu5xx/Sh2KRwwzdi1Z8UP7wjYiJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ1QPd%2Fbtq2Jzeu5xx%2FSh2KRwwzdi1Z8UP7wjYiJk%2Fimg.png&quot; data-origin-width=&quot;106&quot; data-origin-height=&quot;96&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;당연히 나머지 노드도 마찬가지 방식으로 갱신된 것이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 사실 자신의 노드에서 자신의 노드로 가는 간선은 문제에서 주어지지 않는 이상 0개이므로 설명 중 모순인 부분이 존재하지만, 이해를 조금 더 쉽게 돕기 위해 일관적이지 않게 설명을 해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*플로이드-워셜 알고리즘의 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 위의 내용만 정확히 이해했다면, 여타 다이나믹 프로그래밍 방식이 굉장히 간결한 코드를 이끌어 낸 것 처럼 플로이드 워셜 알고리즘의 코드도 굉장히 간결하게 표현된다는 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618493925583&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/*
sample input(첫 번째 숫자는 노드의 개수, 두 번째 숫자는 간선의 개수 이다).
5
8
0 1 5
0 4 1
0 2 7
0 3 2
1 2 3
1 3 6
2 3 10
3 4 4
 */
public class 플로이드 {
	static int N, M;
	static int[][] dist;

	public static void main(String[] args) throws NumberFormatException, IOException {
		// 초기화
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		N = Integer.parseInt(br.readLine());
		M = Integer.parseInt(br.readLine());
		// 플로이드 초기 거리 테이블 초기화
		dist = new int[N][N];
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				// 자기 자신으로 가는 길은 최소 비용이 0이다.
				if (i == j) {
					dist[i][j] = 0;
					continue;
				}
				// 자기 자신으로 가는 경우를 제외하고는 매우 큰 값(N개의 노드를 모두 거쳐서 가더라도 더 큰 값).
				dist[i][j] = 100_000_000;
			}
		}

		for (int i = 0; i &amp;lt; M; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			int cost = Integer.parseInt(st.nextToken());

			// 가는 경로가 하나가 아닐 수 있다. 따라서 그 중 최소 비용을 저장해두면 된다.
			dist[a][b] = Math.min(dist[a][b], cost);
			dist[b][a] = Math.min(dist[b][a], cost);
		}

		// 플로이드 워셜 알고리즘
		// 노드를 1개부터 N개까지 거쳐가는 경우를 모두 고려한다.
		for (int k = 0; k &amp;lt; N; k++) {
			// 노드 i에서 j로 가는 경우.
			for (int i = 0; i &amp;lt; N; i++) {
				for (int j = 0; j &amp;lt; N; j++) {
					// k번째 노드를 거쳐가는 비용이 기존 비용보다 더 작은 경우 갱신
					// 또는 연결이 안되어있던 경우(INF) 연결 비용 갱신.
					dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
				}
			}
		}

		// 출력
		for (int i = 0; i &amp;lt; N; i++) {
			for (int j = 0; j &amp;lt; N; j++) {
				// 연결이 안되어 있는 경우
				if (dist[i][j] == 100_000_000) {
					System.out.print(&quot;INF &quot;);
				} else {
					System.out.print(dist[i][j] + &quot; &quot;);
				}
			}
			System.out.println();
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;88&quot; data-origin-height=&quot;95&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYPXkA/btq2IRzIO4q/TwEt7ruQK1QpinkJHHZd4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYPXkA/btq2IRzIO4q/TwEt7ruQK1QpinkJHHZd4k/img.png&quot; data-alt=&quot;최종 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYPXkA/btq2IRzIO4q/TwEt7ruQK1QpinkJHHZd4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYPXkA%2Fbtq2IRzIO4q%2FTwEt7ruQK1QpinkJHHZd4k%2Fimg.png&quot; data-origin-width=&quot;88&quot; data-origin-height=&quot;95&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최종 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*시간복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 구현을 확인하면 알 수 있겠지만, 시간 복잡도를 구하는 방법은 매우 간단한다. &lt;b&gt;모든 노드(V)에 대해서, V x V 행렬을 갱신해주는 연산을 진행하므로 O(V^3)의 시간복잡도&lt;/b&gt;를 갖는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 무려 O(V^3)라는 시간 복잡도를 갖기 때문에,&amp;nbsp;&lt;b&gt;입력의 크기가 100 정도만 되어도 백 만번의 연산이 수행&lt;/b&gt;되어야 한다. 따라서,&amp;nbsp;&lt;b&gt;플로이드 알고리즘을 사용하는 경우는 입력의 크기를 주의깊게 살펴보도록 하자.&lt;/b&gt;&lt;/p&gt;</description>
      <category>Algorithm/그래프&amp;amp;최단경로</category>
      <category>Algorithm</category>
      <category>Floyd</category>
      <category>Floyd-WarShall</category>
      <category>java</category>
      <category>플로이드</category>
      <category>플로이드-와샬 알고리즘</category>
      <category>플로이드-워셜 알고리즘</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/61</guid>
      <comments>https://sskl660.tistory.com/61#entry61comment</comments>
      <pubDate>Thu, 15 Apr 2021 22:44:08 +0900</pubDate>
    </item>
    <item>
      <title>[Java]크루스칼 알고리즘(Kruskal Algorithm)</title>
      <link>https://sskl660.tistory.com/72</link>
      <description>&lt;p&gt;&lt;b&gt;*크루스칼&amp;nbsp;알고리즘(Kruskal&amp;nbsp;Algorithm)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; &lt;b&gt;크루스칼 알고리즘&lt;/b&gt;은&amp;nbsp;&lt;b&gt;그래프에서 최소 비용 신장 부분 트리(최소 신장 트리 : Minimum Spanning Tree(MST))를 찾는 알고리즘&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;※ 최소 신장 트리, 신장 트리와 같은 용어를 조금 더 자세히 알고 싶다면 위키백과를 참고하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%8B%A0%EC%9E%A5_%EB%B6%80%EB%B6%84_%EA%B7%B8%EB%9E%98%ED%94%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ko.wikipedia.org/wiki/%EC%8B%A0%EC%9E%A5_%EB%B6%80%EB%B6%84_%EA%B7%B8%EB%9E%98%ED%94%84&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618466304244&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;신장 부분 그래프 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 그래프의 신장 부분 나무 그래프 왼쪽의 그래프는 오른쪽과 같이 총 8개의 신장 부분 나무 그래프들을 갖는다. 그래프 이론에서, 신장 부분 그래프(身長部分grap&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%8B%A0%EC%9E%A5_%EB%B6%80%EB%B6%84_%EA%B7%B8%EB%9E%98%ED%94%84&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EC%8B%A0%EC%9E%A5_%EB%B6%80%EB%B6%84_%EA%B7%B8%EB%9E%98%ED%94%84&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iUOVc/hyJScbBTty/OAZfvcpZSsQEjRRAptibNK/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%8B%A0%EC%9E%A5_%EB%B6%80%EB%B6%84_%EA%B7%B8%EB%9E%98%ED%94%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%8B%A0%EC%9E%A5_%EB%B6%80%EB%B6%84_%EA%B7%B8%EB%9E%98%ED%94%84&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iUOVc/hyJScbBTty/OAZfvcpZSsQEjRRAptibNK/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;신장 부분 그래프 - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;위키백과, 우리 모두의 백과사전. 그래프의 신장 부분 나무 그래프 왼쪽의 그래프는 오른쪽과 같이 총 8개의 신장 부분 나무 그래프들을 갖는다. 그래프 이론에서, 신장 부분 그래프(身長部分grap&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*크루스칼 알고리즘의 매커니즘&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 크루스칼 알고리즘은 기본적으로&amp;nbsp;&lt;b&gt;그리디한 선택을 바탕으로 알고리즘을 진행&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;(1) 주어진 그래프의 모든 간선에 대해서, &lt;b&gt;간선의 연결비용을 낮은 순으로 오름 차순 정렬&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;(2)&amp;nbsp;&lt;b&gt;정렬된 간선 순서대로 선택하면서, 간선의 양 끝 정점을 Union 한다. &lt;u&gt;단, 이때 선택된 두 정점이 같은 집합에 속해있다면 사이클(cycle)이 있다고 판단하고 포함시키지 않는다.&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;이러한 매커니즘을 바탕으로 최종 선택된 간선을 연결한 것이 최소 비용 신장트리이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;※&lt;/b&gt;&amp;nbsp;&lt;b&gt;크루스칼 알고리즘은 사실상 서로소 집합만 정확히 알고 있으면 매커니즘은 어렵지 않다. &lt;u&gt;서로소 집합에 대해서 먼저 명확히 이해&lt;/u&gt;하고 있어야만 한다.&lt;/b&gt; 서로소 집합에 대하여 잘 모른다면 아래 글을 참고하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href=&quot;https://sskl660.tistory.com/71?category=845232&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/71?category=845232&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618470142621&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 서로소 집합(Disjoint Set)(Union-Find)(Merge-Find Set)&quot; data-og-description=&quot;*서로소 집합(Disjoint Set) -&amp;gt; 서로소 집합 자료구조는 상호 배타적으로 이루어진 집합(서로소 집합 : 공통 원소가 없는 두 집합)을 효율적으로 표현하기 위해 만들어진 자료구조이다. -&amp;gt; 서로소 집&quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/71?category=845232&quot; data-og-url=&quot;https://sskl660.tistory.com/71&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/AwelU/hyJTItdOtq/KsXHTmESL5ui6nfRVYQxyk/img.png?width=660&amp;amp;height=173&amp;amp;face=0_0_660_173,https://scrap.kakaocdn.net/dn/bgbsCd/hyJTxrHlSH/M14GS7yZKon0gOKrenbgnk/img.png?width=660&amp;amp;height=173&amp;amp;face=0_0_660_173,https://scrap.kakaocdn.net/dn/VnMfY/hyJSiCUwDh/0YOK3eagL3p5OM59dQxk00/img.png?width=665&amp;amp;height=535&amp;amp;face=0_0_665_535&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/71?category=845232&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/71?category=845232&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/AwelU/hyJTItdOtq/KsXHTmESL5ui6nfRVYQxyk/img.png?width=660&amp;amp;height=173&amp;amp;face=0_0_660_173,https://scrap.kakaocdn.net/dn/bgbsCd/hyJTxrHlSH/M14GS7yZKon0gOKrenbgnk/img.png?width=660&amp;amp;height=173&amp;amp;face=0_0_660_173,https://scrap.kakaocdn.net/dn/VnMfY/hyJSiCUwDh/0YOK3eagL3p5OM59dQxk00/img.png?width=665&amp;amp;height=535&amp;amp;face=0_0_665_535');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Java] 서로소 집합(Disjoint Set)(Union-Find)(Merge-Find Set)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;*서로소 집합(Disjoint Set) -&amp;gt; 서로소 집합 자료구조는 상호 배타적으로 이루어진 집합(서로소 집합 : 공통 원소가 없는 두 집합)을 효율적으로 표현하기 위해 만들어진 자료구조이다. -&amp;gt; 서로소 집&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;-&amp;gt; 예를 들어 다음과 같은 그래프에서 최소 신장 트리를 찾아보도록 하자. 우선 첫 번째로,&amp;nbsp;&lt;b&gt;연결된 간선의 연결 비용이 낮은 순으로 위에서 부터 오름차순 정렬&lt;/b&gt;하고, &lt;b&gt;다음 간선을 선택할때 사이클을 판단하기 위해 서로소 집합을 활용&lt;/b&gt;하기로 하였으므로,&amp;nbsp;각 노드의 초기 집합은 아래와 같을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oIwbu/btq2HPIAP1o/XrY2PYGCkjicLaLQ60Pqi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oIwbu/btq2HPIAP1o/XrY2PYGCkjicLaLQ60Pqi0/img.png&quot; data-alt=&quot;초기 상태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oIwbu/btq2HPIAP1o/XrY2PYGCkjicLaLQ60Pqi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoIwbu%2Fbtq2HPIAP1o%2FXrY2PYGCkjicLaLQ60Pqi0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초기 상태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그 다음은 말 그대로 비용이 적은 간선의 양 끝 노드를 선택하면서&amp;nbsp;&lt;b&gt;사이클이 존재하지 않는다면 Union 및 해당 간선 선택, 존재한다면 스킵&lt;/b&gt;하는 형태로 &lt;b&gt;모든 간선에 대하여 탐색이 끝날 때 까지 동작을 반복&lt;/b&gt;하면 된다. 아래 그림들은 이 과정을 나타내는 예시이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOnNZ2/btq2ETSwMe1/ED6fenk3euObN02IKAguq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOnNZ2/btq2ETSwMe1/ED6fenk3euObN02IKAguq1/img.png&quot; data-alt=&quot;먼저, 첫 번째 간선을 선택한다. 두 노드 2, 3은 서로 독립된 집합이기 때문에 Union을 진행하고 간선도 선택한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOnNZ2/btq2ETSwMe1/ED6fenk3euObN02IKAguq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOnNZ2%2Fbtq2ETSwMe1%2FED6fenk3euObN02IKAguq1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;먼저, 첫 번째 간선을 선택한다. 두 노드 2, 3은 서로 독립된 집합이기 때문에 Union을 진행하고 간선도 선택한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/day4dh/btq2Iiw24ME/EXrFlGT0kHlvctTMWvLBw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/day4dh/btq2Iiw24ME/EXrFlGT0kHlvctTMWvLBw1/img.png&quot; data-alt=&quot;마찬가지 방법으로 두 번째 간선을 선택한다. 두 노드 1, 6은 서로 독립된 집합이므로 Union 및 간선을 선택한다.&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/day4dh/btq2Iiw24ME/EXrFlGT0kHlvctTMWvLBw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fday4dh%2Fbtq2Iiw24ME%2FEXrFlGT0kHlvctTMWvLBw1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;마찬가지 방법으로 두 번째 간선을 선택한다. 두 노드 1, 6은 서로 독립된 집합이므로 Union 및 간선을 선택한다.&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8Oz5r/btq2IgzeJQ9/j4ZHnoNXkn5mFhETClQSA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8Oz5r/btq2IgzeJQ9/j4ZHnoNXkn5mFhETClQSA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8Oz5r/btq2IgzeJQ9/j4ZHnoNXkn5mFhETClQSA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8Oz5r%2Fbtq2IgzeJQ9%2Fj4ZHnoNXkn5mFhETClQSA1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xsynm/btq2BDKbGJC/gKkenVexDd4IywGpE1EwQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xsynm/btq2BDKbGJC/gKkenVexDd4IywGpE1EwQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xsynm/btq2BDKbGJC/gKkenVexDd4IywGpE1EwQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXsynm%2Fbtq2BDKbGJC%2FgKkenVexDd4IywGpE1EwQ0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cK6ALb/btq2CDwqppU/NAjkzQGxFVnrJhwI82aLOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cK6ALb/btq2CDwqppU/NAjkzQGxFVnrJhwI82aLOK/img.png&quot; data-alt=&quot;여기까지는 앞 과정과 다른 것이 없다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cK6ALb/btq2CDwqppU/NAjkzQGxFVnrJhwI82aLOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcK6ALb%2Fbtq2CDwqppU%2FNAjkzQGxFVnrJhwI82aLOK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여기까지는 앞 과정과 다른 것이 없다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KOQt2/btq2CEvl0AV/5lepBV8T5ky6QT9pCckKT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KOQt2/btq2CEvl0AV/5lepBV8T5ky6QT9pCckKT1/img.png&quot; data-alt=&quot;5, 6번 노드를 간선에 대해서는 각 노드 5번의 최종 부모는 1, 6번의 최종 부모는 1로 두 집합이 이미 같은 집합에 속해있음을 알 수 있다. 그림에서 확인해보면 알겠지만, 두 노드를 연결하는 순간 사이클이 발생한다. 따라서, 이 경우는 그냥 스킵하면 된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KOQt2/btq2CEvl0AV/5lepBV8T5ky6QT9pCckKT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKOQt2%2Fbtq2CEvl0AV%2F5lepBV8T5ky6QT9pCckKT1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;5, 6번 노드를 간선에 대해서는 각 노드 5번의 최종 부모는 1, 6번의 최종 부모는 1로 두 집합이 이미 같은 집합에 속해있음을 알 수 있다. 그림에서 확인해보면 알겠지만, 두 노드를 연결하는 순간 사이클이 발생한다. 따라서, 이 경우는 그냥 스킵하면 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkjUhu/btq2GR77Xi6/QuPyqNCtGX2goijiM6jb4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkjUhu/btq2GR77Xi6/QuPyqNCtGX2goijiM6jb4k/img.png&quot; data-alt=&quot;나머지 노드에 대해서도 마찬가지로 진행해주면, 최종적으로 선택된 간선(빨간색)이 최소 신장트리(MST)가 됨을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkjUhu/btq2GR77Xi6/QuPyqNCtGX2goijiM6jb4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkjUhu%2Fbtq2GR77Xi6%2FQuPyqNCtGX2goijiM6jb4k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;나머지 노드에 대해서도 마찬가지로 진행해주면, 최종적으로 선택된 간선(빨간색)이 최소 신장트리(MST)가 됨을 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*크루스칼 알고리즘의 구현&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 앞서 언급한대로&amp;nbsp;&lt;b&gt;서로소 집합만 명확히 구현이 가능하다면, 크루스칼 알고리즘의 로직 자체는 크게 어렵지 않다는 것을 확인&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 위의 예시 그대로 크루스칼 알고리즘을 구현하면 아래와 같다. 보통 알고리즘 문제에서는&amp;nbsp;&lt;b&gt;정렬된 상태로 주어지지 않기 때문에, 정렬되지 않은 상태로 입력을 주고 정렬하는 로직도 추가해 주었다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618473839965&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.Scanner;

/*
sample input(첫 줄의 첫 숫자는 정점의 개수, 두 번째 숫자는 간선의 개수).
6 9
1 6 5
2 4 6
1 2 7
3 5 15
5 6 9
3 4 10
1 3 11
2 3 3
4 5 7
 */

public class Kruskal {
	static int V, E;
	static int[][] graph;
	// 각 노드의 부모
	static int[] parent;
	// 최종적으로 연결된 최소 신장 트리 연결 비용.
	static int final_cost;

	public static void main(String[] args) {
		// 그래프의 연결상태(노드1, 노드2, 비용)를 초기화.
		Scanner sc = new Scanner(System.in);
		V = sc.nextInt();
		E = sc.nextInt();
		graph = new int[E][3];
		for (int i = 0; i &amp;lt; E; i++) {
			graph[i][0] = sc.nextInt();
			graph[i][1] = sc.nextInt();
			graph[i][2] = sc.nextInt();
		}
		parent = new int[V];
		final_cost = 0;

		// 간선 비용 순으로 오름차순 정렬
		Arrays.sort(graph, (o1, o2) -&amp;gt; Integer.compare(o1[2], o2[2]));

		// makeSet
		for (int i = 0; i &amp;lt; V; i++) {
			parent[i] = i;
		}
		// 낮은 비용부터 크루스칼 알고리즘 진행
		for (int i = 0; i &amp;lt; E; i++) {
			// 사이클이 존재하지 않는 경우에만 간선을 선택한다(여기서는 최종 비용만 고려하도록 하겠다).
			if (find(graph[i][0] - 1) != find(graph[i][1] - 1)) {
				System.out.println(&quot;&amp;lt;선택된 간선&amp;gt;&quot;);
				System.out.println(Arrays.toString(graph[i]));
				union(graph[i][0] - 1, graph[i][1] - 1);
				final_cost += graph[i][2];
				System.out.println(&quot;&amp;lt;각 노드가 가리키고 있는 부모&amp;gt;&quot;);
				System.out.println(Arrays.toString(parent) + &quot;\n&quot;);
				continue;
			}
		}
		
		System.out.println(&quot;최종 비용 : &quot; + final_cost);
		sc.close();
	}

	private static void union(int a, int b) {
		a = find(a);
		b = find(b);
		if (a &amp;gt; b) {
			parent[a] = b;
		} else {
			parent[b] = a;
		}
	}

	private static int find(int x) {
		if (parent[x] == x)
			return x;
		else
			return find(parent[x]);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNGDQ6/btq2IltPEta/3tZ68DKTCNWBzMmuhk2yhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNGDQ6/btq2IltPEta/3tZ68DKTCNWBzMmuhk2yhK/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNGDQ6/btq2IltPEta/3tZ68DKTCNWBzMmuhk2yhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNGDQ6%2Fbtq2IltPEta%2F3tZ68DKTCNWBzMmuhk2yhK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;※ Find 연산에서 경로 압축 기법을 사용하는 경우, 부모가 다르게 나올 수 있다. 경로 압축 기법을 명확히 이해 했다면 무슨 소리 인지 이해할 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*시간 복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 크루스칼 알고리즘은&amp;nbsp;&lt;b&gt;O(ElogV)의 시간복잡도&lt;/b&gt;를 갖는다. 간단히 말하면 &lt;b&gt;모든 가중치를 정렬하는데 걸리는 시간이 O(ElogE) 시간복잡도&lt;/b&gt;를 갖는데, &lt;b&gt;크루스칼 알고리즘에서 이 연산보다 영향력이 있는 연산은 없기 때문에 최종적으로 O(ElogE)가 걸린다고 생각&lt;/b&gt;하는 것이다. 이때, &lt;b&gt;간선의 수는 최대 V^2개가 될 수 있으므로 O(logE) = O(logV^2) = O(2logV) = O(logV)&lt;/b&gt;로도 볼 수 있고, 최종적으로 O(ElogV)의 시간 복잡도를 갖는 것이다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 크루스칼 알고리즘의 자세한 증명과 시간 복잡도 증명은 위키백과를 참고하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%81%AC%EB%9F%AC%EC%8A%A4%EC%BB%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ko.wikipedia.org/wiki/%ED%81%AC%EB%9F%AC%EC%8A%A4%EC%BB%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618474479564&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;크러스컬 알고리즘 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 컴퓨터 과학에서, 크러스컬 알고리즘(영어: Kruskal&amp;rsquo;s algorithm)은 최소 비용 신장 부분 트리를 찾는 알고리즘이다. 변의 개수를 E {\displaystyle E} , 꼭짓점의 개수를 &quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%ED%81%AC%EB%9F%AC%EC%8A%A4%EC%BB%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%ED%81%AC%EB%9F%AC%EC%8A%A4%EC%BB%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%81%AC%EB%9F%AC%EC%8A%A4%EC%BB%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%ED%81%AC%EB%9F%AC%EC%8A%A4%EC%BB%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;크러스컬 알고리즘 - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;위키백과, 우리 모두의 백과사전. 컴퓨터 과학에서, 크러스컬 알고리즘(영어: Kruskal&amp;rsquo;s algorithm)은 최소 비용 신장 부분 트리를 찾는 알고리즘이다. 변의 개수를 E {\displaystyle E} , 꼭짓점의 개수를&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/그래프&amp;amp;최단경로</category>
      <category>java</category>
      <category>Kruskal Algorithm</category>
      <category>Minimum Spanning Tree</category>
      <category>MST</category>
      <category>서로소 집합</category>
      <category>최소 신장 트리</category>
      <category>크루스칼 알고리즘</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/72</guid>
      <comments>https://sskl660.tistory.com/72#entry72comment</comments>
      <pubDate>Thu, 15 Apr 2021 17:15:21 +0900</pubDate>
    </item>
    <item>
      <title>[Java]서로소 집합(Disjoint Set)(Union-Find)(Merge-Find Set)</title>
      <link>https://sskl660.tistory.com/71</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*서로소 집합(Disjoint Set)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 서로소 집합 자료구조는 &lt;b&gt;상호 배타적으로 이루어진 집합(서로소 집합 : 공통 원소가 없는 두 집합)을 효율적으로 표현하기 위해 만들어진 자료구조&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 서로소 집합은&amp;nbsp;&lt;b&gt;서로 다른 두 개의 집합을 병합하는 연산(Union)(Merge)&lt;/b&gt;과&amp;nbsp;&lt;b&gt;집합의 원소가 어떤 집합에 속해 있는지 판단하는 연산(Find)&lt;/b&gt;을 기반으로 구현되기 때문에,&amp;nbsp;&lt;b&gt;Union-Find 혹은 Merge-Find Set&lt;/b&gt;이라고도 불린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 서로소 집합을 구현하는 방법은&amp;nbsp;&lt;b&gt;연결 리스트를 이용하는 방법&lt;/b&gt;과,&amp;nbsp;&lt;b&gt;트리를 이용하는 방법&lt;/b&gt;이 있는데, 이 글에서는 트리를 이용하는 방법에 대해서만 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*서로소 집합의 단순 구현(트리)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 서로소 집합은 &lt;b&gt;기본적으로 총 3가지 연산(MakeSet, Find, Union)으로 구성&lt;/b&gt;되어 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) MakeSet 연산 &lt;/b&gt;: 대상&amp;nbsp;원소들을 우선&amp;nbsp;&lt;b&gt;모두 각각 독립된 집합으로 분리하는 과정&lt;/b&gt;이다.&amp;nbsp;&lt;b&gt;&lt;u&gt;서로소 집합은 대상 원소가 각각 어떤 집합에 포함되어 있는지 번호를 주어 표시&lt;/u&gt;&lt;/b&gt;한다. 우선 처음 주어지는 원소들은 따로 집합이 정해져 있지 않기 때문에,&amp;nbsp;&lt;u&gt;&lt;b&gt;자기 자신의 원소 번호를 자신이 속해있는 집합으로 초기화&lt;/b&gt;&lt;/u&gt;하는 과정이라고 생각하면 된다. 앞으로 1, 2, 3, 4, 5원소를 기준으로 예를 들어 서로소 집합을 구현해보도록 하겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;173&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mo698/btq2C5d9wp5/GKkU6KqaF14amKhSNwtom0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mo698/btq2C5d9wp5/GKkU6KqaF14amKhSNwtom0/img.png&quot; data-alt=&quot;초기 원소는 자기 자신의 번호를 자신이 속한 집합이라고 인식한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mo698/btq2C5d9wp5/GKkU6KqaF14amKhSNwtom0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMo698%2Fbtq2C5d9wp5%2FGKkU6KqaF14amKhSNwtom0%2Fimg.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;173&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;초기 원소는 자기 자신의 번호를 자신이 속한 집합이라고 인식한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;자기 자신이 가리키는 대상 = 자신이 속한 집합&lt;/b&gt;이 되기 때문에,&amp;nbsp;&lt;b&gt;자기 자신이 가리키는 대상&lt;/b&gt;을 &lt;b&gt;parent(부모)&lt;/b&gt;&lt;b&gt;라고 표현&lt;/b&gt;하기도 한다. 이를 바탕으로 코드를 구현하면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1618407071681&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;

public class DisjointSet {
	public static void main(String[] args) {
		int[] parent = MakeSet(5);
		// 각 인덱스(=노드)는 자기 자신을 가리키고 있다
		System.out.println(Arrays.toString(parent));
	}

	private static int[] MakeSet(int size) {
		// 각 인덱스에 번호가 대응하도록 사이즈를 1더하여 배열 선언.
		int[] arr = new int[size + 1];
		for (int i = 0; i &amp;lt; arr.length; i++) {
			arr[i] = i;
		}
		return arr;
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;168&quot; data-origin-height=&quot;20&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1Vk8I/btq2ybtrAur/Raz7n6dVm0EVl8LDaRwosk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1Vk8I/btq2ybtrAur/Raz7n6dVm0EVl8LDaRwosk/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1Vk8I/btq2ybtrAur/Raz7n6dVm0EVl8LDaRwosk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1Vk8I%2Fbtq2ybtrAur%2FRaz7n6dVm0EVl8LDaRwosk%2Fimg.png&quot; data-origin-width=&quot;168&quot; data-origin-height=&quot;20&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) Union 연산, Find 연산&lt;/b&gt; : 다음은 &lt;u&gt;&lt;b&gt;서로소 집합을 하나의 집합으로 합쳐주는 연산&lt;/b&gt;&lt;/u&gt;&lt;span style=&quot;color: #333333;&quot;&gt;인&lt;/span&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Union 연산&lt;/b&gt;과&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;대상 원소가 어떤 대상을 가리키는지, 즉&amp;nbsp;&lt;u&gt;어떤 집합에 포함되어 있는지(부모가 누구인지)&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;를 파악하는 연산&lt;/u&gt;&lt;/b&gt;인&amp;nbsp;&lt;b&gt;Find 연산&lt;/b&gt;을 구현해보자. 두 연산은 구현 상에서 서로 밀접한 관계가 있기 때문에, 동시에 이해하는 것이 낫다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 먼저 Union 연산을 살펴보자. &lt;b&gt;서로 다른 두 원소를 같은 집합으로 포함&lt;/b&gt;시키기 위해서는 어떤 방법을 사용할까? 정답은&amp;nbsp;&lt;b&gt;두 원소가 모두 같은 부모(parent)를 가리키도록 값을 변경&lt;/b&gt;해주면 된다. &lt;b&gt;이 경우&amp;nbsp;보통 두 원소중 작은 값을 기준으로 가리키는 부모를 통일 시켜준다(자세한 내용은 뒤의 최적화와 관련된 내용 참고!).&lt;/b&gt; 이를 테면 원소 1, 2를 같은 집합으로 속하게 만들고 싶다면 아래와 같은 그림이 될 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;187&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKIiVd/btq2C4GpkIm/KHtIvLZL6lV49CMzqcKFu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKIiVd/btq2C4GpkIm/KHtIvLZL6lV49CMzqcKFu1/img.png&quot; data-alt=&quot;1, 2가 같은 집합에 속해있다면, 원소 2는 1을 부모로 가리켜야 한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKIiVd/btq2C4GpkIm/KHtIvLZL6lV49CMzqcKFu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKIiVd%2Fbtq2C4GpkIm%2FKHtIvLZL6lV49CMzqcKFu1%2Fimg.png&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;187&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1, 2가 같은 집합에 속해있다면, 원소 2는 1을 부모로 가리켜야 한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그림과 같은 상황이라면, 각 원소는 {1, 1, 3, 4, 5}와 같은 형태로 가리키는 대상이 설정되어 있을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;위와 같은 상황&lt;/b&gt;을 이해하면, Find 연산을 구현하는 것은 쉽다. 찾고자 하는 원소가 자신의 인덱스 값과 같다면, 즉&amp;nbsp;&lt;b&gt;자기 자신이 부모인 상황&lt;/b&gt;이라면&amp;nbsp;&lt;b&gt;그 값이 그 집합을 대표하는 번호&lt;/b&gt;일 것이다. 그렇지 않다면,&amp;nbsp;&lt;b&gt;지금 원소가 가리키는 값을 재귀적으로 다시 Find 함수에 넘겨주어 부모 노드까지 탐색&lt;/b&gt;을 하면 된다. 즉, 재귀함수를 이용하여 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618408592136&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static int find(int[] parent, int x) {
  // 만일, 찾는 대상과 인덱스 번호가 같다면 그 인덱스(=노드)가 해당 집합의 부모이다.
  if(parent[x] == x)
	return x;
  // 그렇지 않다면, 해당 인덱스가 가리키는 값(부모 노드)을 따라 최종 부모노드까지 탐색한다.
  else
 	return find(parent, parent[x]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; Find 연산을 구현했으니, 이제 Union 연산을 구현하면 될 것 같지만 한가지 주의할 점이 있다. 그것은 &lt;b&gt;Union 연산은 서로 다른 '두 집합'을 합치는 연산이라는 것&lt;/b&gt;이다. 예를들어 지금까지의 논리로 앞서 만든 집합의 상태에서 3을 1, 2의 집합에 포함시키고, 4, 5를 또 다른 집합으로 만들었다고 가정해보자. 그렇다면 다음과 같은 그림이 될 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;205&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgzEXM/btq2y3aQLW1/4NDNuZCOsDKzKVn6OdeitK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgzEXM/btq2y3aQLW1/4NDNuZCOsDKzKVn6OdeitK/img.png&quot; data-alt=&quot;원소 1, 2, 3이 같은 집합이고 4, 5가 같은 집합이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgzEXM/btq2y3aQLW1/4NDNuZCOsDKzKVn6OdeitK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgzEXM%2Fbtq2y3aQLW1%2F4NDNuZCOsDKzKVn6OdeitK%2Fimg.png&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;205&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;원소 1, 2, 3이 같은 집합이고 4, 5가 같은 집합이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그렇다면 이 상태에서 원소 3, 5를 이용하여 두 집합을 합치는 경우 다음과 같은 실수를 범해서는 안된다.&lt;/p&gt;
&lt;pre id=&quot;code_1618410248794&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static void union(int[] parent, int a, int b) {
	// 각 대상이 가리키는 부모를 구한다.
	int o1 = find(parent, a);
	int o2 = find(parent, b);
	// 부모가 작은 쪽으로 흡수해야 하므로 분기문을 나눈다.
	if (o1 &amp;gt; o2) {
		// a원소의 부모를 b원소의 부모로 바꾼다.
		parent[a] = o2;
	} else {
		// b원소의 부모를 a원소의 부모로 바꾼다.
		parent[b] = o1;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이렇게 하게 된다면&amp;nbsp;&lt;b&gt;원소 5에 대해서만 3이 포함된 집합의 부모를 가리키게 된다.&lt;/b&gt; 즉 다음과 같은 그림의 상황이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;286&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ducQV6/btq2CIXRYOO/IKe3TPs04zyFkmELJgBsz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ducQV6/btq2CIXRYOO/IKe3TPs04zyFkmELJgBsz1/img.png&quot; data-alt=&quot;두 집합이 합쳐진 것이 아니라, 원소만 해당 집합으로 편입 되었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ducQV6/btq2CIXRYOO/IKe3TPs04zyFkmELJgBsz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FducQV6%2Fbtq2CIXRYOO%2FIKe3TPs04zyFkmELJgBsz1%2Fimg.png&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;286&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;두 집합이 합쳐진 것이 아니라, 원소만 해당 집합으로 편입 되었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;&lt;u&gt;서로소 집합에서 '합치기 연산'은 앞서 말했지만 '두 집합을 합치는 연산'이다.&lt;/u&gt; 따라서,&amp;nbsp;&lt;u&gt;두 집합의 부모(대표자)가 다른 부모를 가리키도록 로직을 설계&lt;/u&gt;&lt;/b&gt;해주어야 한다! 그렇다면 아래와 같은 코드로 구현할 수 있을 것이고, 그림은 다음과 같은 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1618410520530&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static void union(int[] parent, int a, int b) {
	// 각 집합을 대표하는 부모가 다른 부모로 편입 되어야 한다. 원소가 편입되어서는 안된다.
	a = find(parent, a);
	b = find(parent, b);
	if (a &amp;gt; b) {
		parent[a] = b;
	} else {
		parent[b] = a;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;233&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRixxv/btq2CHYXCWf/7skeQDjuEJEazN7Z9HtGb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRixxv/btq2CHYXCWf/7skeQDjuEJEazN7Z9HtGb1/img.png&quot; data-alt=&quot;두 서로소 집합을 하나의 집합으로 합친 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRixxv/btq2CHYXCWf/7skeQDjuEJEazN7Z9HtGb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRixxv%2Fbtq2CHYXCWf%2F7skeQDjuEJEazN7Z9HtGb1%2Fimg.png&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;233&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;두 서로소 집합을 하나의 집합으로 합친 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 모든 과정을 하나의 코드로 합치면 아래와 같고, 앞서 합친 순서대로 결과를 출력해보면 다음과 같을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1618410659173&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;

public class DisjointSet {
	public static void main(String[] args) {
		int[] parent = MakeSet(5);
		// 각 인덱스(=노드)는 자기 자신을 가리키고 있다
		System.out.println(Arrays.toString(parent));

		union(parent, 1, 2);
		System.out.println(Arrays.toString(parent));
		union(parent, 2, 3);
		System.out.println(Arrays.toString(parent));
		union(parent, 4, 5);
		System.out.println(Arrays.toString(parent));
		union(parent, 3, 5);
		System.out.println(Arrays.toString(parent));
		System.out.println(find(parent, 1));
		System.out.println(find(parent, 2));
		System.out.println(find(parent, 3));
		System.out.println(find(parent, 4));
		System.out.println(find(parent, 5));
	}

	private static void union(int[] parent, int a, int b) {
		// 각 집합을 대표하는 부모가 다른 부모로 편입 되어야 한다. 원소가 편입되어서는 안된다.
		a = find(parent, a);
		b = find(parent, b);
		if (a &amp;gt; b) {
			parent[a] = b;
		} else {
			parent[b] = a;
		}
	}

	private static int find(int[] parent, int x) {
		// 만일, 찾는 대상과 인덱스 번호가 같다면 그 인덱스(=노드)가 해당 집합의 부모이다.
		if (parent[x] == x)
			return x;
		// 그렇지 않다면, 해당 인덱스가 가리키는 값(부모 노드)을 따라 최종 부모노드까지 탐색한다.
		else
			return find(parent, parent[x]);
	}

	private static int[] MakeSet(int size) {
		// 각 인덱스에 번호가 대응하도록 사이즈를 1더하여 배열 선언.
		int[] arr = new int[size + 1];
		for (int i = 0; i &amp;lt; arr.length; i++) {
			arr[i] = i;
		}
		return arr;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;173&quot; data-origin-height=&quot;192&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xbY77/btq2CjRvPt6/GuEFH4Enk9cdMJJH4BmTG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xbY77/btq2CjRvPt6/GuEFH4Enk9cdMJJH4BmTG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xbY77/btq2CjRvPt6/GuEFH4Enk9cdMJJH4BmTG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxbY77%2Fbtq2CjRvPt6%2FGuEFH4Enk9cdMJJH4BmTG0%2Fimg.png&quot; data-origin-width=&quot;173&quot; data-origin-height=&quot;192&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 알고리즘 문제 풀이시 주의점 :&amp;nbsp;여기서&amp;nbsp;&lt;b&gt;parent 배열은 '각 원소의 부모'&lt;/b&gt;를 나타내는 것 뿐이지&amp;nbsp;&lt;u&gt;&lt;b&gt;각 원소가 실제로 어떤 집합에 속해있는지를 표현해주지 않는다.&lt;/b&gt;&lt;/u&gt;&amp;nbsp;&lt;b&gt;각 원소가 어떤 집합에 속해있는지를 파악하기 위해서는 반드시 Find 연산을 사용&lt;/b&gt;해야만 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*시간복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 우선 기본적으로&amp;nbsp;Union 연산과&amp;nbsp;Find 연산을 살펴보면&amp;nbsp;&lt;b&gt;Union 연산내에서 가장 큰 영향을 미치는 연산이 Find 연산&lt;/b&gt;임을 알 수 있다. 즉,&amp;nbsp;&lt;u&gt;&lt;b&gt;Union 연산과 Find 연산의 시간 복잡도는 동일&lt;/b&gt;&lt;/u&gt;하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 트리의 원소가 편중되어 있는 형태라면, 매 연산마다 노드의 끝까지 탐색해야 되기 때문에&amp;nbsp;&lt;b&gt;O(n)의 시간복잡도&lt;/b&gt;를 가지게 될 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;535&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj30AT/btq2Ehyt2fP/oh74DlkYLFB2boRaROqGl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj30AT/btq2Ehyt2fP/oh74DlkYLFB2boRaROqGl1/img.png&quot; data-alt=&quot;트리가 편중된 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj30AT/btq2Ehyt2fP/oh74DlkYLFB2boRaROqGl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj30AT%2Fbtq2Ehyt2fP%2Foh74DlkYLFB2boRaROqGl1%2Fimg.png&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;535&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;트리가 편중된 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*서로소 집합 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 앞선 서로소 집합의 성능을 개선하기 위하여, Union 연산 혹은 Find 연산에서 각각 연산의 성능을 향상시키는 방법이 존재한다. 두 방법 중 하나를 선택하면 되지만, &lt;b&gt;보통 경로 압축(Path Compression)기법을 기반으로한 Find 연산에서의 최적화 방법을 자주 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) Union 연산에서의 최적화&lt;b&gt;&lt;b&gt;(Union by Rank)&lt;/b&gt;&lt;/b&gt; :&lt;/b&gt; 두 집합을 서로 합치는 과정에서 아무런 기준없이 합치게 된다면 &lt;b&gt;트리의 깊이가 깊어질 수도 있는 문제가 발생&lt;/b&gt;한다. 예를 들어, 원소 1, 2가 같은 집합이고 3, 4, 5가 같은 집합인 경우 1, 2 집합을 3, 4, 5 집합에 합치는 경우는 문제가 발생하지 않는다. 즉,&amp;nbsp;&lt;b&gt;원소의 개수가 적은 집합이 많은 집합에 편입된다면 문제가 발생하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;318&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcZlls/btq2DrOTJhs/XojgtS1K5HKXSUdXfA3Y91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcZlls/btq2DrOTJhs/XojgtS1K5HKXSUdXfA3Y91/img.png&quot; data-alt=&quot;원소의 개수가 적은 집합이 흡수되는 경우 전체 트리의 깊이는 변화하지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcZlls/btq2DrOTJhs/XojgtS1K5HKXSUdXfA3Y91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcZlls%2Fbtq2DrOTJhs%2FXojgtS1K5HKXSUdXfA3Y91%2Fimg.png&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;318&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;원소의 개수가 적은 집합이 흡수되는 경우 전체 트리의 깊이는 변화하지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;하지만 &lt;b&gt;반대로 원소의 개수가 많은 집합이 적은 집합으로 편입된다면 트리의 깊이가 점점 깊어지는 문제가 발생&lt;/b&gt;한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;318&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bD3m79/btq2yaBoCq7/ZwPSacszRnp8EIfUTQNgok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bD3m79/btq2yaBoCq7/ZwPSacszRnp8EIfUTQNgok/img.png&quot; data-alt=&quot;원소의 개수가 많은 집합이 흡수되는 경우 전체 트리의 깊이는 점점 커진다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bD3m79/btq2yaBoCq7/ZwPSacszRnp8EIfUTQNgok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbD3m79%2Fbtq2yaBoCq7%2FZwPSacszRnp8EIfUTQNgok%2Fimg.png&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;318&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;원소의 개수가 많은 집합이 흡수되는 경우 전체 트리의 깊이는 점점 커진다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이렇게&amp;nbsp;&lt;b&gt;&lt;u&gt;깊이가 점점 깊어지면, Find 연산이 재귀의 형태로 이루어져 있으므로 Find 연산을 수행할 때 최악의경우 O(n)의 시간복잡도&lt;/u&gt;&lt;/b&gt;를 갖는다. 이를 해결하기 위하여 &lt;b&gt;Rank를 이용한 Union&lt;/b&gt;&amp;nbsp;&lt;b&gt;연산&lt;b&gt;(Union by Rank)&lt;/b&gt;&lt;/b&gt;&lt;b&gt;을 진행&lt;/b&gt;한다. 이 연산은 간단히 말하면, 기존에 두 집합을 합하는 과정에서 &lt;b&gt;부모 노드의 번호가 작은 쪽으로 편입&lt;/b&gt;&lt;b&gt;하는 대신, 각 집합의 크기(트리의 깊이)를 Rank라는 값으로 기억해두고 앞서 언급한대로 Rank가 더 큰 쪽으로 트리를 편입시키는 방법&lt;/b&gt;을 사용한다. &lt;b&gt;이 경우 시간 복잡도를 O(logN)까지 줄일 수 있다.&lt;/b&gt; 이 글에서는 Rank를 이용한 방법으로 따로 구현을 하지는 않겠다. 개념만 알아두도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2)&amp;nbsp;Find 연산에서의 최적화(경로 압축 : Path Compression) &lt;/b&gt;: 앞서 Rank를 이용한 방법보다&amp;nbsp;&lt;b&gt;구현이 더 쉽기 때문에&lt;/b&gt;&amp;nbsp;서로소 집합 연산의 성능을 향상 시킬때 자주 사용되는 방법이다. 이 방법은&amp;nbsp;&lt;u&gt;&lt;b&gt;Find 연산이 재귀의 형태로 구현된 점, 매 탐색마다 트리의 부모 노드까지 탐색하는 비효율을 방지&lt;/b&gt;&lt;/u&gt;한다는 두 가지 아이디어를 바탕으로 구현할 수 있다. 예를 들어 다음과 같은 그림에서&amp;nbsp;&lt;b&gt;각 원소는 각자의 부모를 가리키고 있지만, &lt;u&gt;실상 Find 연산을 사용하면 그 부모가 모두 똑같은 1임&lt;/u&gt;&lt;/b&gt;을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;443&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s0SFj/btq2C38zugX/zn0ugnMLlvpK2nSuakplg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s0SFj/btq2C38zugX/zn0ugnMLlvpK2nSuakplg0/img.png&quot; data-alt=&quot;파란색 : 각 원소가 가리키는 대상(parent 배열), 빨간색 : Find 연산을 수행하면 실제로 각 원소가 가리키는 최종 부모.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s0SFj/btq2C38zugX/zn0ugnMLlvpK2nSuakplg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs0SFj%2Fbtq2C38zugX%2Fzn0ugnMLlvpK2nSuakplg0%2Fimg.png&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;443&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파란색 : 각 원소가 가리키는 대상(parent 배열), 빨간색 : Find 연산을 수행하면 실제로 각 원소가 가리키는 최종 부모.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;따라서, 이러한 점을 활용하여&amp;nbsp;&lt;b&gt;&lt;u&gt;재귀를 반환(return)하는 과정에서 각 부모를 최종 부모로 바꿔주면서 반환하여 각 원소의 최종 부모를 통일 시켜준다.&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;412&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7ystN/btq2E8OQ047/dqN1kk7IokqmsolQ4B4Jp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7ystN/btq2E8OQ047/dqN1kk7IokqmsolQ4B4Jp0/img.png&quot; data-alt=&quot;Find 연산을 반환하는 과정에서 각 부모를 최종 부모로 갱신 시켜준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7ystN/btq2E8OQ047/dqN1kk7IokqmsolQ4B4Jp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7ystN%2Fbtq2E8OQ047%2FdqN1kk7IokqmsolQ4B4Jp0%2Fimg.png&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;412&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Find 연산을 반환하는 과정에서 각 부모를 최종 부모로 갱신 시켜준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그렇다면 트리는 최종적으로 다음과 같은 구조를 가지게 될 것이다. 다만 이 그림에서 알 수 있듯이, &lt;b&gt;Find 연산은&amp;nbsp;낮은 깊이에서 탐색을 시작한다면, 더 깊은 대상은 최적화가 되지 않는다는 단점&lt;/b&gt;이 존재한다.(만일, 5가 아닌 3에 대해서만 Find 연산을 수행한 경우를 생각해보자).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;439&quot; data-origin-height=&quot;352&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL8U7O/btq2CFfO6M2/KHTi8cug88KJH2jqItABs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL8U7O/btq2CFfO6M2/KHTi8cug88KJH2jqItABs0/img.png&quot; data-alt=&quot;경로 압축을 통한 최종 트리 구조.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL8U7O/btq2CFfO6M2/KHTi8cug88KJH2jqItABs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL8U7O%2Fbtq2CFfO6M2%2FKHTi8cug88KJH2jqItABs0%2Fimg.png&quot; data-origin-width=&quot;439&quot; data-origin-height=&quot;352&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;경로 압축을 통한 최종 트리 구조.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, find 연산를 다음과 같이 개선하여 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618415345084&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static int find(int[] parent, int x) {
	// 만일, 찾는 대상과 인덱스 번호가 같다면 그 인덱스(=노드)가 해당 집합의 부모이다.
	if (parent[x] == x)
		return x;
	// 경로 압축
	else
		return parent[x] = find(parent, parent[x]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;이 경우 시간 복잡도를 O(&amp;alpha;(n))까지 줄일 수 있다. 이는 사실상 O(1)의 시간복잡도와 유사&lt;/b&gt;하다고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ &amp;alpha;(n) 이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 굳이 알 필요는 없지만, 간단히 서술하자면 여기서 &amp;alpha;(n)는 &lt;b&gt;아커만 함수의 역함수&lt;/b&gt;이다. 간단히 말하면 아커만 함수는 작은 입력으로 매우 큰 증가를 만드는 함수인데(우리가 아는 팩토리얼 연산보다도 더 심하다!), 이 함수의 역함수 이기 때문에, 반대로&amp;nbsp;&lt;b&gt;어떤 큰 입력이 와도 작은 값을 도출할 것&lt;/b&gt;(보통 &amp;alpha;(n)은 실용적으로 5보다 작다고 알려져 있다)이다. 따라서 기존 서로소 집합 연산에 비하여 더 빠른 연산이 가능한 것이다. 자세한 내용은 아커만 함수 위키백과의 '역함수' 파트를 참고하도록 하자. &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%95%84%EC%BB%A4%EB%A7%8C_%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ko.wikipedia.org/wiki/%EC%95%84%EC%BB%A4%EB%A7%8C_%ED%95%A8%EC%88%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618415891852&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;아커만 함수 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 계산 가능성 이론에서, 빌헬름 아커만의 이름을 딴 아커만 함수(Ackermann函數, 영어: Ackermann function)는 원시 재귀 함수가 아닌 전역적인 재귀 함수(계산가능 함수)&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%95%84%EC%BB%A4%EB%A7%8C_%ED%95%A8%EC%88%98&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EC%95%84%EC%BB%A4%EB%A7%8C_%ED%95%A8%EC%88%98&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%95%84%EC%BB%A4%EB%A7%8C_%ED%95%A8%EC%88%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%95%84%EC%BB%A4%EB%A7%8C_%ED%95%A8%EC%88%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;아커만 함수 - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;위키백과, 우리 모두의 백과사전. 계산 가능성 이론에서, 빌헬름 아커만의 이름을 딴 아커만 함수(Ackermann函數, 영어: Ackermann function)는 원시 재귀 함수가 아닌 전역적인 재귀 함수(계산가능 함수)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 두 기법을 동시에 사용하는 것은?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 서로소 집합 연산의 성능을 향상 시키기 위한 방법이 2가지나 존재하기 때문에, 그렇다면 이 2가지 방법을 동시에 사용하면 성능이 좋지 않을까? 라는 의문을 가질 수 있다. 일리 있는 말이지만, Rank 관리 기법은&amp;nbsp;&lt;b&gt;트리의 깊이를 다루는 방법&lt;/b&gt;이었고, 경로 압축 기법에서는&amp;nbsp;&lt;b&gt;경로를 압축할 때 마다 트리의 깊이가 시시각각으로 변화&lt;/b&gt;하였다. &lt;b&gt;그런데 이렇게 경로압축을 통해 시시각각 변화하는 트리의 깊이를 따로 관리하고, Rank 관리 기법에 그 깊이들을 다시 활용하는 방식은 굉장히 복잡&lt;/b&gt;하다. 따라서 보통 두 방법 중 하나만 사용하더라도, 코딩테스트 대비 성능 면에서는 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*총정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 경로 압축 기법을 적용하고, 각 코드를 최대한 간소화 시켜 코드를 작성하면 서로소 집합은 다음과 같이 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618416318520&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package pr;

import java.util.Arrays;

public class DisjointSet {
	static int[] parent;

	public static void main(String[] args) {
		// makeSet
		parent = new int[5];
		// 각 인덱스(=노드)는 자기 자신을 가리키고 있다
		parent = MakeSet(5);
		System.out.println(Arrays.toString(parent));
		
		// 1이 포함된 집합, 2가 포함된 집합 합치기.
		union(1, 2);
		System.out.println(Arrays.toString(parent));
		// 2가 포함된 집합, 3이 포함된 집합 합치기.
		union(2, 3);
		System.out.println(Arrays.toString(parent));
		// 4가 포함된 집합, 5가 포함된 집합 합치기.
		union(4, 5);
		System.out.println(Arrays.toString(parent));
		// 3이 포함된 집합, 5가 포함된 집합 합치기.
		union(3, 5);
		System.out.println(Arrays.toString(parent));
		
		// Find 연산을 통한 각 노드가 속한 집합 확인.
		System.out.println(find(1));
		System.out.println(find(2));
		System.out.println(find(3));
		System.out.println(find(4));
		System.out.println(find(5));
	}

	// Union
	private static void union(int a, int b) {
		// 각 집합을 대표하는 부모가 다른 부모로 편입 되어야 한다. 원소가 편입되어서는 안된다.
		a = find(a);
		b = find(b);
		// 일반적으로 더 작은 값으로 다른 집합이 편입되도록 한다.
		if (a &amp;gt; b) {
			parent[a] = b;
		} else {
			parent[b] = a;
		}
	}

	// Find
	private static int find(int x) {
		// 만일, 찾는 대상과 인덱스 번호가 같다면 그 인덱스(=노드)가 해당 집합의 부모이다.
		if (parent[x] == x)
			return x;
		// 경로 압축
		else
			return parent[x] = find(parent[x]);
	}

	// makeSet
	private static int[] MakeSet(int size) {
		// 각 인덱스에 번호가 대응하도록 사이즈를 1더하여 배열 선언.
		int[] arr = new int[size + 1];
		for (int i = 0; i &amp;lt; arr.length; i++) {
			arr[i] = i;
		}
		return arr;
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/자료구조 for Algorithm</category>
      <category>Disjoint set</category>
      <category>java</category>
      <category>Merge Find Set</category>
      <category>union find</category>
      <category>서로소 집합</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/71</guid>
      <comments>https://sskl660.tistory.com/71#entry71comment</comments>
      <pubDate>Thu, 15 Apr 2021 11:08:39 +0900</pubDate>
    </item>
    <item>
      <title>[Database]서브 쿼리(MySQL)</title>
      <link>https://sskl660.tistory.com/69</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*서브 쿼리(SubQuery)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서브 쿼리&lt;/b&gt;란 말 그대로&amp;nbsp;&lt;b&gt;다른 쿼리 내부에 포함되어 있는 쿼리&lt;/b&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;&lt;u&gt;SELECT 문을 이용한 데이터 조회&lt;/u&gt;&lt;/b&gt;&lt;u&gt;는&amp;nbsp;결과적으로&lt;/u&gt;&lt;b&gt;&lt;u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;검색 조건을 만족하는 또 하나의 테이블을 만들어 내는 것&lt;/u&gt;&lt;/b&gt;을 의미한다고 볼 수 있다. 이러한 점을 활용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;검색 결과 테이블을 활용하여 다시 쿼리를 진행하는 것&lt;/b&gt;&lt;/u&gt;을 서브 쿼리라고 생각하면 이해하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*서브 쿼리의 종류&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 서브쿼리는 쿼리의 위치가 어디에 있느냐에 따라서 세 가지 종류로 나눌 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 중첩 서브 쿼리(Nested Subquery) : WHERE절에 사용하는 서브 쿼리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 인라인 뷰(Inline View) : FROM절에 사용하는 서브 쿼리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 스칼라 서브 쿼리(Scalar Subquery) : SELECT절에 사용하는 서브 쿼리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*MySQL Sample Database&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 아래 데이터베이스는 MySQL에서 기본적으로 제공해주는 연습용 SQL 테이블 데이터이다. 해당 데이터를 이용하여 쿼리를 연습해보도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot;&gt;www.mysqltutorial.org/mysql-sample-database.aspx/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618205600881&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MySQL Sample Database&quot; data-og-description=&quot;This page provides you with a MySQL sample database that helps you to practice with MySQL effectively and quickly. You can download the sample database and load it into your MySQL Server.&quot; data-og-host=&quot;www.mysqltutorial.org&quot; data-og-source-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; data-og-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xIiRf/hyJQEdEFux/wor1JX7p0Dirbjxo81FjA1/img.png?width=701&amp;amp;height=560&amp;amp;face=0_0_701_560&quot;&gt;&lt;a href=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; data-source-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xIiRf/hyJQEdEFux/wor1JX7p0Dirbjxo81FjA1/img.png?width=701&amp;amp;height=560&amp;amp;face=0_0_701_560');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*서브 쿼리의 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 예를 들어 특정 이름을 가진 고객의 주문 정보를 조회한다고 생각해보자. 먼저 Join을 이용하면 다음과 같은 방법을 사용해볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618154772298&quot; class=&quot;sql&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 이름이 &quot;Atelier graphique&quot;인 고객의 주문 정보
select orderNumber, orderDate
from customers c join orders o
on c.customerNumber = o.customerNumber
where customerName = &quot;Atelier graphique&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;하지만, 서브 쿼리를 이용하면&amp;nbsp;&lt;b&gt;테이블을 굳이 조합하지 않더라도 해당 고객의 정보를 서브 쿼리를 이용하여 가져 온 뒤 쿼리를 연결하여 정보를 조회&lt;/b&gt;할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618154772298&quot; class=&quot;sql&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 이름이 &quot;Atelier graphique&quot;인 고객의 주문 정보
select orderNumber, orderDate
from orders
where customerNumber = (select customerNumber
			from customers
                      where customerName = &quot;Atelier graphique&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;u&gt;&lt;b&gt;어떤 검색 조건을 만족하는 테이블을 조회하는 방법은 이와 같이 여러가지 방법이 사용&lt;/b&gt;될 수 있다.&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;따라서, 적절한 경우에 적절한 쿼리를 사용하여 테이블을 조회하는 방법을 고민하는 것이 바람직하다(상황에 따라 어떤 쿼리를 쓰느냐에 따라 효율이 달라질 수 있다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*중첩 서브 쿼리(Nested Subquery)&lt;/b&gt; : &lt;span style=&quot;color: #333333;&quot;&gt;WHERE절에 사용하는 서브 쿼리.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 단일 행 서브쿼리 :&amp;nbsp;서브 쿼리의 결과가 1개의 행을 도출&lt;/b&gt;하는 경우 단일 행 서브쿼리라고 한다. 위의 예시는 단일 행 서브쿼리라고 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618154772298&quot; class=&quot;sql&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 전체 상품의 평균 가격보다 가격이 높은 주문 정보
select *
from orderdetails
where priceEach &amp;gt; (select avg(buyPrice)
		from products)
order by priceEach;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 다중 행 서브쿼리 : 서브 쿼리의 결과가 여러개의 행을 도출&lt;/b&gt;하는 경우 다중 행 서브쿼리라고 한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1618193310147&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- IN : 서브 쿼리 결과중 하나의 값이라도 같은 값이 존재한다면
-- 구매 가격이 40 ~ 45사이인 물건들의 주문 내역
select orderNumber, productCode, priceEach
from orderdetails
where productCode in (select productCode
			from products
			where buyPrice between 40 and 45);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다중 행 서브 쿼리를 사용하는 경우, 서브 쿼리로 출력되는 결과행이 다수이기 때문에&amp;nbsp;&lt;b&gt;IN, ANY, ALL과 같은 복수 행 연산자를 사용&lt;/b&gt;하여야 한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1618194283281&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- ANY : 서브 쿼리 결과에 대하여 어느 하나의 값이라도 만족하면 결과 반환.
-- 전체 물건의 구매 가격에 대하여 하나라도 주문 가격이 낮은 경우
select orderNumber, productCode, priceEach
from orderdetails
where priceEach &amp;lt; any (select buyPrice
		from products);

-- ALL : 서브 쿼리 결과에 대하여 모든 값이 만족해야만 결과 반환.
-- 전체 물건의 구매 가격에 대하여 항상 주문 가격이 높은 경우
select orderNumber, productCode, priceEach
from orderdetails
where priceEach &amp;gt; all (select buyPrice
		from products);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 다중 열 서브쿼리 : 서브 쿼리의 결과가 여러 열을&lt;/b&gt; &lt;b&gt;도출&lt;/b&gt;하는 경우 다중 열 서브쿼리라고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1618195005101&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 사무실 코드가 1인 사원들의 매니저, 직업이 일치하는 사원들의 사번과 이름
select employeeNumber, lastName, firstName
from employees
where (reportsTo, jobTitle) in (select reportsTo, jobTitle
				from employees
				where officeCode = 1);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*인라인 뷰(Inline View) &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;: FROM절에 사용하는 서브 쿼리.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 앞서 &lt;b&gt;SELECT 문을 이용한 데이터 조회&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;는&amp;nbsp;결과적으로&lt;/span&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;검색 조건을 만족하는 또 하나의 테이블을 만들어 내는 것&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;을 의미한다고 하였었다. 인라인 뷰는 이러한 점을 적극 활용하여&amp;nbsp;&lt;b&gt;FROM절에 동적으로 생성된 테이블&lt;/b&gt;을 배치하여 질의를 수행하는 방법이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618201431558&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 모든 고객의 평균 신용 한도보다 신용 한도가 큰 고객들의 담당 직원
select *
from (select customerNumber, salesRepEmployeeNumber, creditLimit
	  from customers
	  where creditLimit &amp;gt; (select avg(creditLimit) from customers)) a join employees e
on a.salesRepEmployeeNumber = e.employeeNumber
order by creditLimit;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;151&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/srGX0/btq2lBdMINe/FwoeuCqRkxdal1g1mSYtGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/srGX0/btq2lBdMINe/FwoeuCqRkxdal1g1mSYtGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/srGX0/btq2lBdMINe/FwoeuCqRkxdal1g1mSYtGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsrGX0%2Fbtq2lBdMINe%2FFwoeuCqRkxdal1g1mSYtGk%2Fimg.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;151&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*스칼라 서브 쿼리(Scalar Subquery) &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;: SELECT절에 사용하는 서브 쿼리.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 마찬가지로 데이터 조회를 통해 만들어진 결과를 SELECT 절에 배치하여 결과를 형성한다. 원리를 바탕으로 생각하면 크게 이해하기 어렵지 않다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618203536915&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 고객번호가 120 ~ 150번인 고객들의 고객 정보와 담당 직원 이름
select customerNumber, customerName, salesRepEmployeeNumber, 
(select lastName from employees where customers.salesRepEmployeeNumber = employees.employeeNumber) as Counselor
from customers
where customerNumber between 120 and 150;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;209&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckv6RL/btq2kDbYawe/73c5fyX8WEOse37qdgkmc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckv6RL/btq2kDbYawe/73c5fyX8WEOse37qdgkmc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckv6RL/btq2kDbYawe/73c5fyX8WEOse37qdgkmc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckv6RL%2Fbtq2kDbYawe%2F73c5fyX8WEOse37qdgkmc0%2Fimg.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;209&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*서브 쿼리와 DDL, DML&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 쿼리의 결과가 또 하나의 테이블을 반환한다는 점을 이용하여 CREATE, INSERT, UPDATE, DELETE문에 다양하게 활용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618204228825&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- CREATE 문에서 테이블을 복사하는 경우
create table student2
select * from student;

create table student2
select studentNo, studentName, grade from student;

-- 테이블의 구조만 복사하고 싶은 경우(WHERE절을 활용한다).
create table student2
select * from student
where false;

-- INSERT 문에서 테이블 데이터를 복사하는 경우
insert into student2
select * from student;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Web/Database</category>
      <category>Database</category>
      <category>mysql</category>
      <category>SUB QUERY</category>
      <category>서브 쿼리</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/69</guid>
      <comments>https://sskl660.tistory.com/69#entry69comment</comments>
      <pubDate>Mon, 12 Apr 2021 14:33:28 +0900</pubDate>
    </item>
    <item>
      <title>[Database]조인과 집합연산(MySQL)</title>
      <link>https://sskl660.tistory.com/68</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*조인(Join)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;b&gt;조인&lt;/b&gt;이란 &lt;b&gt;둘 이상의 테이블에서 데이터가 필요한 경우, 여러 테이블을 조합하여 데이터를 사용&lt;/b&gt;하기 위해 사용되는 연산이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 기본적으로 RDBMS는&amp;nbsp;&lt;b&gt;중복 데이터를 최소화하기 위하여 데이터를 쪼개서 저장&lt;/b&gt;하기 때문에, 이러한 조인 연산이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*MySQL Sample Database&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 아래 데이터베이스는 MySQL에서 기본적으로 제공해주는 연습용 SQL 테이블 데이터이다. 해당 데이터를 이용하여 쿼리를 연습해보도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.mysqltutorial.org/mysql-sample-database.aspx/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618137214632&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MySQL Sample Database&quot; data-og-description=&quot;This page provides you with a MySQL sample database that helps you to practice with MySQL effectively and quickly. You can download the sample database and load it into your MySQL Server.&quot; data-og-host=&quot;www.mysqltutorial.org&quot; data-og-source-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; data-og-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xIiRf/hyJQEdEFux/wor1JX7p0Dirbjxo81FjA1/img.png?width=701&amp;amp;height=560&amp;amp;face=0_0_701_560&quot;&gt;&lt;a href=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xIiRf/hyJQEdEFux/wor1JX7p0Dirbjxo81FjA1/img.png?width=701&amp;amp;height=560&amp;amp;face=0_0_701_560');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL Sample Database&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page provides you with a MySQL sample database that helps you to practice with MySQL effectively and quickly. You can download the sample database and load it into your MySQL Server.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.mysqltutorial.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*INNER JOIN&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 가장 일반적인 조인으로써, &lt;b&gt;조건에 맞는 &lt;/b&gt;&lt;/span&gt;&lt;b&gt;테이블의 교집합&lt;/b&gt;을 추출해내는 조인이라고 생각하면 이해하기 쉽다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bagHvW/btq2iWa68Fs/sgGzHcQ0EYOrAsCSr3Ylfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bagHvW/btq2iWa68Fs/sgGzHcQ0EYOrAsCSr3Ylfk/img.png&quot; data-alt=&quot;서로 연관된 내용을 검색하고 출력한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bagHvW/btq2iWa68Fs/sgGzHcQ0EYOrAsCSr3Ylfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbagHvW%2Fbtq2iWa68Fs%2FsgGzHcQ0EYOrAsCSr3Ylfk%2Fimg.png&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서로 연관된 내용을 검색하고 출력한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 조인 조건 &lt;/b&gt;&lt;b&gt;: 두 테이블을 연결시키는 기준을 설정&lt;/b&gt;한다. 이 기준에 따라서 크게&amp;nbsp;&lt;b&gt;동등 조인&lt;/b&gt;과&amp;nbsp;&lt;b&gt;비동등 조인&lt;/b&gt;으로 조인이 분류되기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 동등 조인&lt;b&gt;(EQUI JOIN)&lt;/b&gt; : 테이블의 기본키(Primary Key), 외래키(Foreign Key) 관계를 기반&lt;/b&gt;으로 테이블을 조합하는 방식이다. 쉽게 말해 서로 같은 값을 갖는 조건을 활용하여 테이블을 조합한다.&lt;/p&gt;
&lt;pre id=&quot;code_1618139652765&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- customer 테이블의 기본키인 customerNumber와 orders 테이블의 외래키인 customerNumber를 이용하여 테이블을 조인
select *
from customers join orders
on customers.customerNumber = orders.customerNumber;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;조인은 테이블을 합치는 과정이기 때문에, &lt;b&gt;중복되는 열에 대하여 어떤 테이블의 소유인지 명시&lt;/b&gt;를 해주어야 한다. 위와 같이 테이블이름을 모두 적어주는 방법도 있지만, &lt;b&gt;별칭을 활용하는 방법&lt;/b&gt;도 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618139942942&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- customer 테이블의 기본키인 customerNumber와 orders 테이블의 외래키인 customerNumber를 이용하여 테이블을 조인
select *
from customers c join orders o
on c.customerNumber = o.customerNumber;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위와 같이 테이블을 조인하는 경우, &lt;b&gt;해당 조인 조건에 대응하는 모든 경우의 수를 산출&lt;/b&gt;한다. 이를&amp;nbsp;&lt;b&gt;CROSS JOIN 혹은 Cartesian Product&lt;/b&gt;라고도 하며 일반적인 경우에는 모든 경우의 수를 산출하는 경우가 거의 없으므로 자주 사용하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;154&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdAiXT/btq2hCEnGwr/0Xu0bR2b75Pllkd9H8Zd60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdAiXT/btq2hCEnGwr/0Xu0bR2b75Pllkd9H8Zd60/img.png&quot; data-alt=&quot;customer 테이블&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdAiXT/btq2hCEnGwr/0Xu0bR2b75Pllkd9H8Zd60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdAiXT%2Fbtq2hCEnGwr%2F0Xu0bR2b75Pllkd9H8Zd60%2Fimg.png&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;154&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;customer 테이블&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;129&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4XMZo/btq2hIEHAUa/HOrzKoQS0iFO9iJyTdRWp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4XMZo/btq2hIEHAUa/HOrzKoQS0iFO9iJyTdRWp0/img.png&quot; data-alt=&quot;order테이블&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4XMZo/btq2hIEHAUa/HOrzKoQS0iFO9iJyTdRWp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4XMZo%2Fbtq2hIEHAUa%2FHOrzKoQS0iFO9iJyTdRWp0%2Fimg.png&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;129&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;order테이블&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;188&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dymjbz/btq2gQC6q5v/dHshRt8fU7WxIr7jGYGvZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dymjbz/btq2gQC6q5v/dHshRt8fU7WxIr7jGYGvZ0/img.png&quot; data-alt=&quot;Cartesian Product(Cross Join)결과. 고객의 주문 수에 따라 고객의 정보가 중복되는 것을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dymjbz/btq2gQC6q5v/dHshRt8fU7WxIr7jGYGvZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdymjbz%2Fbtq2gQC6q5v%2FdHshRt8fU7WxIr7jGYGvZ0%2Fimg.png&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;188&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cartesian Product(Cross Join)결과. 고객의 주문 수에 따라 고객의 정보가 중복되는 것을 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;따라서 보통 INNER JOIN은&amp;nbsp;&lt;b&gt;WHERE 절과 함께 사용&lt;/b&gt;하여&amp;nbsp;&lt;b&gt;원하는 검색 결과만 조회&lt;/b&gt;하는 경우가 많다.&lt;/p&gt;
&lt;pre id=&quot;code_1618140987192&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 103번 고객의 주문 내역
select c.customerNumber, c.customerName, o.orderNumber, o.orderDate
from customers c join orders o
on c.customerNumber = o.customerNumber
where c.customerNumber = 103;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;78&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LWJ3F/btq2njcmVRT/NoKWmdm1PuMmAKYgEyeDSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LWJ3F/btq2njcmVRT/NoKWmdm1PuMmAKYgEyeDSk/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LWJ3F/btq2njcmVRT/NoKWmdm1PuMmAKYgEyeDSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLWJ3F%2Fbtq2njcmVRT%2FNoKWmdm1PuMmAKYgEyeDSk%2Fimg.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;78&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1618142503908&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 103번 ~ 120번 고객의 주문 내역
select c.customerNumber, c.customerName, o.orderNumber, o.orderDate
from customers c join orders o
on c.customerNumber = o.customerNumber
where c.customerNumber between 103 and 120;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;195&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dODNWB/btq2heX1uyz/HCBEOc8ZSMvyITiDhZt2V1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dODNWB/btq2heX1uyz/HCBEOc8ZSMvyITiDhZt2V1/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dODNWB/btq2heX1uyz/HCBEOc8ZSMvyITiDhZt2V1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdODNWB%2Fbtq2heX1uyz%2FHCBEOc8ZSMvyITiDhZt2V1%2Fimg.png&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;195&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;만일,&amp;nbsp;&lt;b&gt;두 테이블에 대하여 같은 컬럼명을 갖는 모든 열에 대한 동등 조인 결과 값을 검색&lt;/b&gt;하고 싶다면,&amp;nbsp;&lt;b&gt;NATURAL JOIN을 사용&lt;/b&gt;하면 된다. MySQL 데이터 베이스에는 해당 조건을 보여 줄만한 예제 데이터가 존재하지 않지만, 예를 들어 A반과 B반 학생 각각의 국영수 성적을 담은 테이블이 있다고 할 때, A, B반에서 모든 성적이 똑같은 학생을 확인해보고자 할때 NATURAL JOIN을 활용할 수 있다. 사실상 사용할 일이 거의 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 비동등 조인(NON-EQUI&lt;span&gt;&amp;nbsp;&lt;/span&gt;JOIN) : 테이블의 기본키, 외래키외에 다른 column을 사용하여 조인 조건으로 사용하는 조인을 말한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-&amp;gt; 예를 들어 다음과 같은 상품의 등급을 가격에 따라 분류한 테이블이 존재한다고 생각해보자&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;158&quot; data-origin-height=&quot;77&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnBP9g/btq2npQ6swW/qOnATbmnwLeQpfsyjQpZ80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnBP9g/btq2npQ6swW/qOnATbmnwLeQpfsyjQpZ80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnBP9g/btq2npQ6swW/qOnATbmnwLeQpfsyjQpZ80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnBP9g%2Fbtq2npQ6swW%2FqOnATbmnwLeQpfsyjQpZ80%2Fimg.png&quot; data-origin-width=&quot;158&quot; data-origin-height=&quot;77&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 비동등 조인을 이용하여 상품별 등급을 출력해줄 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618142185619&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 각 상품의 퀄리티를 다음과 같은 조인 조건을 만족하며 조합하라.
select productCode, productName, buyPrice, grade
from products join quality
on buyPrice &amp;gt;= low and buyPrice &amp;lt;= high
order by buyPrice;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;198&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBhEr5/btq2lBxBdZ8/PTeQLv54tsfRrlBZzAgk21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBhEr5/btq2lBxBdZ8/PTeQLv54tsfRrlBZzAgk21/img.png&quot; data-alt=&quot;위의 기준과 같이 상품의 등급이 분류되었음을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBhEr5/btq2lBxBdZ8/PTeQLv54tsfRrlBZzAgk21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBhEr5%2Fbtq2lBxBdZ8%2FPTeQLv54tsfRrlBZzAgk21%2Fimg.png&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;198&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위의 기준과 같이 상품의 등급이 분류되었음을 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*OUTER JOIN&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; INNER JOIN의 경우 &lt;b&gt;교집합을 추출하는 방식&lt;/b&gt;이기 때문에, &lt;b&gt;다른 쪽 테이블에 데이터가 존재하지 않는 경우 해당 데이터는 고려하지 않는 문제점&lt;/b&gt;이 존재한다. 이를 해결하기 위해 사용할 수 있는 것이 OUTER JOIN이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 예를 들어 MySQL의 데이터에서 고객(customers)에 대한 담당 직원(employees)이 존재하지 않는 경우가 존재한다.&lt;/p&gt;
&lt;pre id=&quot;code_1618145072204&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select customerNumber, customerName, salesRepEmployeeNumber
from customers;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKYtWC/btq2kru7BAb/StdG9oPuKIwfCS2sY05hz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKYtWC/btq2kru7BAb/StdG9oPuKIwfCS2sY05hz1/img.png&quot; data-alt=&quot;담당 직원이 존재하지 않는 고객&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKYtWC/btq2kru7BAb/StdG9oPuKIwfCS2sY05hz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKYtWC%2Fbtq2kru7BAb%2FStdG9oPuKIwfCS2sY05hz1%2Fimg.png&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;담당 직원이 존재하지 않는 고객&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;따라서, 고객 테이블과 직원 테이블을 INNER JOIN하는 경우, Havel &amp;amp; Zbyszek Co에 대한 정보가 사라진 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618145054701&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select customerNumber, customerName, salesRepEmployeeNumber
from employees join customers
on employeeNumber = salesRepEmployeeNumber
order by customerNumber;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bogrY0/btq2lpRoksL/sCHGsXMPX9X2X66r8z21C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bogrY0/btq2lpRoksL/sCHGsXMPX9X2X66r8z21C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bogrY0/btq2lpRoksL/sCHGsXMPX9X2X66r8z21C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbogrY0%2Fbtq2lpRoksL%2FsCHGsXMPX9X2X66r8z21C0%2Fimg.png&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;203&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;이때,&amp;nbsp;&lt;b&gt;OUTER JOIN을 활용하면 해당 고객도 포함하여 검색 결과를 도출&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618145131618&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select customerNumber, customerName, salesRepEmployeeNumber
from customers left outer join employees
on employeeNumber = salesRepEmployeeNumber
order by customerNumber;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;201&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bISSJB/btq2pkaW0vf/7AhDaN1SylvbpkBNusoDa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bISSJB/btq2pkaW0vf/7AhDaN1SylvbpkBNusoDa1/img.png&quot; data-alt=&quot;담당직원이 존재하지 않는 경우도 출력해준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bISSJB/btq2pkaW0vf/7AhDaN1SylvbpkBNusoDa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbISSJB%2Fbtq2pkaW0vf%2F7AhDaN1SylvbpkBNusoDa1%2Fimg.png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;201&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;담당직원이 존재하지 않는 경우도 출력해준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이처럼 OUTER JOIN은 다음과 같은 벤다이어 그램을 가진다고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;260&quot; data-origin-height=&quot;223&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bExXLP/btq2hCxEqTD/hmlxggEktOXJqxgIifPTM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bExXLP/btq2hCxEqTD/hmlxggEktOXJqxgIifPTM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bExXLP/btq2hCxEqTD/hmlxggEktOXJqxgIifPTM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbExXLP%2Fbtq2hCxEqTD%2FhmlxggEktOXJqxgIifPTM1%2Fimg.png&quot; data-origin-width=&quot;260&quot; data-origin-height=&quot;223&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;216&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ca4mex/btq2hZzodX2/fow0gjRrx7y3OdCytDxHIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ca4mex/btq2hZzodX2/fow0gjRrx7y3OdCytDxHIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ca4mex/btq2hZzodX2/fow0gjRrx7y3OdCytDxHIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fca4mex%2Fbtq2hZzodX2%2Ffow0gjRrx7y3OdCytDxHIk%2Fimg.png&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;216&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;261&quot; data-origin-height=&quot;218&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC9GLi/btq2lpX9Ph9/KH7nJrRGKKuj0Ocl7LzG7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC9GLi/btq2lpX9Ph9/KH7nJrRGKKuj0Ocl7LzG7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC9GLi/btq2lpX9Ph9/KH7nJrRGKKuj0Ocl7LzG7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC9GLi%2Fbtq2lpX9Ph9%2FKH7nJrRGKKuj0Ocl7LzG7k%2Fimg.png&quot; data-origin-width=&quot;261&quot; data-origin-height=&quot;218&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;다만 &lt;b&gt;MySQL에서는 FULL OUTER JOIN을 지원하지 않기 때문&lt;/b&gt;에, &lt;b&gt;집합 연산자를 활용하여 FULL OUTER JOIN을 검색 결과를 도출&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*SELF JOIN&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;b&gt;자기 자신의 테이블에 대해서도 조인이 가능&lt;/b&gt;하다. 쉽게 생각하면&amp;nbsp;&lt;b&gt;자신의 테이블이 2개 존재한다고 생각하고 조인을 진행&lt;/b&gt;하면 &lt;b&gt;SELF JOIN&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1618147543631&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 직원과 직원의 매니저(보고하는 대상)
select e.employeeNumber, e.lastName, m.employeeNumber as &quot;Manager&quot;, m.lastName
from employees e join employees m
on e.reportsTo = m.employeeNumber;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dz4Ya6/btq2iq4FB9S/QzGFGoXXB1xsqw3JDDZJI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dz4Ya6/btq2iq4FB9S/QzGFGoXXB1xsqw3JDDZJI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dz4Ya6/btq2iq4FB9S/QzGFGoXXB1xsqw3JDDZJI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdz4Ya6%2Fbtq2iq4FB9S%2FQzGFGoXXB1xsqw3JDDZJI1%2Fimg.png&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*집합 연산자(SET Operator)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 앞서 조인은 집합 연산과 유사한 방식으로 동작한다는 사실을 확인할 수 있었다. 마찬가지로, SQL에서는 여러가지 집합 연산을 제공하는데 &lt;b&gt;MySQL의 경우에는 UNION 연산만을 지원한다(그 외의 집합 연산은 여러 연산자 및 조인을 활용하여 구현할 수 있다).&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;UNION 연산과 FULL OUTER JOIN &lt;/b&gt;: MySQL에서는 FULL OUTER JOIN을 제공하지 않는다고 하였다. 따라서, L&lt;b&gt;EFT OUTER JOIN과 RIGHT OUTER JOIN을 UNION(합집합)하면, FULL OUTER JOIN&lt;/b&gt;을 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618208029082&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select customerNumber, customerName, salesRepEmployeeNumber
from customers left outer join employees
on employeeNumber = salesRepEmployeeNumber
UNION
select customerNumber, customerName, salesRepEmployeeNumber
from customers right outer join employees
on employeeNumber = salesRepEmployeeNumber
order by customerNumber;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;UNION vs UNION ALL&amp;nbsp;&lt;/b&gt;: 이 둘의 차이는 중복되는 행의 제거(distinct)여부 이다. 기본적으로 UNION연산은 합집합 과정에서 중복되는 요소는 제거하면서 두 테이블을 합친다. 반면 UNION ALL연산은 두 테이블의 중복되는 요소를 제거하지 않고 테이블을 합친다.&lt;/p&gt;</description>
      <category>Web/Database</category>
      <category>Database</category>
      <category>join</category>
      <category>mysql</category>
      <category>Union</category>
      <category>조인</category>
      <category>집합연산자</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/68</guid>
      <comments>https://sskl660.tistory.com/68#entry68comment</comments>
      <pubDate>Sun, 11 Apr 2021 22:26:34 +0900</pubDate>
    </item>
    <item>
      <title>[Database]내장 함수, 집계 함수와 GROUP BY절(MySQL)</title>
      <link>https://sskl660.tistory.com/67</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*MySQL API&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 앞서 제시한 데이터 타입, 혹은 기존에 익숙한 프로그래밍 언어와 마찬가지로&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;b&gt;MySQL의 자세한 문법이나 사용을 보고 싶으면 API문서를 참고하는 습관&lt;/b&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;을 들이도록 하자. 내장 함수에 있어서도 마찬가지이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dev.mysql.com/doc/refman/8.0/en/functions.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618127799134&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MySQL :: MySQL 8.0 Reference Manual :: 12 Functions and Operators&quot; data-og-description=&quot;Chapter 12 Functions and Operators Expressions can be used at several points in SQL statements, such as in the ORDER BY or HAVING clauses of SELECT statements, in the WHERE clause of a SELECT, DELETE, or UPDATE statement, or in SET statements. Expressions &quot; data-og-host=&quot;dev.mysql.com&quot; data-og-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; data-og-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/functions.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL :: MySQL 8.0 Reference Manual :: 12 Functions and Operators&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Chapter 12 Functions and Operators Expressions can be used at several points in SQL statements, such as in the ORDER BY or HAVING clauses of SELECT statements, in the WHERE clause of a SELECT, DELETE, or UPDATE statement, or in SET statements. Expressions&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.mysql.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*더미 테이블&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; SQL에는 보통&amp;nbsp;&lt;b&gt;테이블이 존재 하지 않지만, 테이블을 표시하고 싶은 경우(예를 들면 산술 연산에 대한 결과등을 테이블 형태로 출력)&lt;/b&gt;, 참조를 위한&amp;nbsp;&lt;b&gt;가상의 테이블&lt;/b&gt;을 제공해준다. 이것을&amp;nbsp;&lt;b&gt;더미 테이블&lt;/b&gt;이라고 부르며, 보통 &lt;b&gt;dual&lt;/b&gt;이라는 이름의 형태로 존재한다.&lt;/p&gt;
&lt;pre id=&quot;code_1618128292264&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 더미 테이블 dual
select 1 + 1
from dual;

-- 테이블 이름을 아예 참조하지 않아도 무관하다.
select 1 + 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*알아두면 편리한 내장 함수들&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618129042656&quot; class=&quot;sql&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 절대값
select abs(-7), abs(0), abs(3);

-- 올림(정수 기준)
select ceil(1.24);

-- 내림(정수 기준)
select floor(1.24);

-- 반올림(대상 수, 기준 자릿수) : 기준 자릿수는 1의 자릿수를 기준으로 왼쪽은 -, 오른쪽은 +로 자릿수가 늘어난다.
-- Ex : 100의 자리에 대하여 반올림
select round(153.1254, -2);

-- Ex : 소숫점 아래 2번째 자리에 대하여 반올림
select round(153.1254, 2);

-- Ex : 1의 자리에 대하여 반올림
select round(153.1254);

-- 모든 문자를 소문자로
select lcase(&quot;SElect&quot;);

-- 모든 문자를 대문자로
select ucase(&quot;SElect&quot;);

-- 현재 날짜
select now();

-- 날짜 형식 지정(연, 월, 일, 요일, 시, 분, 초).
select date_format(now(), &quot;%Y.%M.%D %W %H:%I:%S&quot;);
select date_format(now(), &quot;%y.%m.%d %w %h:%i:%s&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;*MySQL Sample Database&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 아래 데이터베이스는 MySQL에서 기본적으로 제공해주는 연습용 SQL 테이블 데이터이다. 해당 데이터를 이용하여 쿼리를 연습해보도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot;&gt;www.mysqltutorial.org/mysql-sample-database.aspx/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618206740729&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MySQL Sample Database&quot; data-og-description=&quot;This page provides you with a MySQL sample database that helps you to practice with MySQL effectively and quickly. You can download the sample database and load it into your MySQL Server.&quot; data-og-host=&quot;www.mysqltutorial.org&quot; data-og-source-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; data-og-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BfCW3/hyJSqeyak1/Xr7ZfaiCtrT4HXJpPh8bYk/img.png?width=701&amp;amp;height=560&amp;amp;face=0_0_701_560&quot;&gt;&lt;a href=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.mysqltutorial.org/mysql-sample-database.aspx/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BfCW3/hyJSqeyak1/Xr7ZfaiCtrT4HXJpPh8bYk/img.png?width=701&amp;amp;height=560&amp;amp;face=0_0_701_560');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL Sample Database&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page provides you with a MySQL sample database that helps you to practice with MySQL effectively and quickly. You can download the sample database and load it into your MySQL Server.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.mysqltutorial.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*집계 함수(Aggregate Function)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 집계 함수란, &lt;span style=&quot;color: #333333;&quot;&gt;여러행 또는 테이블 전체 행으로부터 하나의 결과값을 반환하는 함수이다. 보통&amp;nbsp;&lt;b&gt;GROUP BY절과 함께 사용&lt;/b&gt;되는 경우가 많다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618130422656&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 검색된 행의 개수를 출력
select count(*)
from student;

-- 학생 성적의 총합
select sum(grade)
from student;

-- 학생 성적의 평균
select avg(grade)
from student;

-- 학생 성적 중 최고 성적
select max(grade)
from student;

-- 학생 성적 중 최저 성적
select min(grade)
from student;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*집계 함수(Aggregation Function)와 GROUP BY절&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 집계 함수란, 여러행 또는 테이블 전체 행으로부터 하나의 결과를 반환하는 함수라고 하였다. 예를 들어 고객 테이블에서 같은 주에 속하는 고객들의 평균 신용 한도를 알아보고 싶다고 가정하자. 이때 다음과 같은 쿼리를 수행하면 문제가 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1618206720217&quot; class=&quot;sql&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 오류 코드
select state, avg(creditLimit)
from customers;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;왜냐하면 avg(creditLimit)에 대한 쿼리의 수행 결과는 전체 테이블에 대하여 수행이 되어 1개의 행을 반환하지만, state 열은 여러개의 결과를 반환하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이러한 문제를 해결하기 위하여,&amp;nbsp;&lt;b&gt;집계함수를 전체 테이블에 한 번에 적용하는 것이 아닌 지정한 그룹마다 집계함수를 구하기 위한 방법&lt;/b&gt;이 필요하고 이 방법이&amp;nbsp;&lt;b&gt;GROUP BY절을 활용하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1618206720217&quot; class=&quot;sql&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 같은 주에 속하는 고객들의 평균 신용 한도
select state, avg(creditLimit)
from customers
group by state
order by state;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;212&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rn2O9/btq2kCK3t7n/Q3c77B0iCW0va96k0A2GUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rn2O9/btq2kCK3t7n/Q3c77B0iCW0va96k0A2GUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rn2O9/btq2kCK3t7n/Q3c77B0iCW0va96k0A2GUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRn2O9%2Fbtq2kCK3t7n%2FQ3c77B0iCW0va96k0A2GUk%2Fimg.png&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;212&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1618206720217&quot; class=&quot;sql&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 각 주문별 최고 판매액과 최저 판매액
select orderNumber, max(priceEach), min(priceEach)
from orderdetails
group by orderNumber;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;173&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FLxmw/btq2rygmO56/zHMX4IdsapOov0f8yP7g9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FLxmw/btq2rygmO56/zHMX4IdsapOov0f8yP7g9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FLxmw/btq2rygmO56/zHMX4IdsapOov0f8yP7g9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFLxmw%2Fbtq2rygmO56%2FzHMX4IdsapOov0f8yP7g9k%2Fimg.png&quot; data-origin-width=&quot;285&quot; data-origin-height=&quot;173&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*HAVING절&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; GROUP BY절에&amp;nbsp;&lt;b&gt;조건에 맞는 대상만 그루핑하고 싶은 경우 HAVING절을 사용&lt;/b&gt;하면 된다.&amp;nbsp;&lt;b&gt;WHERE절 대신 HAVING절을 사용하는 이유&lt;/b&gt;는,&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;WHERE절이 GROUP BY절보다 먼저 수행되기 때문에 GROUP BY절의 조건은 따로 고려해주는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1618206720217&quot; class=&quot;sql&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 100 ~ 150번 고객 중 같은 주에 속하는 고객들의 평균 신용 한도(단, 평균 신용한도가 50000이상인 지역만)
select state, avg(creditLimit) -- 5
from customers -- 실행 순서 1
where customerNumber between 100 and 150 -- 2
group by state -- 3
having avg(creditLimit) &amp;gt; 50000 -- 4
order by avg(creditLimit); -- 6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;172&quot; data-origin-height=&quot;106&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/de4Ykh/btq2lqJ9JKe/rDBsxD644O0emrkKqpI1R1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/de4Ykh/btq2lqJ9JKe/rDBsxD644O0emrkKqpI1R1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/de4Ykh/btq2lqJ9JKe/rDBsxD644O0emrkKqpI1R1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fde4Ykh%2Fbtq2lqJ9JKe%2FrDBsxD644O0emrkKqpI1R1%2Fimg.png&quot; data-origin-width=&quot;172&quot; data-origin-height=&quot;106&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/Database</category>
      <category>Database</category>
      <category>group by</category>
      <category>having</category>
      <category>mysql</category>
      <category>내장 함수</category>
      <category>더미 테이블</category>
      <category>집계함수</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/67</guid>
      <comments>https://sskl660.tistory.com/67#entry67comment</comments>
      <pubDate>Sun, 11 Apr 2021 17:40:58 +0900</pubDate>
    </item>
    <item>
      <title>[Database]DML(MySQL)</title>
      <link>https://sskl660.tistory.com/66</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*DML(Data Manipulation Language)&amp;nbsp;&lt;/b&gt;: 데이터 조작어. 데이터베이스 객체에서 데이터를&amp;nbsp;&lt;b&gt;CRUD(Create Read Update Delete : insert select update delete)&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 데이터 삽입(INSERT)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617723546271&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 모든 열에 데이터를 삽입하는 경우
insert into table_name
values (val1, val2, ...);

-- 특정 열에 데이터를 삽입하는 경우(권장)
insert into table_name (col_name1, col_name2, ...)
values (val1, val2, ...);

-- 여러 데이터(행)를 한 번에 삽입하는 경우
insert into table_name (col_name1, col_name2, ...)
values (val1, val2, ...),
       (val1, val2, ...);
       
-- Ex
insert into student (studentname, studentid, studentpwd)
values (&quot;kim&quot;, &quot;asas&quot;, &quot;1234&quot;),
       (&quot;lee&quot;, &quot;asdf&quot;, &quot;1234&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 데이터 변경(UPDATE)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617723581008&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- UPDATE(where 절을 생략하면 모든 데이터가 바뀌니 주의!).
update table_name
set col_name1 = val1, ...
where conditions;

-- Ex
update student
set studentname = &quot;park&quot;, studentid = &quot;aaaa&quot;
where studentno = 2;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 데이터 삭제(DELETE)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617724019775&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- DELETE(UPDATE와 마찬가지로 where절을 삭제하면 모든 데이터가 삭제되니 주의!).
delete from table_name
where conditions;

-- Ex
delete from student
where studentno = 3;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;(4) 데이터 조회(READ)&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 테이블 조회(기본)&lt;/p&gt;
&lt;pre id=&quot;code_1618124174246&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 전체 테이블 조회
select *
from table_name;

-- Ex
select *
from student;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1618124649026&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 특정 열을 선택하여 조회
select col_name, col_name2, ...
from table_name;

-- Ex
select studentNo, studentName
from student;

-- 중복되는 행을 제외하고 조회(DISTINCT 명령어)
select distinct col_name
from studnt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;별칭 : 열에 사용자 지정 이름을 새로 붙인다(AS).&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618124957072&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 문법
select col_name as &quot;alias&quot;
from table_name;

-- Ex
select studentNo as &quot;학번&quot;
from student;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt; 조건을 만족하는 테이블 내용 조회 : WHERE 절&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618125238716&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- Ex : 나이가 21살 이상인 학생 조회
select *
from student
where age &amp;gt;= 21;

-- 조건에 AND, OR, NOT을 활용할 수 있다.
-- AND Ex : 나이가 21살이고, 이름이 kim인 학생 조회
select *
from student
where age = 21 and studentName = &quot;kim&quot;;

-- OR Ex : 나이가 21살 이거나, 이름이 kim인 학생 조회
select *
from student
where age = 21 or studentName = &quot;kim&quot;;

-- NOT Ex : 나이가 21살이 아닌 학생 조회
select *
from student
where not (age = 21);

-- IN, BETWEEN을 이용한 범위 조건
-- IN Ex : 나이가 21, 22, 23살인 학생 조회
select *
from student
where age in (21, 22, 23);

-- BETWEEN Ex : 나이가 21, 22, 23살인 학생 조회
select *
from student
where age BETWEEN 21 AND 23;

-- NULL 값에 대한 비교 : NULL 값은 '-' 연산자가 아닌 'is' 연산자를 사용해야 한다.
select *
from student
where studentNo is null;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ LIKE 명령어와 wild card(%, _) : 특정 문자를 포함한 대상을 검색할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618126566481&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- % : 어떤 문자가 몇 개가 와도 상관 없다.
-- 이름이 &quot;김&quot;으로 시작하는 모든 학생 조회
select *
from student
where studentName like &quot;김%&quot;;

-- 이름에 &quot;김&quot;을 포함하는 모든 학생 조회
select *
from student
where studentName like &quot;%김%&quot;;

-- 이름이 &quot;김&quot;으로 끝나는 모든 학생 조회
select *
from student
where studentName like &quot;%김&quot;;

-- _ : 해당 문자의 개수 만큼 해당 위치에 어떤 문자가 와도 상관 없다.
-- 이름이 &quot;김&quot;으로 시작하고 3글자인 모든 학생 조회
select *
from student
where studentName like &quot;김__&quot;;

-- 이름 중간에 &quot;김&quot;을 포함하고 3글자인 모든 학생 조회
select *
from student
where studentName like &quot;_김_&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;b&gt;출력행 정렬 : ORDER BY 절&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618127075655&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 테이블을 오름차순(ASC : 디폴트), 내림차순(DESC)으로 정렬한다.
-- ASC Ex : 학생의 나이순 오름차순으로 정렬
select *
from student
order by age;

-- DESC Ex : 학생의 나이순 내림차순으로 정렬
select *
from student
order by age desc;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*MySQL API&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 앞서 제시한 데이터 타입, 혹은 기존에 익숙한 프로그래밍 언어와 마찬가지로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;MySQL의 자세한 문법이나 사용을 보고 싶으면 API문서를 참고하는 습관&lt;/b&gt;을 들이도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot;&gt;dev.mysql.com/doc/refman/8.0/en/sql-statements.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618127416329&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MySQL :: MySQL 8.0 Reference Manual :: 13 SQL Statements&quot; data-og-description=&quot;&quot; data-og-host=&quot;dev.mysql.com&quot; data-og-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot; data-og-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL :: MySQL 8.0 Reference Manual :: 13 SQL Statements&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.mysql.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Web/Database</category>
      <category>Database</category>
      <category>DML</category>
      <category>mysql</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/66</guid>
      <comments>https://sskl660.tistory.com/66#entry66comment</comments>
      <pubDate>Sun, 11 Apr 2021 16:50:31 +0900</pubDate>
    </item>
    <item>
      <title>[Database]DDL(MySQL)</title>
      <link>https://sskl660.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*DDL(Data Definition Language)&amp;nbsp;&lt;/b&gt;: 데이터 정의어.&amp;nbsp;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*데이터베이스 : 생성, 변경, 삭제, 사용.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617719961321&quot; class=&quot;sql&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 다국어 처리
create database db
default character set utf8mb3 collate utf8mb3_general_ci;

-- 이모지 문자까지 다국어 처리
create database db
default character set utf8mb4 collate utf8mb4_general_ci;

-- 변경
alter database db
default character set utf8mb4 collate utf8mb4_general_ci;

-- 삭제
drop database db;

-- 데이터베이스 사용
use db;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*테이블&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 데이터 타입 : &lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/data-types.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dev.mysql.com/doc/refman/8.0/en/data-types.html&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1617721013182&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MySQL :: MySQL 8.0 Reference Manual :: 11 Data Types&quot; data-og-description=&quot;MySQL supports SQL data types in several categories: numeric types, date and time types, string (character and byte) types, spatial types, and the JSON data type. This chapter provides an overview and more detailed description of the properties of the type&quot; data-og-host=&quot;dev.mysql.com&quot; data-og-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/data-types.html&quot; data-og-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/data-types.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/data-types.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/data-types.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL :: MySQL 8.0 Reference Manual :: 11 Data Types&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MySQL supports SQL data types in several categories: numeric types, date and time types, string (character and byte) types, spatial types, and the JSON data type. This chapter provides an overview and more detailed description of the properties of the type&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.mysql.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 테이블 생성(CREATE)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 문법&lt;/p&gt;
&lt;pre id=&quot;code_1617721114113&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create table table_name(
	col_name1 Type [option],
	col_name2 Type [option],
	...
    );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 예시&lt;/p&gt;
&lt;pre id=&quot;code_1617721928835&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create database db
default character set utf8mb4 collate utf8mb4_general_ci;

use db;

create table student (
	studentno INT NOT NULL auto_increment primary key,
	studentname VARCHAR(20) NOT NULL,
	studentid VARCHAR(20),
	studentpwd VARCHAR(20)
    );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ option에는 다음과 같은 속성들이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;NOT NULL&amp;nbsp;&lt;/b&gt;: null 값을 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;AUTO INCREMENT&amp;nbsp;&lt;/b&gt;: 새 레코드가 추가 될 때 마다 필드 값을 자동으로 1씩 증가시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;&lt;u&gt;&lt;b&gt;PRIMARY KEY&lt;/b&gt;&lt;/u&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;:&amp;nbsp;&lt;b&gt;테이블에서 행을 고유하게 식별하기 위해 사용&lt;/b&gt;한다(기본키).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;FOREIGN KEY&amp;nbsp;&lt;/b&gt;: &lt;b&gt;특정 테이블의 PK컬럼에 저장되어 있는 값을 저장하고 가리킨다&lt;/b&gt;(참조키, 외래키).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&amp;nbsp;UNIQUE: 컬럼에 중복된 값 저장 불가능(NULL 제외).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;&amp;nbsp;&lt;/span&gt;DEFAULT value&lt;span style=&quot;color: #333333;&quot;&gt;: 기본값을 value로 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; UNSIGNED : Type이 숫자인 경우, 값을 0 혹은 양수로 제한한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 테이블 변경(ALTER)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617722185240&quot; class=&quot;sql&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- ADD(새로운 열 추가)
alter table table_name add col_name TYPE [option];

-- Add Ex
alter table student add age INT NOT NULL;

-- RENAME(열 이름 변경)
alter table table_name rename column col_name to change_name;

-- RENAME Ex
alter table student rename column age to grade;

-- MODIFY(열 데이터 타입 변경)
alter table table_name modify col_name TYPE;

-- MODIFY Ex
alter table student modify grade decimal(10);

-- DROP(열 삭제)
alter table table_name drop col_name;

-- DROP Ex
alter table student drop grade;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(4) 테이블 삭제(DROP)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617722807405&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- DROP(테이블 삭제)
drop table table_name;

-- DROP Ex
drop table student;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*MySQL API&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 앞서 제시한 데이터 타입, 혹은 기존에 익숙한 프로그래밍 언어와 마찬가지로 &lt;b&gt;MySQL의 자세한 문법이나 사용을 보고 싶으면 API문서를 참고하는 습관&lt;/b&gt;을 들이도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dev.mysql.com/doc/refman/8.0/en/sql-statements.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1617722984451&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MySQL :: MySQL 8.0 Reference Manual :: 13 SQL Statements&quot; data-og-description=&quot;&quot; data-og-host=&quot;dev.mysql.com&quot; data-og-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot; data-og-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL :: MySQL 8.0 Reference Manual :: 13 SQL Statements&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.mysql.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Web/Database</category>
      <category>Database</category>
      <category>DDL</category>
      <category>mysql</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/65</guid>
      <comments>https://sskl660.tistory.com/65#entry65comment</comments>
      <pubDate>Sun, 11 Apr 2021 15:47:51 +0900</pubDate>
    </item>
    <item>
      <title>[Database]SQL 개요</title>
      <link>https://sskl660.tistory.com/64</link>
      <description>&lt;p&gt;&lt;b&gt;*RDBMS(Relational Database Management System)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;RDBMS란 관계형 데이터베이스 시스템을 지칭하는 약어이다. RDBMS는&amp;nbsp;&lt;b&gt;테이블 기반의 DBMS&lt;/b&gt;로,&amp;nbsp;&lt;b&gt;데이터를 테이블 단위로 관리&lt;/b&gt;한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*SQL(Structured Query Language)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;SQL이란, &lt;b&gt;데이터베이스에 있는 정보를 사용할 수 있도록 지원하는 언어&lt;/b&gt;이다. 기본적으로 NoSQL을 제외한&amp;nbsp;&lt;b&gt;모든 DBMS에서 사용이 가능&lt;/b&gt;하며,&amp;nbsp;&lt;u&gt;&lt;b&gt;데이터의 대소문자를 제외한 대소문자는 구별하지 않는다&lt;/b&gt;&lt;/u&gt;는 특징을 가지고 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*SQL 구문의 기본적인 구성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;(1) DDL(Data Definition Language)&amp;nbsp;&lt;/b&gt;: &lt;b&gt;데이터를 정의하는 언어&lt;/b&gt;이다. 데이터베이스 객체의&amp;nbsp;&lt;b&gt;구조를 정의하는 역할&lt;/b&gt;을 하며, &lt;b&gt;테이블 생성, 삭제, 수정등의 기능을 수행&lt;/b&gt;한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 80px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center;&quot;&gt;명령어&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center;&quot;&gt;기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center;&quot;&gt;&lt;b&gt;CREATE&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center;&quot;&gt;데이터베이스 관련 객체(데이터베이스, 뷰, 테이블...)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;생성&lt;/b&gt;&lt;/u&gt;한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center;&quot;&gt;&lt;b&gt;ALTER&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center;&quot;&gt;존재하는 데이터베이스 관련 객체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;수정&lt;/b&gt;&lt;/u&gt;한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center;&quot;&gt;&lt;b&gt;DROP&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center;&quot;&gt;존재하는 데이터베이스 관련 객체를&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;삭제&lt;/u&gt;&lt;/b&gt;한다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;b&gt;(2) DML(Data Manipulation Language) : 데이터를 조작하는 언어&lt;/b&gt;이다. 데이터베이스의 &lt;b&gt;데이터를 조작하는 역할&lt;/b&gt;을 한다. 대표적으로 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인&amp;nbsp;&lt;b&gt;&lt;u&gt;CRUD(Create, Read, Update, Delete)&lt;/u&gt;를 테이블의 레코드에서 수행&lt;/b&gt;한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center; height: 20px;&quot;&gt;명령어&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center; height: 20px;&quot;&gt;기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;INSERT(C)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center; height: 20px;&quot;&gt;데이터베이스 관련 객체(데이터베이스, 뷰, 테이블...)에 &lt;u&gt;&lt;b&gt;데이터를 입력&lt;/b&gt;&lt;/u&gt;한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;SELECT(R)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center; height: 20px;&quot;&gt;데이터베이스 관련 객체에 &lt;u&gt;&lt;b&gt;데이터를&lt;span&gt;&amp;nbsp;조회&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;UPDATE(U)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center; height: 20px;&quot;&gt;데이터베이스 관련 객체에 &lt;b&gt;&lt;u&gt;데이터를 수정&lt;/u&gt;&lt;/b&gt;한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;DELETE(D)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;데이터베이스 관련 객체에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;u&gt;데이터를 삭제&lt;/u&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;b&gt;(3) DCL(Data Control Language) : 데이터를 제어하는 언어&lt;/b&gt;이다. 데이터베이스의&amp;nbsp;&lt;b&gt;접근 권한, 조작 권한등을 정의하는 역할&lt;/b&gt;을 한다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 60px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; height: 20px; text-align: center;&quot;&gt;명령어&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; height: 20px; text-align: center;&quot;&gt;기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;GRANT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; height: 20px; text-align: center;&quot;&gt;데이터베이스 관련 객체(데이터베이스, 뷰, 테이블...)에 대한&lt;span&gt; &lt;/span&gt;&lt;u&gt;&lt;b&gt;권한을 사용자에게 부여&lt;/b&gt;&lt;/u&gt;한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.9535%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;REVOKE&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; height: 20px; text-align: center;&quot;&gt;데이터베이스 관련 객체에 대한&lt;span&gt; &lt;/span&gt;&lt;u&gt;&lt;b&gt;사용자의 권한을 취소&lt;/b&gt;&lt;/u&gt;한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;b&gt;(4) TCL(Transaction Control Language) : 트랜잭션을 제어하는 언어&lt;/b&gt;이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center;&quot;&gt;명령어&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center;&quot;&gt;기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center;&quot;&gt;&lt;b&gt;COMMIT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center;&quot;&gt;실행한 명령어를&amp;nbsp;&lt;b&gt;데이터베이스에 최종적으로 적용&lt;/b&gt;시킨다(저장).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.9535%; text-align: center;&quot;&gt;&lt;b&gt;ROLLBACK&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 80.9302%; text-align: center;&quot;&gt;실행한 명령어를&amp;nbsp;&lt;b&gt;COMMIT 명령어 수행 전으로 복구&lt;/b&gt;시킨다(되돌리기).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/Database</category>
      <category>Database</category>
      <category>DCL</category>
      <category>DDL</category>
      <category>DML</category>
      <category>SQL</category>
      <category>Tcl</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/64</guid>
      <comments>https://sskl660.tistory.com/64#entry64comment</comments>
      <pubDate>Sun, 11 Apr 2021 15:47:19 +0900</pubDate>
    </item>
    <item>
      <title>[Java]그래프의 표현</title>
      <link>https://sskl660.tistory.com/60</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*그래프의 표현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;프로그래밍을 하다보면 그래프를 만들어야 하는 경우가 발생할 수 있는데, &lt;b&gt;프로그래밍에서 그래프를 표현하는 방법은 크게 2가지(인접 행렬, 인접 리스트)&lt;/b&gt;로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;인접 행렬 :&amp;nbsp;&lt;/b&gt;수학에서&amp;nbsp;&lt;b&gt;행렬&lt;/b&gt;은&amp;nbsp;&lt;b&gt;그래프를 표현하는데 사용&lt;/b&gt;되기도 하였다. 따라서&amp;nbsp;&lt;b&gt;프로그래밍에서 2차원 배열은 행렬의 성질을 갖는다는 점을 활용&lt;/b&gt;하여 마찬가지로 그래프를 표현할 수 있다. 기본적으로 인접행렬을 이용한 그래프 표현은 &lt;b&gt;각 인덱스를 정점이라고 생각&lt;/b&gt;하고,&amp;nbsp;&lt;b&gt;정점이 교차하는 지점(좌표)&lt;/b&gt;&lt;b&gt;을 연결된 상태&lt;/b&gt;&lt;b&gt;라고 표시&lt;/b&gt;해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) &lt;b&gt;무향 그래프&lt;/b&gt; : &lt;b&gt;방향을 가지지 않는&lt;/b&gt;&lt;b&gt; 그래프&lt;/b&gt;를 말한다. 따라서,&amp;nbsp;&lt;b&gt;행렬이 대칭적으로 같은 값을 갖는 특징&lt;/b&gt;을 갖는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;552&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/myFdE/btqZVnccnz5/vWOUZ2U3PcVZZgw1lxkTLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/myFdE/btqZVnccnz5/vWOUZ2U3PcVZZgw1lxkTLK/img.png&quot; data-alt=&quot;무향 그래프와 인접행렬 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/myFdE/btqZVnccnz5/vWOUZ2U3PcVZZgw1lxkTLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmyFdE%2FbtqZVnccnz5%2FvWOUZ2U3PcVZZgw1lxkTLK%2Fimg.png&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;552&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;무향 그래프와 인접행렬 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) &lt;b&gt;유향 그래프 &lt;/b&gt;: &lt;b&gt;방향을 가지고 있는 그래프&lt;/b&gt;를 말한다. 따라서,&amp;nbsp;&lt;b&gt;무조건 행렬이 대칭적으로 같은 값을 갖지는 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;520&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfvo1S/btqZV62mFCB/tWs97A9JbSAoImBKIY8Nc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfvo1S/btqZV62mFCB/tWs97A9JbSAoImBKIY8Nc1/img.png&quot; data-alt=&quot;유향 그래프와 인접행렬 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfvo1S/btqZV62mFCB/tWs97A9JbSAoImBKIY8Nc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbfvo1S%2FbtqZV62mFCB%2FtWs97A9JbSAoImBKIY8Nc1%2Fimg.png&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;520&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유향 그래프와 인접행렬 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;인접 리스트 :&amp;nbsp;&lt;/b&gt;인접 리스트를 이용하는 방식은&amp;nbsp;&lt;b&gt;연결 리스트 자료구조를 활용&lt;/b&gt;하여 그래프를 표현할 수 있다.&amp;nbsp;&lt;b&gt;1차원 배열의 각 인덱스를 노드&lt;/b&gt;라고 생각하고,&amp;nbsp;&lt;b&gt;정점의 연결이 있을 때마다 해당 정점에 연결된 노드 정보를 추가&lt;/b&gt;해주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 무향 그래프 : 연결된 노드의 정보를 추가할때&amp;nbsp;&lt;b&gt;각 노드에 대하여 각각 정보를 추가&lt;/b&gt;해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;562&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cr4bQV/btqZZTOwkx5/YhixwfENG5oXXUu7lKiOK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cr4bQV/btqZZTOwkx5/YhixwfENG5oXXUu7lKiOK0/img.png&quot; data-alt=&quot;무향 그래프와 인접 리스트 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cr4bQV/btqZZTOwkx5/YhixwfENG5oXXUu7lKiOK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcr4bQV%2FbtqZZTOwkx5%2FYhixwfENG5oXXUu7lKiOK0%2Fimg.png&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;562&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;무향 그래프와 인접 리스트 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 유향 그래프 :&amp;nbsp;&lt;b&gt;연결된 노드의 정보만 추가&lt;/b&gt;해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1235&quot; data-origin-height=&quot;555&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsD2uz/btqZV7fUoI6/ITlkluNd5ySnj2Hk2GZCG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsD2uz/btqZV7fUoI6/ITlkluNd5ySnj2Hk2GZCG1/img.png&quot; data-alt=&quot;유향 그래프와 인접 리스트 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsD2uz/btqZV7fUoI6/ITlkluNd5ySnj2Hk2GZCG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsD2uz%2FbtqZV7fUoI6%2FITlkluNd5ySnj2Hk2GZCG1%2Fimg.png&quot; data-origin-width=&quot;1235&quot; data-origin-height=&quot;555&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유향 그래프와 인접 리스트 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*장단점&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;541&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tc4VL/btqZZTnuZpD/UnzSCbU0pF1Sk8J2S2iwZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tc4VL/btqZZTnuZpD/UnzSCbU0pF1Sk8J2S2iwZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tc4VL/btqZZTnuZpD/UnzSCbU0pF1Sk8J2S2iwZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftc4VL%2FbtqZZTnuZpD%2FUnzSCbU0pF1Sk8J2S2iwZ1%2Fimg.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;541&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;&lt;b&gt;인접 행렬&lt;/b&gt;은 &lt;b&gt;간선의 추가와 삭제가 빈번하게 사용되는 경우&lt;/b&gt;, &lt;b&gt;인접 리스트&lt;/b&gt;는 &lt;b&gt;노드의 추가와 삭제가 빈번하게 사용되는 경우&lt;/b&gt; 사용하는 것이 좋다.&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;*인접 행렬 구현&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;&lt;b&gt;알고리즘 문제에서는&lt;/b&gt; &lt;b&gt;주로 연결되는 두 노드의 정점과 비용으로 그래프의 연결성이 주어지기 때문(노드 노드 비용)&lt;/b&gt;에, 그 상황을 가정하여 인접행렬을 구현해보면 다음과 같다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1615556231610&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

/*
정점, 간선의 개수 이후
(노드, 노드, 비용)이 주어진 경우
5 6
5 1 1
1 2 2
1 3 3
2 3 4
2 4 5
3 4 6
 */

public class Graph {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// V = 정점의 개수, E = 간선의 개수.
		int V = sc.nextInt();
		int E = sc.nextInt();
		
		// 2차원 배열(인접 행렬)을 만든다.
		// 인덱스의 번호 = 노드의 번호 이기 때문에, 2차원 배열의 크기를 임의로 1 늘려서 정의한다(스킬).
		int[][] graph = new int[V + 1][V + 1];
		
		int row;
		int col;
		int cost;
		for(int i = 0; i &amp;lt; E; i++) {
			row = sc.nextInt();
			col = sc.nextInt();
			cost = sc.nextInt();
			graph[row][col] = cost;
			// 만일, 무향 그래프라면 반대의 상황도 추가해 준다.
			// graph[col][row] = cost;
		}
		
		// 인접 행렬 출력
		for(int i = 1; i &amp;lt; V + 1; i++) {
			for(int j = 1; j &amp;lt; V + 1; j++) {
				System.out.print(graph[i][j] + &quot; &quot;);
			}
			System.out.println();
		}
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;88&quot; data-origin-height=&quot;96&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXUSB/btq6f8rNIC7/OHCDukKAIOF8YoV6skftSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXUSB/btq6f8rNIC7/OHCDukKAIOF8YoV6skftSK/img.png&quot; data-alt=&quot;유향 그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXUSB/btq6f8rNIC7/OHCDukKAIOF8YoV6skftSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXUSB%2Fbtq6f8rNIC7%2FOHCDukKAIOF8YoV6skftSK%2Fimg.png&quot; data-origin-width=&quot;88&quot; data-origin-height=&quot;96&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유향 그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;89&quot; data-origin-height=&quot;95&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2u1P9/btq6hd7cTdN/djpMqIVgRwn6NekSb3KDV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2u1P9/btq6hd7cTdN/djpMqIVgRwn6NekSb3KDV0/img.png&quot; data-alt=&quot;무향 그래프(대칭성을 확인할 수 있다)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2u1P9/btq6hd7cTdN/djpMqIVgRwn6NekSb3KDV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2u1P9%2Fbtq6hd7cTdN%2FdjpMqIVgRwn6NekSb3KDV0%2Fimg.png&quot; data-origin-width=&quot;89&quot; data-origin-height=&quot;95&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;무향 그래프(대칭성을 확인할 수 있다)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;*인접 리스트 구현&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;알고리즘 문제에서는&lt;/b&gt;&lt;b&gt;주로 연결되는 두 노드의 정점과 비용으로 그래프의 연결성이 주어지기 때문(노드 노드 비용)&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;에, 마찬가지로 그 상황을 가정하여 인접 리스트를 구해보면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;자바의 경우,&amp;nbsp;&lt;b&gt;리스트 안에 자유롭게 노드를 추가 가능한 리스트를 추가&lt;/b&gt;할 수 있어야 하기 때문에 List 내부에&amp;nbsp;&lt;b&gt;동적 리스트&lt;/b&gt;를 선언하여 처리해준다. 또한, 그 안에 &lt;b&gt;대상 노드와 비용을 리스트처럼 처리&lt;/b&gt;하는 경우가 많기 때문에,&amp;nbsp;&lt;b&gt;Node라는 클래스(객체)를 따로 선언&lt;/b&gt;해주어 처리해주는 것이 깔끔하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1615558070374&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Graph;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/*
정점, 간선의 개수 이후
(노드, 노드, 비용)이 주어진 경우
5 6
5 1 1
1 2 2
1 3 3
2 3 4
2 4 5
3 4 6
 */

public class Graph {
	// 노드와 비용을 포함하는 객체를 미리 만들어준다.
	static public class Node {
		// 연결되는 정점
		int end;
		// 비용
		int cost;

		Node(int end, int cost) {
			this.end = end;
			this.cost = cost;
		}

		@Override
		public String toString() {
			return &quot;[&quot; + end + &quot;, &quot;
					+ &quot;&quot; + cost + &quot;]&quot;;
		}
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// V = 정점의 개수, E = 간선의 개수.
		int V = sc.nextInt();
		int E = sc.nextInt();
		
		// 1차원 리스트를 만든다.
		// 인덱스의 번호 = 노드의 번호 이기 때문에, 1차원 리스트의 크기를 임의로 1 늘려서 정의한다(스킬).
		List&amp;lt;ArrayList&amp;lt;Node&amp;gt;&amp;gt; graph = new ArrayList&amp;lt;ArrayList&amp;lt;Node&amp;gt;&amp;gt;();
		for (int i = 0; i &amp;lt; V + 1; i++) {
			graph.add(new ArrayList&amp;lt;Node&amp;gt;());
		}

		int a;
		int b;
		int cost;
		for (int i = 0; i &amp;lt; E; i++) {
			a = sc.nextInt();
			b = sc.nextInt();
			cost = sc.nextInt();
			
			graph.get(a).add(new Node(b, cost));
			// 만일, 무향 그래프라면 반대의 상황도 추가해 준다.
			// graph.get(b).add(new Node(a, cost));
		}

		// 인접 행렬 출력
		System.out.println(graph);
		sc.close();
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;22&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yg4MM/btqZYlx5udb/B4rybwLnqZ6ugbUJfTuXkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yg4MM/btqZYlx5udb/B4rybwLnqZ6ugbUJfTuXkk/img.png&quot; data-alt=&quot;유향 그래프&amp;amp;amp;nbsp;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yg4MM/btqZYlx5udb/B4rybwLnqZ6ugbUJfTuXkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyg4MM%2FbtqZYlx5udb%2FB4rybwLnqZ6ugbUJfTuXkk%2Fimg.png&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;22&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유향 그래프&amp;nbsp;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;23&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpBe4U/btqZZyYdqUt/LJg5Hf4EfEpCMdDDqHpUv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpBe4U/btqZZyYdqUt/LJg5Hf4EfEpCMdDDqHpUv0/img.png&quot; data-alt=&quot;무향 그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpBe4U/btqZZyYdqUt/LJg5Hf4EfEpCMdDDqHpUv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpBe4U%2FbtqZZyYdqUt%2FLJg5Hf4EfEpCMdDDqHpUv0%2Fimg.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;23&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;무향 그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;유향 그래프의 1번째 인덱스(1번 노드)의 1번째 인덱스(첫 번째 대상 노드)는 2번 노드로 가는데 비용이 2가 든다는 의미, 2번째 인덱스(두 번째 대상 노드)는 3번 노드로 가는데 비용이 3이 든다는 의미이다. 적절히 잘 구현된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;각 인덱스 내부의 대상 노드 값을&amp;nbsp;&lt;b&gt;오름차순으로 정렬&lt;/b&gt;하면 더 깔끔하게 표현가능하지만, 큰 상관은 없다.&lt;/p&gt;</description>
      <category>Algorithm/그래프&amp;amp;최단경로</category>
      <category>Java 그래프</category>
      <category>그래프의 표현</category>
      <category>인접 리스트</category>
      <category>인접 행렬</category>
      <category>자바를 이용한 그래프 표현</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/60</guid>
      <comments>https://sskl660.tistory.com/60#entry60comment</comments>
      <pubDate>Fri, 12 Mar 2021 00:41:28 +0900</pubDate>
    </item>
    <item>
      <title>[Java]다익스트라 알고리즘(Dijkstra Algorithm)</title>
      <link>https://sskl660.tistory.com/59</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*다익스트라 알고리즘(Dijkstra Algorithm)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 다익스트라 알고리즘은 &lt;u&gt;&lt;b&gt;음의 가중치&lt;/b&gt;(음의 간선, 음의 값)&lt;b&gt;가 없는 그래프의 한 노드&lt;/b&gt;&lt;/u&gt;에서 &lt;b&gt;각 모든 노드까지의 최단거리를 구하는 알고리즘&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 초기 모델은&amp;nbsp;&lt;b&gt;O(V^2)의 시간복잡도&lt;/b&gt;를 가졌다.&amp;nbsp;이후&amp;nbsp;&lt;b&gt;우선순위 큐&lt;/b&gt; 등을 이용한 고안된 알고리즘이 탄생했고, 현재는&amp;nbsp;&lt;b&gt;O((V+E)log V)의 시간복잡도&lt;/b&gt;를 가지고 있다(만일 &lt;b&gt;연결 그래프라면 O(ElogV)까지 시간 복잡도를 줄일 수 있다&lt;/b&gt;고 한다).&amp;nbsp;&lt;b&gt;일반적으로는 그래프가 희소 그래프인 경우에 우선순위 큐를 이용하는 것이 낫다고 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※음의 가중치를 가지면 안되는 이유는 최소 비용의 음의 무한대 발산, 그리디 알고리즘 적용 불가능 등이 있다. 후자는 제일 아래에 있는 다익스트라 알고리즘 정당성 증명을 참고하도로 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※연결 그래프 :&amp;nbsp;모든 두 꼭짓점 사이에 경로가 존재하는 그래프.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※희소 그래프 : 밀집 그래프의 반대. 밀집 그래프란, 간선의 수가 최대에 가까운 그래프를 만한다. 보통,&amp;nbsp;&lt;b&gt;간선의 총 개수가 정점의 개수^2과 근사하다면 밀집 그래프&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*다익스트라 알고리즘의 매커니즘&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 다익스트라 알고리즘은 &lt;b&gt;기본적으로&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;그리디 알고리즘&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이자&amp;nbsp;&lt;/span&gt;&lt;b&gt;다이나믹 프로그래밍 기법을 사용한&amp;nbsp;알고리즘&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 다익스트라 알고리즘은 기본적으로 아래&amp;nbsp;&lt;b&gt;두 단계를 반복&lt;/b&gt;하여 &lt;b&gt;임의의 노드&lt;/b&gt;에서&amp;nbsp;&lt;b&gt;각 모든 노드까지의 최단거리&lt;/b&gt;를 구한다. 임의의 노드에서 다른 노드로 가는 값을 &lt;b&gt;비용&lt;/b&gt;이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(1)&amp;nbsp;&lt;b&gt;방문하지 않은 노드&lt;/b&gt;&amp;nbsp;&lt;b&gt;중&lt;/b&gt;에서&amp;nbsp;&lt;b&gt;가장 비용이 적은 노드를 선택&lt;/b&gt;한다(그리디 알고리즘).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(2)&amp;nbsp;&lt;b&gt;해당 노드로부터 갈 수 있는 노드들의 비용을 갱신&lt;/b&gt;한다(다이나믹 프로그래밍).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; 예를 들어 아래 그림에서,&amp;nbsp;&lt;b&gt;A노드에서 출발하여 F노드로 가는 최단 경로를 구하는 문제&lt;/b&gt;를 다익스트라 알고리즘을 적용하여 생각해보자.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;382&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q0yim/btqZSuIfKTX/ORDr8TKshVic2HL8MZILE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q0yim/btqZSuIfKTX/ORDr8TKshVic2HL8MZILE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q0yim/btqZSuIfKTX/ORDr8TKshVic2HL8MZILE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ0yim%2FbtqZSuIfKTX%2FORDr8TKshVic2HL8MZILE1%2Fimg.png&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;382&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;각 단계마다 &lt;b&gt;기준이 필요&lt;/b&gt;하기 때문에, 지금부터는&amp;nbsp;&lt;b&gt;방문하지 않은 노드의 집합을 Before, 방문한 노드의 집합을 After, 현재까지 A노드가 방문한 곳 까지의 최소 비용을 D[대상 노드]라고 정의&lt;/b&gt;하도록 하자. 그렇다면 현재 각 집합이 가지고 있는 값은 다음과 같은 것 이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;261&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIp5JD/btqZSvmSfMm/Rv4QrBbAub0KXBANFzH0VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIp5JD/btqZSvmSfMm/Rv4QrBbAub0KXBANFzH0VK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIp5JD/btqZSvmSfMm/Rv4QrBbAub0KXBANFzH0VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIp5JD%2FbtqZSvmSfMm%2FRv4QrBbAub0KXBANFzH0VK%2Fimg.png&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;261&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;lt;초기화 단계&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그렇다면, 이 상태에서&amp;nbsp;&lt;b&gt;방문하지 않은 노드 &lt;/b&gt;&lt;b&gt;중 가장 비용이 적은 대상 노드&lt;/b&gt;는 어디일까? A노드에서 다른 간선으로 가는 비용이 0인 간선이 존재하지 않는다면, 당연히 A노드일 것이다. &lt;b&gt;또한, 그러한 값이 존재한다고 하더라도 첫 번째 단계에서는 '&lt;/b&gt;&lt;b&gt;A노드에서 A노드로 가는 지점이 가장 짧다'라고 그냥 정의&lt;/b&gt;하고 시작한다. 즉, 첫 번째 단계에서는 가장 비용이 적은 노드를 선택할 기준이 없기 때문에&amp;nbsp;&lt;b&gt;출발지인 A노드 자신을 초기 선택 노드로 초기화&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyqhF/btqZP26PpBS/jZFwHhRPmq19Vfb7lx7dcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyqhF/btqZP26PpBS/jZFwHhRPmq19Vfb7lx7dcK/img.png&quot; data-alt=&quot;아직 A노드를 방문하지는 않았지만, A노드에서 A노드로 가는 비용이 가장 적다라고 정의한 상태.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyqhF/btqZP26PpBS/jZFwHhRPmq19Vfb7lx7dcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyqhF%2FbtqZP26PpBS%2FjZFwHhRPmq19Vfb7lx7dcK%2Fimg.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아직 A노드를 방문하지는 않았지만, A노드에서 A노드로 가는 비용이 가장 적다라고 정의한 상태.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;lt;알고리즘 적용&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;초기화가 끝났으니, 이제 앞서 언급한 두 가지 논리를 그냥 반복해서 적용하면 끝이다. 위 상태에서&amp;nbsp;&lt;b&gt;방문하지 않은 노드 중 가장 비용이 적은 대상 노드&lt;/b&gt;는 어디 인가?&amp;nbsp;&lt;b&gt;당연히 A노드이다.&lt;/b&gt; 또한,&amp;nbsp;&lt;b&gt;A노드를 기준으로 갈 수 있는 인접 노드로의 최소 비용&lt;/b&gt;은 얼마일까? 결과는 아래와 같을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;406&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxh3hK/btqZQImIuPQ/lxaCT6jrYkkiFkDIGKhw7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxh3hK/btqZQImIuPQ/lxaCT6jrYkkiFkDIGKhw7K/img.png&quot; data-alt=&quot;A노드 방문 완료.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxh3hK/btqZQImIuPQ/lxaCT6jrYkkiFkDIGKhw7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdxh3hK%2FbtqZQImIuPQ%2FlxaCT6jrYkkiFkDIGKhw7K%2Fimg.png&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;406&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;A노드 방문 완료.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;다음 단계는 어떨까? &lt;b&gt;앞선 단계를 그냥 계속 반복하기만 하면 된다.&lt;/b&gt; 현재 상태에서&amp;nbsp;&lt;b&gt;방문하지 않은 노드 중 가장 비용이 적은 노드&lt;/b&gt;는 어디 인가? A노드는 방문 하였기 때문에 B노드가 될 것이다. 따라서 B노드를 방문하고, B노드와 인접한 노드들의 최소 비용을 갱신해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;424&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0NDYy/btqZRrkJVfN/CKXhckGREW1eqbys82ccFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0NDYy/btqZRrkJVfN/CKXhckGREW1eqbys82ccFK/img.png&quot; data-alt=&quot;B노드에서 C노드로 가는 비용은 9이다. 하지만 이미 C노드로가는 최소 비용이 5이므로 갱신할 필요가 없다. B노드에서 F노드로 가는 비용은 아직 모르므로, 최초 방문 값인 12로 설정해 주었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0NDYy/btqZRrkJVfN/CKXhckGREW1eqbys82ccFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0NDYy%2FbtqZRrkJVfN%2FCKXhckGREW1eqbys82ccFK%2Fimg.png&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;424&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;B노드에서 C노드로 가는 비용은 9이다. 하지만 이미 C노드로가는 최소 비용이 5이므로 갱신할 필요가 없다. B노드에서 F노드로 가는 비용은 아직 모르므로, 최초 방문 값인 12로 설정해 주었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다음 단계도 마찬가지이다. 이제는 A&lt;span style=&quot;color: #333333;&quot;&gt;노드&lt;/span&gt;와 B&lt;span style=&quot;color: #333333;&quot;&gt;노드&lt;/span&gt;를 방문하였기 때문에, 그 중에서 가장 비용이 적은 노드인 D를 선택하고 방문한 뒤 같은 과정을 진행해주면 된다. 이후 과정은 생략하고 그림과 그림 설명으로 대체하도록 하겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;434&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3oV4n/btqZRsDVDoB/yGXXvLuXGk5LuPMIUnPniK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3oV4n/btqZRsDVDoB/yGXXvLuXGk5LuPMIUnPniK/img.png&quot; data-alt=&quot;D노드를 거쳐 C노드로 가는 비용은 4이고, 현재까지 C노드로 가는 최소 비용이 5였기 때문에, D[C]를 4로 갱신할 수 있다. 이전 단계와 마찬가지로, E노드로가는 비용은 미정이었기 때문에 최초 방문 값인 10으로 설정할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3oV4n/btqZRsDVDoB/yGXXvLuXGk5LuPMIUnPniK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3oV4n%2FbtqZRsDVDoB%2FyGXXvLuXGk5LuPMIUnPniK%2Fimg.png&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;434&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;D노드를 거쳐 C노드로 가는 비용은 4이고, 현재까지 C노드로 가는 최소 비용이 5였기 때문에, D[C]를 4로 갱신할 수 있다. 이전 단계와 마찬가지로, E노드로가는 비용은 미정이었기 때문에 최초 방문 값인 10으로 설정할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;455&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bD3NB6/btqZV60H070/2f3H3YAtoUGd5w9jgqe1Sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bD3NB6/btqZV60H070/2f3H3YAtoUGd5w9jgqe1Sk/img.png&quot; data-alt=&quot;그 다음으로 선택된 노드는 C이고, C노드에서 E노드로 가는 값과 F노드로 가는 값은 각각 기존 E노드나 F노드로 가는 비용보다 모두 작다. 따라서 각 값을 갱신할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bD3NB6/btqZV60H070/2f3H3YAtoUGd5w9jgqe1Sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbD3NB6%2FbtqZV60H070%2F2f3H3YAtoUGd5w9jgqe1Sk%2Fimg.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;455&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그 다음으로 선택된 노드는 C이고, C노드에서 E노드로 가는 값과 F노드로 가는 값은 각각 기존 E노드나 F노드로 가는 비용보다 모두 작다. 따라서 각 값을 갱신할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;425&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7fEyM/btqZWNmjozq/gTjXlB6mRIsJuWKmCK1fA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7fEyM/btqZWNmjozq/gTjXlB6mRIsJuWKmCK1fA1/img.png&quot; data-alt=&quot;그 다음으로 선택된 노드는 E이고, E노드에서 F노드로 가는 비용은 기존 F노드로 가는 비용보다 작다. 따라서 그 값을 갱신해 주었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7fEyM/btqZWNmjozq/gTjXlB6mRIsJuWKmCK1fA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7fEyM%2FbtqZWNmjozq%2FgTjXlB6mRIsJuWKmCK1fA1%2Fimg.png&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;425&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그 다음으로 선택된 노드는 E이고, E노드에서 F노드로 가는 비용은 기존 F노드로 가는 비용보다 작다. 따라서 그 값을 갱신해 주었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마지막으로 방문해야하는 노드인 F에서는 &lt;b&gt;더 이상 갈 수 있는 노드가 존재하지 않으므로, 방문만 완료하고 알고리즘을 종료&lt;/b&gt;해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;402&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K5lmL/btqZUV6qeaz/Y6g7S9tPtkod5GPrNkElKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K5lmL/btqZUV6qeaz/Y6g7S9tPtkod5GPrNkElKk/img.png&quot; data-alt=&quot;모든&amp;amp;amp;nbsp;노드 방문 완료.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K5lmL/btqZUV6qeaz/Y6g7S9tPtkod5GPrNkElKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK5lmL%2FbtqZUV6qeaz%2FY6g7S9tPtkod5GPrNkElKk%2Fimg.png&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;402&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;모든&amp;nbsp;노드 방문 완료.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;따라서, 다익스트라 알고리즘에 의한 A&lt;span style=&quot;color: #333333;&quot;&gt;노드&lt;/span&gt;부터 F&lt;span style=&quot;color: #333333;&quot;&gt;노드&lt;/span&gt;까지(혹은 A&lt;span style=&quot;color: #333333;&quot;&gt;노드&lt;/span&gt;부터 각 모든 정점 까지)의 최소 비용은 위와 같은 값을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;*다익스트라 알고리즘의 구현 : O(V^2)&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선 위의 로직을 구현하기 위해서는 &lt;b&gt;입력으로 주어진 그래프를 저장하는 방법&lt;/b&gt;을 알아야 한다. 그래프를 표현하는 방법이 미숙하다면 아래 게시글을 참고하도록 하자.&lt;a href=&quot;https://sskl660.tistory.com/60&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/60&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1615641462808&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java]그래프의 표현&quot; data-og-description=&quot;*그래프의 표현 -&amp;gt;프로그래밍을 하다보면 그래프를 만들어야 하는 경우가 발생할 수 있는데, 프로그래밍에서 그래프를 그리를 방법은 크게 2가지(인접 행렬, 인접 리스트)로 나뉜다. -&amp;gt;인접 행렬 &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/60&quot; data-og-url=&quot;https://sskl660.tistory.com/60&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rlfon/hyJyti4Jex/thLLylMJGV0I7DJhrcOgF1/img.png?width=800&amp;amp;height=434&amp;amp;face=0_0_800_434,https://scrap.kakaocdn.net/dn/berm3Y/hyJypHInVq/wEd08m2n53hucoKLssJ8T1/img.png?width=800&amp;amp;height=434&amp;amp;face=0_0_800_434,https://scrap.kakaocdn.net/dn/keZT6/hyJyskahWY/KE3DlJinhcWWzKqkQaLKJ1/img.png?width=1313&amp;amp;height=562&amp;amp;face=0_0_1313_562&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/60&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/60&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rlfon/hyJyti4Jex/thLLylMJGV0I7DJhrcOgF1/img.png?width=800&amp;amp;height=434&amp;amp;face=0_0_800_434,https://scrap.kakaocdn.net/dn/berm3Y/hyJypHInVq/wEd08m2n53hucoKLssJ8T1/img.png?width=800&amp;amp;height=434&amp;amp;face=0_0_800_434,https://scrap.kakaocdn.net/dn/keZT6/hyJyskahWY/KE3DlJinhcWWzKqkQaLKJ1/img.png?width=1313&amp;amp;height=562&amp;amp;face=0_0_1313_562');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java]그래프의 표현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*그래프의 표현 -&amp;gt;프로그래밍을 하다보면 그래프를 만들어야 하는 경우가 발생할 수 있는데, 프로그래밍에서 그래프를 그리를 방법은 크게 2가지(인접 행렬, 인접 리스트)로 나뉜다. -&amp;gt;인접 행렬&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;한 번 방문한 배열은 방문할 수 없으므로&amp;nbsp;&lt;b&gt;방문&amp;nbsp;&lt;/b&gt;&lt;b&gt;여부를 체크할 배열&lt;/b&gt;이 필요할 것이고, &lt;b&gt;각 &lt;span style=&quot;color: #333333;&quot;&gt;노드&lt;/span&gt; 까지의 최소 비용을 저장할 배열&lt;/b&gt;이 필요할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;구현에서 고려해 주어야 하는 것은, &lt;b&gt;미방문 지점의 값을 항상 최소의 값으로 갱신하는 것이 목표&lt;/b&gt;이기 때문에, &lt;b&gt;미 방문 지점은 매우 큰 값으로 초기화&lt;/b&gt;하여 로직을 처리해주면 된다(구할 수 있다면, 노드가 가질 수 있는 최대 비용을 넣어두어도 된다).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;b&gt;최소 비용을 갖는 노드을 선택하는 과정&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;은 앞선 일반적인 구현에서는&amp;nbsp;&lt;/span&gt;&lt;b&gt;최악의 경우 모든 노드을 확인해야 하고, 이 것은 V번 반복하기 때문에 O(V^2)&lt;/b&gt;&lt;b&gt;의 시간 복잡도&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;를 갖는다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1615640949320&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Graph;

import java.util.ArrayList;
import java.util.Scanner;

/*
sample input
5 6
1
5 1 1
1 2 2
1 3 3
2 3 4
2 4 5
3 4 6
 */

// 도착 지점과, 도착지점으로 가는 비용을 의미하는 클래스를 정의한다.
class Node {
	int idx;
	int cost;

	// 생성자
	Node(int idx, int cost) {
		this.idx = idx;
		this.cost = cost;
	}
}

public class Dijkstra {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 노드와 간선의 개수
		int V = sc.nextInt();
		int E = sc.nextInt();
		// 출발지점
		int start = sc.nextInt();

		// 1. 인접리스트를 이용한 그래프 초기화
		ArrayList&amp;lt;ArrayList&amp;lt;Node&amp;gt;&amp;gt; graph = new ArrayList&amp;lt;ArrayList&amp;lt;Node&amp;gt;&amp;gt;();
		// 노드의 번호가 1부터 시작하므로, 0번 인덱스 부분을 임의로 만들어 놓기만 한다.
		for (int i = 0; i &amp;lt; V + 1; i++) {
			graph.add(new ArrayList&amp;lt;&amp;gt;());
		}
		// 그래프에 값을 넣는다.
		for (int i = 0; i &amp;lt; E; i++) {
			// a로 부터 b로 가는 값은 cost이다.
			int a = sc.nextInt();
			int b = sc.nextInt();
			int cost = sc.nextInt();

			graph.get(a).add(new Node(b, cost));
		}

		// 2. 방문 여부를 확인할 boolean 배열, start 노드부터 end 노드 까지의 최소 거리를 저장할 배열을 만든다.
		boolean[] visited = new boolean[V + 1];
		int[] dist = new int[V + 1];

		// 3. 최소 거리 정보를 담을 배열을 초기화 한다.
		for (int i = 0; i &amp;lt; V + 1; i++) {
			// 출발 지점 외 나머지 지점까지의 최소 비용은 최대로 지정해둔다.
			dist[i] = Integer.MAX_VALUE;
		}
		// 출발 지점의 비용은 0으로 시작한다.
		dist[start] = 0;

		// 4. 다익스트라 알고리즘을 진행한다.
		// 모든 노드을 방문하면 종료하기 때문에, 노드의 개수 만큼만 반복을 한다.
		for (int i = 0; i &amp;lt; V; i++) {
			// 4 - 1. 현재 거리 비용 중 최소인 지점을 선택한다.
			// 해당 노드가 가지고 있는 현재 비용.
			int nodeValue = Integer.MAX_VALUE;
			// 해당 노드의 인덱스(번호).
			int nodeIdx = 0;
			// 인덱스 0은 생각하지 않기 때문에 0부터 반복을 진행한다.
			for (int j = 1; j &amp;lt; V + 1; j++) {
				// 해당 노드를 방문하지 않았고, 현재 모든 거리비용 중 최솟값을 찾는다.
				if (!visited[j] &amp;amp;&amp;amp; dist[j] &amp;lt; nodeValue) {
					nodeValue = dist[j];
					nodeIdx = j;
				}
			}
			// 최종 선택된 노드를 방문처리 한다.
			visited[nodeIdx] = true;

			// 4 - 2. 해당 지점을 기준으로 인접 노드의 최소 거리 값을 갱신한다.
			for (int j = 0; j &amp;lt; graph.get(nodeIdx).size(); j++) {
				// 인접 노드를 선택한다.
				Node adjNode = graph.get(nodeIdx).get(j);
				// 인접 노드가 현재 가지는 최소 비용과
				// 현재 선택된 노드의 값 + 현재 노드에서 인접 노드로 가는 값을 비교하여 더 작은 값으로 갱신한다.
				if (dist[adjNode.idx] &amp;gt; dist[nodeIdx] + adjNode.cost) {
					dist[adjNode.idx] = dist[nodeIdx] + adjNode.cost;
				}
			}
		}

		// 5. 최종 비용을 출력한다.
		for (int i = 1; i &amp;lt; V + 1; i++) {
			if (dist[i] == Integer.MAX_VALUE) {
				System.out.println(&quot;INF&quot;);
			} else {
				System.out.println(dist[i]);
			}
		}
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;*다익스트라 알고리즘의 구현(우선순위 큐 이용) : O((V+E)log V)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;기본적으로 다익스트라 알고리즘은&amp;nbsp;&lt;b&gt;최소 비용을 갖는 노드를 선택&lt;/b&gt;하고,&amp;nbsp;&lt;b&gt;주변 노드의 값을 갱신&lt;/b&gt;하였다. 그렇다면,&amp;nbsp;&lt;b&gt;비용을 나타내는 배열에서 갱신된 노드를 제외하고는 여전히 INF의 값을 갖기 때문에 굳이 고려해줄 필요가 없음&lt;/b&gt;을 알게 된다. 즉,&amp;nbsp;&lt;u&gt;&lt;b&gt;갱신하는 주변 노드의 값에 대해서만 다음 최소 비용을 갖는 노드를 선택해주면 된다는 것&lt;/b&gt;&lt;/u&gt;이 우선순위큐를 이용하는 것의 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;&lt;b&gt;우선 순위큐에 들어가는 노드의 수&lt;/b&gt;&amp;nbsp;&lt;b&gt;= 갱신해야하는 주변 노드의 수&lt;/b&gt;라고 하였다. 이 말을 다르게하면, &lt;b&gt;갱신해야하는 주변 노드의 수 = 갱신해야 하는 주변 노드로의 간선의 수&lt;/b&gt;를 말한다. 즉, &lt;b&gt;&lt;u&gt;우선 순위 큐에 삽입하는 최대 횟수&lt;/u&gt;는 간선의 개수&lt;/b&gt;이다. 따라서, 모든 간선에 대하여 삽입 연산이 발생하기 때문에 &lt;b&gt;최대 O(&lt;/b&gt;&lt;b&gt;ElogE)&lt;/b&gt;의 시간이 걸릴 것이다.&amp;nbsp;그런데,&amp;nbsp;&lt;b&gt;희소 그래프의 경우 E &amp;lt;= V^2이므로, 최대 O(ElogV)&lt;/b&gt;의 시간이 걸린다고도 볼 수 있다.&amp;nbsp; 각 노드들을 &lt;u&gt;&lt;b&gt;우선순위큐에 추출해주는 연산&lt;/b&gt;&lt;/u&gt;에대해서는 최대 V개의 노드에 대하여 우선순위큐에서 추출할 것이므로 &lt;b&gt;최대 O(VlogV)&lt;/b&gt;의 시간이 걸릴 것이고 따라서 &lt;u&gt;&lt;b&gt;최대 모든 노드, 간선에대하여 우선 순위큐를 계산해줘야 하므로 O((V+E)logV)의 시간이 걸릴 것&lt;/b&gt;&lt;/u&gt; 이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;b&gt;※주의할 점&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;우선 순위큐에 넣는 다음 노드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최소 비용으로 선택된 노드의 주변 노드&lt;/b&gt;라고 하였다. 그런데, 이 주변 노드를&amp;nbsp;&lt;u&gt;&lt;b&gt;무차별적으로 우선순위큐에 넣고 무차별적으로 검사를 한다면 문제가 발생&lt;/b&gt;&lt;/u&gt;한다. 즉, 최소 비용으로 뽑은 노드의&amp;nbsp;&lt;b&gt;방문 체크를 하지 않는 경우&lt;/b&gt;와&amp;nbsp;&lt;b&gt;갱신이 이루어 지지 않는 노드까지 우선 순위큐에 넣는 경우&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;모두&amp;nbsp;&lt;u&gt;&lt;b&gt;중복된 노드를 재 방문 하게 되는 문제가 발생&lt;/b&gt;&lt;/u&gt;한다. 자세한 내용은 아래 코드의 주석을 참고하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;시간 복잡도의 핵심은 poll() 연산(최소 비용을 뽑는 연산)과 offer() 연산(최소 비용 후보를 우선 순위큐에 넣는 연산)이다. 만일, 중복 노드를 무차별적으로 큐에 넣는다면 위에서 결과적으로 말한 &lt;b&gt;최대 V개의 노드에서 우선순위큐를 추출하는 O(VlogV)가 보장되지 못한다.&lt;/b&gt; 따라서, 중복 노드 방문을 두 가지 조건을 기반으로 방지한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1615645239794&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Graph;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

/*
sample input
5 6
1
5 1 1
1 2 2
1 3 3
2 3 4
2 4 5
3 4 6
 */

public class Dijkstra2 {
	static int V, E, start;
	static ArrayList&amp;lt;ArrayList&amp;lt;Node&amp;gt;&amp;gt; graph;

	static class Node {// 다음 노드의 인덱스와, 그 노드로 가는데 필요한 비용을 담고 있다.
		int idx, cost;

		Node(int idx, int cost) {
			this.idx = idx;
			this.cost = cost;
		}
	}

	public static void main(String[] args) throws IOException {
		// 초기화
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		V = Integer.parseInt(st.nextToken());
		E = Integer.parseInt(st.nextToken());
		start = Integer.parseInt(br.readLine());
		graph = new ArrayList&amp;lt;ArrayList&amp;lt;Node&amp;gt;&amp;gt;();
		for (int i = 0; i &amp;lt; V + 1; i++) {
			graph.add(new ArrayList&amp;lt;Node&amp;gt;());
		}
		for (int i = 0; i &amp;lt; E; i++) {
			st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			int c = Integer.parseInt(st.nextToken());
			// 문제에서는 유향 그래프에서의 다익스트라 알고리즘(이 조건도 문제에 따라 중요하다!).
			graph.get(s).add(new Node(e, c));
		}

		// 다익스트라 알고리즘 초기화
		int[] dist = new int[V + 1]; // 최소 비용을 저장할 배열
		for (int i = 0; i &amp;lt; V + 1; i++) {
			dist[i] = Integer.MAX_VALUE;
		}

		// 주의점 1. 다익스트라 알고리즘의 최소비용을 기준으로 추출해야 한다. 최대 비용을 기준으로 하는 경우 최악의 경우 지수시간 만큼의 연산을
		// 해야한다!
		PriorityQueue&amp;lt;Node&amp;gt; q = new PriorityQueue&amp;lt;Node&amp;gt;((o1, o2) -&amp;gt; Integer.compare(o1.cost, o2.cost));
		// 시작 노드에서, 시작 노드로 가는 값이 초기에 가장 짧은 비용을 갖는 노드이다.
		// 즉, 도착 정점은 start, 비용은 0인 노드를 가장 먼저 선택할 것이다.
		q.offer(new Node(start, 0));
		// 해당 노드를 선택한 것이나 마찬가지 이므로, dist[start] = 0으로 갱신.
		dist[start] = 0;
		while (!q.isEmpty()) {
			Node curNode = q.poll();

			// 목표 정점이 꺼내 졌다면, 해당 노드까지는 최솟값 갱신이 완료 되었다는 것이 확정이다(다익스트라 알고리즘).
			// 따라서, 반복문을 종료해도 되지만, 해당 코드는 시작 정점에 대하여 모든 정점으로의 최단 경로를 구하는 것을 가정한다.
			// 아래 주석된 코드는 목표 정점이 구해졌다면 빠르게 탈출할 수 있는 조건이다.
//			if (curNode.idx == end) {
//				System.out.println(dist[curNode.idx]);
//				return;
//			}

			// 꺼낸 노드 = 현재 최소 비용을 갖는 노드.
			// 즉, 해당 노드의 비용이 현재 dist배열에 기록된 내용보다 크다면 고려할 필요가 없으므로 스킵한다.
			// 주의점 2 : 중복노드 방지1 : 만일, 이 코드를 생략한다면, 언급한 내용대로 이미 방문한 정점을 '중복하여 방문'하게 된다.
			// 만일 그렇다면, 큐에 있는 모든 다음 노드에대하여 인접노드에 대한 탐색을 다시 진행하게 된다.
			// 그래프 입력이 만일 완전 그래프의 형태로 주어진다면, 이 조건을 생략한 것 만으로 시간 복잡도가 E^2에 수렴할 가능성이 생긴다.
			if (dist[curNode.idx] &amp;lt; curNode.cost) {
				continue;
			}

			// 선택된 노드의 모든 주변 노드를 고려한다.
			for (int i = 0; i &amp;lt; graph.get(curNode.idx).size(); i++) {
				Node nxtNode = graph.get(curNode.idx).get(i);
				// 만일, 주변 노드까지의 현재 dist값(비용)과 현재 선택된 노드로부터 주변 노드로 가는 비용을 비교하고, 더 작은 값을 선택한다.
				// 주의점 3 : 중복노드 방지 2 : 만일, 조건문 없이 조건문의 내용을 수행한다면 역시 중복 노드가 발생한다.
				// 간선에 연결된 노드를 모두 넣어준다면 앞서 언급한 정점의 시간 복잡도 VlogV를 보장할 수 없다.
				// 마찬가지로 E^2에 수렴할 가능성이 생긴다. 따라서 이 조건 안에서 로직을 진행해야만 한다.
				if (dist[nxtNode.idx] &amp;gt; curNode.cost + nxtNode.cost) {
					dist[nxtNode.idx] = curNode.cost + nxtNode.cost;
					// 갱신된 경우에만 큐에 넣는다.
					q.offer(new Node(nxtNode.idx, dist[nxtNode.idx]));
				}
			}
		}

		// 결과 출력
		System.out.println(Arrays.toString(dist));
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*다익스트라 알고리즘 정당성 증명&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;다익스트라 알고리즘의 정당성을 증명하기 위하여 위키백과등을 참고하면 복잡한 수식으로 표현되어 있어 이해하기가 어려운 편인데, 여기에서는 조금 더 직관적인 설명으로 정당성을 이해해보도록 하겠다. 원래는&amp;nbsp;&lt;b&gt;수학적 귀납법을 이용하여 엄밀하게 증명해야 하지만&lt;/b&gt;, 여기서는 직관적인 이해에 초점을 맞추어 기술하도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우선, 다익스트라 알고리즘을 진행하며 우리는 매번&amp;nbsp;&lt;b&gt;현재 최소 비용을 갖는 노드를 선택&lt;/b&gt;하였다. 여기서 눈치가 빠른 사람이라면 알고 있었겠지만, 자세히 확인해보면&amp;nbsp;&lt;b&gt;그렇게 선택이 된 노드는 다익스트라 알고리즘이 모든 노드를 방문할 때까지&lt;/b&gt;(즉, 알고리즘이 종료될 때 까지)&lt;b&gt; 최소 비용의 갱신이 더 이상 이루어지지 않았다&lt;/b&gt;는 점을 알 수 있다(갱신 되는 노드는 아직 선택되지 않은 노드들에 대해서만 이루어지고 있다!).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;어쨋든 &lt;b&gt;최소 비용을 갖는 노드로 선택이 되었다면, 그 노드는 앞으로 다른 노드를 방문하는 것과 관계없이 항상 값이 갱신되지 않을 것&lt;/b&gt;이라는 말이다.&amp;nbsp;&lt;b&gt;다익스트라 알고리즘은 이 명제를 이용하여 정당성을 증명&lt;/b&gt;한다(왜냐하면, 이 명제가 참이라면 모든 노드에 대한 방문을 완료 하였을때 각 노드는 최솟값을 가지고 있을 것이다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;글로만 적어서는 여러가지 수식을 써야하고, 이해도 잘 안되기 때문에 아래 그림을 참고하며 이해하도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 최소비용이 갱신되지 않는 이유&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;첫 부분에서 언급하였지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다익스트라 알고리즘은 그리디 알고리즘&lt;/b&gt;이다. 쉽게 말해 다익스트라 알고리즘의 기본적인 아이디어는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'최단 거리는 최단 거리로 이루어져 있다'&lt;/b&gt;, 다르게 말해&lt;b&gt; '최단 거리를 이어 붙여서 최단 거리를 만든다'&lt;/b&gt;는 것이다. 즉, 그리디 알고리즘의 최적 부분 구조 조건이 성립하기 때문에 위와 같은 결과가 발생하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 다익스트라 알고리즘 증명&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;&lt;b&gt;가설&lt;/b&gt;&lt;b&gt; : 이미 선택된 노드는 최단 거리가 갱신되지 않는다(즉, 다익스트라 알고리즘으로 선택된 노드는 최종 최소 비용이다).&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;우리는 지금부터 이 가설을 증명하기 위해 &lt;u&gt;&lt;b&gt;귀류법을 사용&lt;/b&gt;&lt;/u&gt;할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) &lt;u&gt;&lt;b&gt;이미 선택된 노드는 앞으로 선택되는 노드에 의해서 최단 거리가 갱신이 된다라고 가정&lt;/b&gt;&lt;/u&gt;해보자.&amp;nbsp;&lt;b&gt;즉, 이후 선택하는노드를 거쳐 들어오는 더 짧은 최단 경로가 존재한다&lt;/b&gt;고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) &lt;b&gt;&lt;u&gt;만일 그러한 노드가 존재한다면, &lt;/u&gt;&lt;u&gt;&lt;b&gt;해&lt;/b&gt;당 노드는 적어도 한 번 다익스트라 알고리즘을 이용해 거쳐온 노드외의 노드를 지나야만 한다.&lt;/u&gt; &lt;/b&gt;이 사실은 조금만 생각해보면 당연한 이야기이다. 왜냐하면, &lt;b&gt;다익스트라 알고리즘으로 선택되어진 모든 노드만을 거쳐서 지나온다면, 해당 노드는 다익스트라 알고리즘으로 선택된 노드의 최소 비용을 갱신할 수 없다.&lt;/b&gt; 아래 그림을 보며 이해해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;553&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9PNU6/btqZ1bu4I9i/xJ9qsCYuhCCkkvc3kI0kXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9PNU6/btqZ1bu4I9i/xJ9qsCYuhCCkkvc3kI0kXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9PNU6/btqZ1bu4I9i/xJ9qsCYuhCCkkvc3kI0kXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9PNU6%2FbtqZ1bu4I9i%2FxJ9qsCYuhCCkkvc3kI0kXK%2Fimg.png&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;553&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 즉, 다음과 같이 다익스트라 알고리즘으로 선택된 경로 외에 다른 노드에서 들어오는 경로가 존재할 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;386&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNOjM8/btqZ0sDOkv2/RkU7PGfllHr3N4VhSMM4FK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNOjM8/btqZ0sDOkv2/RkU7PGfllHr3N4VhSMM4FK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNOjM8/btqZ0sDOkv2/RkU7PGfllHr3N4VhSMM4FK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNOjM8%2FbtqZ0sDOkv2%2FRkU7PGfllHr3N4VhSMM4FK%2Fimg.png&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;386&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) 하지만 이 사실은 잘 생각해보면&amp;nbsp;&lt;b&gt;모순되는 부분을 가지고 있다.&lt;/b&gt; 어떤 부분일까? 애초에 다익스트라 알고리즘이 어떻게 진행되고 있었는지를 생각해보자.&amp;nbsp;&lt;b&gt;&lt;u&gt;다익스트라 알고리즘에서 다음 노드를 선택하는 기준이 무엇이었는가?&lt;/u&gt; 그렇다. 'E'라는 노드를 선택하는 기준은 현재 E가 가지고 있는 비용이 최소였기 때문에 선택한 것이다!&lt;/b&gt; 그런데, 만약 저러한 노드가 존재하는 상황이 발생한다면&amp;nbsp;&lt;b&gt;우리는 정해진 규칙에 따라서 다익스트라 알고리즘을 진행하지 않은 것이다.&lt;/b&gt; 만일, 해당 노드를 Z라고 가정한다면 &lt;b&gt;&lt;u&gt;Z부터 E까지의 간선의 길이는 0 보다 큰 값을 가지고 있을 것(음의 가중치를 가지면 안되는 이유)&lt;/u&gt;&lt;/b&gt;이다. 즉,&amp;nbsp;&lt;u&gt;&lt;b&gt;시작 노드 S부터 노드 Z까지의 길이는 시작 노드 S부터 E까지의 거리보다&lt;/b&gt;&lt;b&gt; 짧다!&lt;/b&gt;&lt;/u&gt; 다익스트라 알고리즘은 분명 매번 최소 비용을 갖는 노드만을 선택한다고 하였는데, 그것보다 더 짧은 비용을 갖는 노드가 존재한다고하면 당연히 모순이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;577&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIA8Kl/btqZ6jZHKxb/3UHmVfPxaok2AACjCPRkU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIA8Kl/btqZ6jZHKxb/3UHmVfPxaok2AACjCPRkU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIA8Kl/btqZ6jZHKxb/3UHmVfPxaok2AACjCPRkU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIA8Kl%2FbtqZ6jZHKxb%2F3UHmVfPxaok2AACjCPRkU1%2Fimg.png&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;577&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(5) 즉,&amp;nbsp;&lt;b&gt;초기에 설정한 가정&lt;/b&gt;(이미 선택된 노드는 앞으로 선택되는 정점에 의해서 최단 거리가 갱신이 된다)&lt;b&gt;은 모순&lt;/b&gt;이다. 즉,&amp;nbsp;&lt;b&gt;귀류 가정이 모순이므로, 본 명제는 참&lt;/b&gt;임을 알 수 있다. 수식을 이용한 증명은 위키백과 정확성 증명부분을 참고하도록하자. &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1615659998109&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;데이크스트라 알고리즘&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 컴퓨터 과학에서, 데이크스트라 알고리즘(영어: Dijkstra algorithm) 또는 다익스트라 알고리즘은 도로 교통망 같은 곳에서 나타날 수 있는 그래프에서 꼭짓점 간의 &quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gpYRJ/hyJymRUkQM/YLAQZiDAC7jXOFbqwMcA5K/img.gif?width=283&amp;amp;height=222&amp;amp;face=0_0_283_222,https://scrap.kakaocdn.net/dn/bIMNjI/hyJynJ12L9/k832KL2svGx0TaRkzMBdT1/img.png?width=220&amp;amp;height=218&amp;amp;face=0_0_220_218&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gpYRJ/hyJymRUkQM/YLAQZiDAC7jXOFbqwMcA5K/img.gif?width=283&amp;amp;height=222&amp;amp;face=0_0_283_222,https://scrap.kakaocdn.net/dn/bIMNjI/hyJynJ12L9/k832KL2svGx0TaRkzMBdT1/img.png?width=220&amp;amp;height=218&amp;amp;face=0_0_220_218');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;데이크스트라 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;위키백과, 우리 모두의 백과사전. 컴퓨터 과학에서, 데이크스트라 알고리즘(영어: Dijkstra algorithm) 또는 다익스트라 알고리즘은 도로 교통망 같은 곳에서 나타날 수 있는 그래프에서 꼭짓점 간의&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/그래프&amp;amp;최단경로</category>
      <category>Dijkstrra algorithm</category>
      <category>java</category>
      <category>다익스트라 알고리즘</category>
      <category>다익스트라 알고리즘 자바</category>
      <category>다익스트라 알고리즘 정당성 증명</category>
      <category>다익스트라 알고리즘 증명</category>
      <category>데이크스트라 알고리즘 자바</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/59</guid>
      <comments>https://sskl660.tistory.com/59#entry59comment</comments>
      <pubDate>Fri, 12 Mar 2021 00:40:29 +0900</pubDate>
    </item>
    <item>
      <title>[Java]순열과 다음 순열</title>
      <link>https://sskl660.tistory.com/55</link>
      <description>&lt;p&gt;&lt;b&gt;*재귀를 이용한 순열 구하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 처음에는, &lt;b&gt;재귀를 이용하여 모든 순열&lt;/b&gt;을 구하였다. 하지만&amp;nbsp;&lt;b&gt;이전에 공부한 다음 순열을 이용하여도 모든 순열을 구할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href=&quot;https://sskl660.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/48&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1614261778156&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 순열(Permutation)&quot; data-og-description=&quot;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231, &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/48&quot; data-og-url=&quot;https://sskl660.tistory.com/48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ddxxxU/hyJnZQF99S/Upt6qpD0Xz8QiNYTxgHfG0/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/fCD80/hyJnZpAdsw/v33hqOQw31ta7qHIZYYEWk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/eH1UR/hyJn809v6T/qDRAbINUjjygmXQtLJfDI1/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ddxxxU/hyJnZQF99S/Upt6qpD0Xz8QiNYTxgHfG0/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/fCD80/hyJnZpAdsw/v33hqOQw31ta7qHIZYYEWk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/eH1UR/hyJn809v6T/qDRAbINUjjygmXQtLJfDI1/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Java] 순열(Permutation)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231,&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;b&gt;&lt;a href=&quot;https://sskl660.tistory.com/54&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/54&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1614261768649&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java]다음 순열(Next Permutation)&quot; data-og-description=&quot;*다음 순열(Next Permutation). -&amp;gt; 다음 순열이란, 말 그대로 해당 숫자의 다음에 올 순열의 수를 의미한다. Ex) {1, 2, 3}에서 3개를 선택하는 경우 순열은 123, 132, 213, 231, 312, 321이 있다. 그렇다면 123..&quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/54&quot; data-og-url=&quot;https://sskl660.tistory.com/54&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dSEydV/hyJoadATwG/dLpWVOPjN6VFmPB5rCo7Q1/img.png?width=165&amp;amp;height=317&amp;amp;face=0_0_165_317,https://scrap.kakaocdn.net/dn/3Uzh5/hyJnX6oFVF/boQc01PWc3kmAQjAotTeK0/img.png?width=165&amp;amp;height=317&amp;amp;face=0_0_165_317,https://scrap.kakaocdn.net/dn/G68vN/hyJn4YJGa5/pVXEcaWJufMzdGRPTExrx0/img.png?width=401&amp;amp;height=214&amp;amp;face=0_0_401_214&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/54&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/54&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dSEydV/hyJoadATwG/dLpWVOPjN6VFmPB5rCo7Q1/img.png?width=165&amp;amp;height=317&amp;amp;face=0_0_165_317,https://scrap.kakaocdn.net/dn/3Uzh5/hyJnX6oFVF/boQc01PWc3kmAQjAotTeK0/img.png?width=165&amp;amp;height=317&amp;amp;face=0_0_165_317,https://scrap.kakaocdn.net/dn/G68vN/hyJn4YJGa5/pVXEcaWJufMzdGRPTExrx0/img.png?width=401&amp;amp;height=214&amp;amp;face=0_0_401_214');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Java]다음 순열(Next Permutation)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;*다음 순열(Next Permutation). -&amp;gt; 다음 순열이란, 말 그대로 해당 숫자의 다음에 올 순열의 수를 의미한다. Ex) {1, 2, 3}에서 3개를 선택하는 경우 순열은 123, 132, 213, 231, 312, 321이 있다. 그렇다면 123..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;-&amp;gt;&amp;nbsp;&lt;u&gt;보통 재귀를 이용한 방식은 생각보다&amp;nbsp;&lt;b&gt;메모리와 시간을 다음 순열을 이용한 방법보다 더 잡아 먹는다.&lt;/b&gt; 따라서, &lt;b&gt;다음 순열을 반복적으로 구하는 과정을 통하여 순열을 구하는 방법을 연습하도록 하자.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*다음 순열을 이용한 모든 순열 구하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; &lt;b&gt;첫 순열을 포함하여, (모든 순열의 경우의수(nPn) - 1)번 만큼 다음 순열을 구해준다면&lt;/b&gt; &lt;b&gt;모든 순열&lt;/b&gt;을 구할 수 있다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 예를 들어 집합 {1, 2, 3}에서 3개를 선택한 모든 순열을 다음 순열을 이용하여 구현해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1614262071347&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package cases;

import java.util.Arrays;

public class Permutation2 {
	static int[] nums = { 1, 2, 3 };

	public static void main(String[] args) {
		// 순열의 총 개수를 구한다.
		int per_num = 1;
		for (int i = 1; i &amp;lt;= nums.length; i++) {
			per_num *= i;
		}
		System.out.println(&quot;순열의 총 개수  = &quot; + per_num);

		// 해당 순열의 개수 만큼 다음 순열을 구한다.
		for (Integer num : nums) {
			System.out.print(num + &quot; &quot;);
		}
		System.out.println();
		for (int i = 0; i &amp;lt; per_num - 1; i++) {
			nextPermutation();
			System.out.println();
		}
	}

	private static void nextPermutation() {
		// 주어진 순열의 뒤부터 탐색하며, 증가하는 부분을 찾는다.
		int idx = 0;
		int N = nums.length;
		for (int i = N - 1; i &amp;gt; 0; i--) {
			if (nums[i - 1] &amp;lt; nums[i]) {
				idx = i;
				break;
			}
		}

		// 해당 인덱스를 기준으로, 좌/우지점을 나눈다.
		// 좌측의 제일 오른쪽 숫자에 대하여, 우측의 제일 오른쪽 지점부터 탐색하며 큰 수를 찾는다.
		// 해당 숫자를 찾았다면 각 숫자를 서로 Swap한다.
		for (int i = N - 1; i &amp;gt;= idx; i--) {
			if (nums[idx - 1] &amp;lt; nums[i]) {
				int temp = nums[idx - 1];
				nums[idx - 1] = nums[i];
				nums[i] = temp;
				break;
			}
		}

		// 우측 지점을 정렬한다.
		Arrays.sort(nums, idx, N);

		// 결과 출력
		for (Integer num : nums) {
			System.out.print(num + &quot; &quot;);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SKEBn/btqYAuoG6ND/DnBkoc8qUFkfioDcJFZjuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SKEBn/btqYAuoG6ND/DnBkoc8qUFkfioDcJFZjuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SKEBn/btqYAuoG6ND/DnBkoc8qUFkfioDcJFZjuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSKEBn%2FbtqYAuoG6ND%2FDnBkoc8qUFkfioDcJFZjuk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;※ 만일,&amp;nbsp;&lt;b&gt;주어진 수 부터의 모든 다음 순열&lt;/b&gt;을 구하고 싶다면, 일전에 공부한 &lt;b&gt;'다음 순열은 원소가 증가하는 부분이 존재하지 않으면 존재하지 않는다'는 점&lt;/b&gt;을 이용하여 구하면 된다.&lt;/p&gt;</description>
      <category>Algorithm/완전 탐색</category>
      <category>Next permutation</category>
      <category>permutation</category>
      <category>다음 순열</category>
      <category>다음 순열을 이용한 모든 순열 구하기</category>
      <category>순열</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/55</guid>
      <comments>https://sskl660.tistory.com/55#entry55comment</comments>
      <pubDate>Thu, 25 Feb 2021 23:10:02 +0900</pubDate>
    </item>
    <item>
      <title>[Java]다음 순열(Next Permutation)</title>
      <link>https://sskl660.tistory.com/54</link>
      <description>&lt;p&gt;&lt;b&gt;*다음 순열(Next Permutation).&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 다음 순열이란, 말 그대로 &lt;b&gt;해당 숫자의 다음에 올 순열의 수&lt;/b&gt;를 의미한다.&lt;/p&gt;
&lt;p&gt;Ex) {1, 2, 3}에서 3개를 선택하는 경우 순열은 123, 132, 213, 231, 312, 321이 있다. 그렇다면 123 다음에 올 순열은 무엇일까? 132이다. 즉,&amp;nbsp;&lt;b&gt;123의 다음 순열은 132&lt;/b&gt;임을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*다음 순열 구하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 다음 순열을 구하는 로직은&lt;u&gt;&amp;nbsp;&lt;b&gt;우리가 무의식적으로 다음 순열을 구하는 로직을 천천히 곱씹으며 구체화&lt;/b&gt;&lt;/u&gt;시켜보면 가능하다.&amp;nbsp;&lt;b&gt;우리는 이미 다음 순열을 구하는 방법을 알고 있다!&lt;/b&gt;(다만 막상 논리적 순서로 나타내보려 하면 헷갈리고 어려울 뿐이다...)&lt;/p&gt;
&lt;p&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;&lt;u&gt;규칙성을 찾기 위해서는, 작은 경우부터 침착하게 내가 어떻게 구하고 있는지 분석&lt;/u&gt;해보면 된다.&lt;/b&gt; 예를 들어, 집합 {1, 2, 3}에서 3개를 선택하는 순열은 다음과 같은 순서로 구한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VpsnZ/btqYDj70Xsv/vegyawbl9WhlPxOGyACJv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VpsnZ/btqYDj70Xsv/vegyawbl9WhlPxOGyACJv1/img.png&quot; data-alt=&quot;우리는 이미 자연스럽게 다음 순열을 구할 줄 안다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VpsnZ/btqYDj70Xsv/vegyawbl9WhlPxOGyACJv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVpsnZ%2FbtqYDj70Xsv%2Fvegyawbl9WhlPxOGyACJv1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;우리는 이미 자연스럽게 다음 순열을 구할 줄 안다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 우선 123의 다음 순열인 132를 구하는 과정을 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBrSVo/btqYus6vvvP/X28vTjITxG8YzwqTwahwk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBrSVo/btqYus6vvvP/X28vTjITxG8YzwqTwahwk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBrSVo/btqYus6vvvP/X28vTjITxG8YzwqTwahwk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBrSVo%2FbtqYus6vvvP%2FX28vTjITxG8YzwqTwahwk1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;우선 우리는&amp;nbsp;&lt;b&gt;해당 수의 뒷 부분 부터 탐색하면서, 크기가 증가하는 부분을 찾는다&lt;/b&gt;(뒤에서 부터 찾으면, 2에서 3으로 증가하는 부분을 먼저 찾을 수 있다).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVtoj0/btqYxoPOCKo/PTkPjLL9IgDGt7gRGb56d1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVtoj0/btqYxoPOCKo/PTkPjLL9IgDGt7gRGb56d1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVtoj0/btqYxoPOCKo/PTkPjLL9IgDGt7gRGb56d1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVtoj0%2FbtqYxoPOCKo%2FPTkPjLL9IgDGt7gRGb56d1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;이렇게 증가하는 부분을 찾았다면,&amp;nbsp;&lt;b&gt;그 부분을 기준으로 좌/우 지점을 구분&amp;nbsp;&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YTtM3/btqYE68pv3X/kYBceAnIH2QZVxbFWDb5R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YTtM3/btqYE68pv3X/kYBceAnIH2QZVxbFWDb5R0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YTtM3/btqYE68pv3X/kYBceAnIH2QZVxbFWDb5R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYTtM3%2FbtqYE68pv3X%2FkYBceAnIH2QZVxbFWDb5R0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;구분된 지점에 대하여,&amp;nbsp;&lt;b&gt;좌측 지점의 가장 끝 숫자에 대하여 우측 지점에서 큰 수를 찾는다. 이때, 큰 수를 찾는 순서는&amp;nbsp;&lt;u&gt;우측 지점의 제일 마지막 부분부터&lt;/u&gt;&lt;u&gt; 시작&lt;/u&gt;&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qZsJ9/btqYAsLaUZr/MsxPJFNIq71LcUXRL9Ks1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qZsJ9/btqYAsLaUZr/MsxPJFNIq71LcUXRL9Ks1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qZsJ9/btqYAsLaUZr/MsxPJFNIq71LcUXRL9Ks1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqZsJ9%2FbtqYAsLaUZr%2FMsxPJFNIq71LcUXRL9Ks1K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그렇게 찾은 숫자를&amp;nbsp;&lt;b&gt;서로 Swap&lt;/b&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;해준다. 다음 순열을 처음 접하는 사람이라면, 우리가 이렇게 복잡한 과정을 당연히 하고 있었다는 사실에 신기함을 느낄 것이다. &lt;b&gt;하지만 여기서 끝난 것이 아니다. 한 가지 과정이 더 남아있는데, 그것은 다음 예시를 참고하자.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 다음으로, 132의 다음 순열인 213을 구하는 과정을 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKxIZN/btqYwgR56Zt/ryAL1T45zxmJvb4rs3IuR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKxIZN/btqYwgR56Zt/ryAL1T45zxmJvb4rs3IuR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKxIZN/btqYwgR56Zt/ryAL1T45zxmJvb4rs3IuR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKxIZN%2FbtqYwgR56Zt%2FryAL1T45zxmJvb4rs3IuR1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;마찬가지로, 해당 수의 뒷 부분부터 탐색하면서 증가하는 부분을 찾는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG4ar6/btqYrEGjQp4/0K0kxDGFDy3HYkf0mkqSCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG4ar6/btqYrEGjQp4/0K0kxDGFDy3HYkf0mkqSCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG4ar6/btqYrEGjQp4/0K0kxDGFDy3HYkf0mkqSCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG4ar6%2FbtqYrEGjQp4%2F0K0kxDGFDy3HYkf0mkqSCk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그 부분을 찾았다면, 그 지점을 기준으로 좌/우 지점을 구분한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAdt5B/btqYtPua8XJ/mOkXVG5aZMGSVWZpeQ8rLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAdt5B/btqYtPua8XJ/mOkXVG5aZMGSVWZpeQ8rLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAdt5B/btqYtPua8XJ/mOkXVG5aZMGSVWZpeQ8rLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAdt5B%2FbtqYtPua8XJ%2FmOkXVG5aZMGSVWZpeQ8rLk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;구분된 지점 좌측의 가장 우측 숫자에 대하여 우측 지점의 우측 끝 부분 부터 탐색하면서, 더 큰 수를 찾는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTF1bj/btqYB5IW3eJ/hVEqM3k5uvVQiYzfUkfVD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTF1bj/btqYB5IW3eJ/hVEqM3k5uvVQiYzfUkfVD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTF1bj/btqYB5IW3eJ/hVEqM3k5uvVQiYzfUkfVD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTF1bj%2FbtqYB5IW3eJ%2FhVEqM3k5uvVQiYzfUkfVD0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그 숫자를 찾았다면, 각 숫자를 서로 Swap해준다.&amp;nbsp;&lt;b&gt;하지만, 132의 다음 순열은 213인데 231이 나온 것&lt;/b&gt;을 확인할 수 있다. 즉, 아직 한 가지 로직이 더 남아 있음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wDIHS/btqYAtceUyE/MmNiZGzOSWskJjckUg0av1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wDIHS/btqYAtceUyE/MmNiZGzOSWskJjckUg0av1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wDIHS/btqYAtceUyE/MmNiZGzOSWskJjckUg0av1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwDIHS%2FbtqYAtceUyE%2FMmNiZGzOSWskJjckUg0av1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;마지막으로,&amp;nbsp;&lt;b&gt;나눠진 지점의 우측 부분의 모든 수를 '오름차순' 정렬 해준다.&lt;/b&gt; 여기까지가 우리가 다음 순열을 구할 때 무의식적으로 하던 행위이다.&amp;nbsp;&lt;b&gt;이렇게, 규칙성을 찾는 문제는 작은 문제부터 시작하여 자신의 로직이 맞는지 천천히 검증한다면 다음 순열 뿐 만 아니라 다른 문제도 비교적 쉽게 규칙성을 찾을 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 이제부터는&amp;nbsp;&lt;b&gt;단순히 '구현'의 문제&lt;/b&gt;이다. 이 모든 과정을 코드로 구현하기만 하면 된다. 아래 예시는 입력된 수의 다음 순열을 구하는 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1614260258351&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package cases;

import java.util.Arrays;
import java.util.Scanner;

public class NextPermutation {
	static int[] input;
	static int N;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 입력받은 수를 배열에 저장.
		String line = sc.nextLine();
		N = line.length();
		input = new int[N];

		for (int i = 0; i &amp;lt; line.length(); i++) {
			input[i] = line.charAt(i) - '0';
		}

		// 다음 순열.
		nextPermutation();
		sc.close();
	}

	private static void nextPermutation() {
		// 주어진 순열의 뒤부터 탐색하며, 증가하는 부분을 찾는다.
		int idx = N - 1;
		while (idx &amp;gt; 0 &amp;amp;&amp;amp; input[idx - 1] &amp;gt; input[idx]) {
			idx--;
		}

		// 만일, 증가하는 부분이 존재하지 않는다면 다음 순열은 존재하지 않는 것이다.
		if (idx == 0) {
			System.out.println(&quot;다음 순열이 존재하지 않습니다. 마지막 순열 입니다.&quot;);
			return;
		}

		// 해당 인덱스를 기준으로, 좌/우 지점으로 나눈다.
		// 좌측의 제일 오른쪽 숫자에 대하여, 우측의 제일 오른쪽 지점부터 탐색하며 큰 수를 찾는다.
		int big_idx = N - 1;
		while (big_idx &amp;gt; idx &amp;amp;&amp;amp; input[idx - 1] &amp;gt; input[big_idx]) {
			big_idx--;
		}

		// 해당 숫자를 찾았다면 각 숫자를 서로 Swap한다.
		int temp = input[idx - 1];
		input[idx - 1] = input[big_idx];
		input[big_idx] = temp;

		// 우측 지점을 정렬한다.
		Arrays.sort(input, idx, N);
		
		// 결과 출력
		System.out.println(Arrays.toString(input));
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/euSoSg/btqYusMgS46/vL5bzxC7HixlBK4WXj25rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/euSoSg/btqYusMgS46/vL5bzxC7HixlBK4WXj25rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/euSoSg/btqYusMgS46/vL5bzxC7HixlBK4WXj25rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeuSoSg%2FbtqYusMgS46%2FvL5bzxC7HixlBK4WXj25rK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;※ for문으로 구현해도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1614260851054&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package cases;

import java.util.Arrays;
import java.util.Scanner;

public class NextPermutation {
	static int[] input;
	static int N;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 입력받은 수를 배열에 저장.
		String line = sc.nextLine();
		N = line.length();
		input = new int[N];

		for (int i = 0; i &amp;lt; line.length(); i++) {
			input[i] = line.charAt(i) - '0';
		}

		// 다음 순열.
		nextPermutation();
		sc.close();
	}

	private static void nextPermutation() {
		// 주어진 순열의 뒤부터 탐색하며, 증가하는 부분을 찾는다.
		int idx = N - 1;
		for (int i = N - 1; i &amp;gt; 0; i--) {
			if (input[i - 1] &amp;lt; input[i]) {
				idx = i;
				break;
			}
		}

		// 만일, 증가하는 부분이 존재하지 않으면 다음 순열은 존재하지 않는 것이다.
		if (idx == 0) {
			System.out.println(&quot;다음 순열이 존재하지 않습니다. 마지막 순열 입니다.&quot;);
			return;
		}

		// 해당 인덱스를 기준으로, 좌/우지점을 나눈다.
		// 좌측의 제일 오른쪽 숫자에 대하여, 우측의 제일 오른쪽 지점부터 탐색하며 큰 수를 찾는다.
		// 해당 숫자를 찾았다면 각 숫자를 서로 Swap한다.
		for (int i = N - 1; i &amp;gt;= idx; i--) {
			if (input[idx - 1] &amp;lt; input[i]) {
				int temp = input[idx - 1];
				input[idx - 1] = input[i];
				input[i] = temp;
				break;
			}
		}
		
		// 우측 지점을 정렬한다.
		Arrays.sort(input, idx, N);
		
		// 결과 출력
		System.out.println(Arrays.toString(input));
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/완전 탐색</category>
      <category>java</category>
      <category>Next permutation</category>
      <category>다음 순열</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/54</guid>
      <comments>https://sskl660.tistory.com/54#entry54comment</comments>
      <pubDate>Thu, 25 Feb 2021 22:47:36 +0900</pubDate>
    </item>
    <item>
      <title>[Java]부분 집합(Subset)과 멱집합(Power Set)</title>
      <link>https://sskl660.tistory.com/53</link>
      <description>&lt;p&gt;&lt;b&gt;*부분 집합(Subset)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 부분 집합이란 쉽게 말해서 어떤 집합에 포함되는 집합을 말한다. 말 그대로 어떤 집합의 '부분'이 되는 집합이라고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;Ex) {1, 2, 3}의 부분 집합은 공집합, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3} 이 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*멱집합(Power set)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 멱집합이란, &lt;b&gt;해당 집합의 모든 부분 집합을 모아둔 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;Ex) {1, 2, 3}의 멱집합은 {공집합, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}} 이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*부분 집합 구하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 부분 집합은 기본적으로&amp;nbsp;&lt;b&gt;조합&lt;/b&gt;을 이용하여 쉽게 구할 수 있다. 어떤 집합에서 개수가 전체 원소의 개수가 n개인 부분 집합을 구한다면, &lt;b&gt;해당 집합에서 n개의 수를 '선택'&lt;/b&gt; 하면 된다. &lt;b&gt;부분 집합은 각 원소의 순서를 바꿔도 같은 부분집합&lt;/b&gt;이다. 따라서, 조합을 이용한다면 부분 집합을 쉽게 구할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*멱집합 구하기(조합 이용)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 멱집합은&amp;nbsp;&lt;b&gt;해당 집합의 모든 부분 집합을 모은 것&lt;/b&gt;이라고 하였다. 따라서, 해당 집합의 원소의 개수가 총 N개라고 한다면&amp;nbsp;&lt;b&gt;0부터 N개의 원소를 가지는 모든 부분 집합을 구하면 멱집합을 구할 수 있음&lt;/b&gt;을 알 수 있다.&amp;nbsp;&lt;b&gt;따라서, 기본적으로 원소수를 바꿔 가면서 모든 조합을 구해주면 멱집합을 쉽게 구할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 예를 들어, 집합 {1, 2, 3}의 멱집합은 다음과 같이 구할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1614253571579&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package cases;

import java.util.Arrays;

public class PowerSet_Combination {
	static int[] nums = { 1, 2, 3 };
	// 최대 원소의 개수
	static int max_cnt;
	// 각 부분 집합을 저장할 배열
	static int[] subset;

	public static void main(String[] args) {
		// 원소를 선택하는 개수 0 ~ 3개.
		for (int i = 0; i &amp;lt;= 3; i++) {
			max_cnt = i;
			subset = new int[i];
			// 대상 집합에서 원소를 0 ~ 3개를 선택하는 조합을 모두 구한다.
			Combination(0, 0);
		}
	}

	private static void Combination(int cnt, int k) {
		if (cnt == max_cnt) {
			System.out.println(Arrays.toString(subset));
			return;
		}
		for (int i = k; i &amp;lt; nums.length; i++) {
			subset[cnt] = nums[i];
			Combination(cnt + 1, i + 1);
		}

	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*멱집합 원소의 개수(부분 집합의 총 개수)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 그렇다면 해당 집합의 모든 부분 집합의 개수, 즉 멱집합의 모든 원소의 개수는 몇 개 일까?&amp;nbsp;&lt;b&gt;이 문제는 중복 순열의 개념을 응용하여 해결 할 수 있다.&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 예를 들어, 집합 {1, 2, 3}에서 부분 집합을 구하는 것은 &lt;b&gt;3개의 공간에 각 숫자를 넣을 것인지 말 것인지를 결정하는 문제&lt;/b&gt;&lt;b&gt;로 치환 가능하다.&lt;/b&gt; 즉, 1을 넣을 공간에 1을 넣을지 말지, 2를 넣을 공간에 2를 넣을지 말지, 3을 넣을 공간에 3을 넣을지 말지를 결정하여 &lt;b&gt;부분 집합을 결정할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;531&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEKyaS/btqYrGD10zo/k3M7gH8mBAEYGhnOMCzcCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEKyaS/btqYrGD10zo/k3M7gH8mBAEYGhnOMCzcCk/img.png&quot; data-alt=&quot;부분 집합을 구하는 것은 중복 순열 문제로 치환 가능하다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEKyaS/btqYrGD10zo/k3M7gH8mBAEYGhnOMCzcCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEKyaS%2FbtqYrGD10zo%2Fk3M7gH8mBAEYGhnOMCzcCk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;531&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;부분 집합을 구하는 것은 중복 순열 문제로 치환 가능하다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt; 따라서 최종적으로&amp;nbsp;&lt;b&gt;전체 원소의 개수만큼 해당 숫자를 선택할지/선택하지 않을지를 결정&lt;/b&gt;하면 되기 때문에,&amp;nbsp;&lt;b&gt;부분 집합의 총 개수는 2의 N승(N은 대상 집합의 총 원소의 개수)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhZmaI/btqYB59Ykme/nTMkHd39h3RljzHHHYkwc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhZmaI/btqYB59Ykme/nTMkHd39h3RljzHHHYkwc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhZmaI/btqYB59Ykme/nTMkHd39h3RljzHHHYkwc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhZmaI%2FbtqYB59Ykme%2FnTMkHd39h3RljzHHHYkwc1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*멱집합 구하기(재귀 이용)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 뜬금없이 부분 집합의 총 개수를 구하는 방법을 이야기한 이유는,&amp;nbsp;&lt;b&gt;부분 집합의 총 개수를 구하는 로직을 이용하여 멱집합을 구하는 방법이 존재&lt;/b&gt;하기 때문이다. &lt;b&gt;해당 로직을 적절히 재귀로 구현하면 역시 멱집합을 구할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt; 보통 멱집합에서 재귀를 이용하는 로직을 설명하기 위해서 다음과 같은 설명을 자주 볼 수 있다. 예를 들어, 집합 {1, 2, 3}의 멱집합은 집합 {1, 2, 3}에서 &lt;b&gt;원소 1을 제외한 부분 집합의 모든 멱집합의 원소에, 원소 1을 포함하여 생각해주면 된다.&lt;/b&gt; 즉, 집합 {2, 3}의 멱집합은 공집합, {2}, {3}, {2, 3}인데, 각 멱집합의 원소에 원소 1을 추가하여 생각해주면 {1}, {1, 2}, {1, 3}, {1, 2, 3}의 경우를 추가해줄 수 있다.&amp;nbsp; 이러한 과정을 거치면 최종적으로 집합 {1, 2, 3}의 멱집합과 같아진다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 위의 로직은 쉽게 말해&amp;nbsp;&lt;b&gt;앞에서 언급한 부분 집합의 총 개수를 구하는 로직과 같다. 즉, 어떤 원소를 포함 시킬 것인지 아니면 포함시키지 않을 것인지를 고민하며 선택을 반복하면 최종적으로 모든 부분 집합을 구할 수 있다.&lt;/b&gt; 집합 {1, 2, 3}의 부분 집합을 &lt;b&gt;어떤 원소를 포함 시키느냐, 포함 시키지 않느냐의 문제로 해결 하는 예로 아래 트리 구조를 참고&lt;/b&gt;하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxZq0m/btqYrGjWyDA/QKslDjSOK1Lpyi0efANt7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxZq0m/btqYrGjWyDA/QKslDjSOK1Lpyi0efANt7K/img.png&quot; data-alt=&quot;어떤 문제를 선택하느냐, 선택하지 않느냐의 문제이기 때문에 포화 이진 트리의 구조를 갖는다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxZq0m/btqYrGjWyDA/QKslDjSOK1Lpyi0efANt7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxZq0m%2FbtqYrGjWyDA%2FQKslDjSOK1Lpyi0efANt7K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;어떤 문제를 선택하느냐, 선택하지 않느냐의 문제이기 때문에 포화 이진 트리의 구조를 갖는다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt; 즉, 이렇게 이진 트리의 구조를 가지고 있기 때문에&amp;nbsp;&lt;b&gt;재귀를 이용한다면, 최종적으로 모든 멱집합의 개수&lt;/b&gt;를 구할 수 있다. &lt;b&gt;해당 숫자를 선택했는지, 선택하지 않았는지를 표현하기 위해서 visited boolean 배열을 만들어 활용할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614256408297&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package cases;

public class PowerSet_Recursion {
	static int[] nums = { 1, 2, 3 };
	// 해당 숫자를 선택 했는지, 선택하지 않았는지를 표현해줄 배열.
	static boolean[] visited = new boolean[3];

	public static void main(String[] args) {
		// 아무것도 선택하지 않는 경우부터 시작한다.
		powerSet(0);
	}

	private static void powerSet(int cnt) {
		// 3개의 숫자에 대한 선택을 완료 하였다면, 선택된 숫자들을 출력한다.
		// 선택된 각 숫자들은 대상 배열의 '부분 집합'이다!
		if (cnt == nums.length) {
			for (int i = 0; i &amp;lt; nums.length; i++) {
				// 숫자가 선택 되었다면 출력한다.
				if (visited[i]) {
					System.out.print(nums[i] + &quot; &quot;);
				}
			}
			System.out.println();
			return;
		}

		// 해당 숫자를 선택하고 재귀를 진행한다.
		visited[cnt] = true;
		powerSet(cnt + 1);
		// 해당 숫자를 선택하지 않고 재귀를 진행한다.
		visited[cnt] = false;
		powerSet(cnt + 1);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI2i01/btqYAsqSH6L/SReZPygulUOdJn8dHBDnU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI2i01/btqYAsqSH6L/SReZPygulUOdJn8dHBDnU0/img.png&quot; data-alt=&quot;.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI2i01/btqYAsqSH6L/SReZPygulUOdJn8dHBDnU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI2i01%2FbtqYAsqSH6L%2FSReZPygulUOdJn8dHBDnU0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;※ 출력 &lt;span&gt;결과를 보면 위의 트리와 출력 순서가 같은 것을 확인 할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/완전 탐색</category>
      <category>java</category>
      <category>power set</category>
      <category>subset</category>
      <category>멱집합</category>
      <category>부분 집합</category>
      <category>부분 집합의 개수</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/53</guid>
      <comments>https://sskl660.tistory.com/53#entry53comment</comments>
      <pubDate>Thu, 25 Feb 2021 21:36:16 +0900</pubDate>
    </item>
    <item>
      <title>[Java]덱(Deque)</title>
      <link>https://sskl660.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*덱(Deque)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 덱이란 &lt;b&gt;큐와 스택의 특성을 동시에 가질 수 있는 자료구조&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 두 가지 특성을 동시에 활용할 수 있기 때문에&amp;nbsp;더 다양하게 활용될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;285&quot; width=&quot;760&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hxc0C/btqXRvaJm5q/iLcSGAOAmdslMPxb2XkYTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hxc0C/btqXRvaJm5q/iLcSGAOAmdslMPxb2XkYTK/img.png&quot; data-alt=&quot;덱 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hxc0C/btqXRvaJm5q/iLcSGAOAmdslMPxb2XkYTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHxc0C%2FbtqXRvaJm5q%2FiLcSGAOAmdslMPxb2XkYTK%2Fimg.png&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;285&quot; width=&quot;760&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;덱 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*Java의 덱&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 덱 자료 구조는 &lt;b&gt;기본적으로 Queue의 구조를 채용&lt;/b&gt;하고 있다. 따라서 일반 큐의 연산인 poll() 메서드와 offer() 메서드는 동일하게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 덱 자료 구조는&amp;nbsp;&lt;b&gt;양 방향을 모두 head로 볼 수 있다.&lt;/b&gt; 따라서, 배열의 관점에서 인덱스가 0인 부분의 head는 &lt;b&gt;일반 큐 메서드 이름에 Fisrt를 추가하여 구분&lt;/b&gt;하고, 마지막 인덱스 부분의 head는 &lt;b&gt;Last를 추가하여 구분&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt; peek() 메서드도 마찬가지이다. 좌측 부분의 head를 확인하고 싶다면 peek() 메서드 혹은 peekFirst() 메서드를 사용하면 되고, 우측 부분의 head를 확인하고 싶다면 peekLast() 메서드를 사용하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(참고 : &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docs.oracle.com/javase/7/docs/api/&lt;/a&gt;)&lt;/p&gt;
&lt;figure id=&quot;og_1613653297719&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Java Platform SE 7&quot; data-og-description=&quot;&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/7/docs/api/&quot; data-og-url=&quot;https://docs.oracle.com/javase/7/docs/api/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/7/docs/api/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java Platform SE 7&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1613653699131&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.ArrayDeque;
import java.util.Deque;

/**
 * 조합 : n 개 중에서 r 개 선택
 */
public class test {
    public static void main(String[] args) {
		Deque&amp;lt;Integer&amp;gt; dq = new ArrayDeque&amp;lt;Integer&amp;gt;();
		
		// 일반 큐의 구조와 마찬가지로 1, 2, 3 투입.
		dq.offer(1);
		dq.offer(2);
		dq.offer(3);
		// 큐의 좌측에 100 투입.
		dq.offerFirst(100);
		// 큐의 우측에 200 투입(그냥 offer 연산은 사용해도 된다).
		dq.offerLast(200);
		// 큐의 우측 원소를 추출
		dq.pollLast();
		
		// 큐의 우측 원소를 확인
		System.out.println(dq.peekLast());
		// 큐의 전체 숫자를 차레로 확인
		for(Integer num : dq) {
			System.out.print(num + &quot; &quot;);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/자료구조 for Algorithm</category>
      <category>deque</category>
      <category>java</category>
      <category>덱</category>
      <category>자료구조</category>
      <category>자바</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/52</guid>
      <comments>https://sskl660.tistory.com/52#entry52comment</comments>
      <pubDate>Thu, 18 Feb 2021 22:08:42 +0900</pubDate>
    </item>
    <item>
      <title>[Java]중복 조합(Combination with repetition)</title>
      <link>https://sskl660.tistory.com/51</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;중복 조합을 완벽하게 이해하기 위해서는 순열, 중복 순열, 조합 세 가지를 모두 정확히 이해하고 공부하는 것이 좋다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/48?category=879763&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/48?category=879763&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613629755252&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 순열(Permutation)&quot; data-og-description=&quot;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231, &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/48?category=879763&quot; data-og-url=&quot;https://sskl660.tistory.com/48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kfF3h/hyJjTPRbz9/neALFogGEG6xMHh0CPHxK1/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bC6IBr/hyJjTvy48T/QHbaomCbL9RKkVDtAaJ2bk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bu4sg9/hyJjM4g1o3/yocUswOUxun4tmOeueRYok/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/48?category=879763&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/48?category=879763&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kfF3h/hyJjTPRbz9/neALFogGEG6xMHh0CPHxK1/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bC6IBr/hyJjTvy48T/QHbaomCbL9RKkVDtAaJ2bk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bu4sg9/hyJjM4g1o3/yocUswOUxun4tmOeueRYok/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] 순열(Permutation)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/49?category=879763&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/49?category=879763&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613629763053&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 중복 순열(Permutation with repetition)&quot; data-og-description=&quot;*중복 순열(Permutation with repetition) -&amp;gt;순열을 이해했다면, 중복 순열은 이해하기 쉽다. 순열을 먼저 이해하도록 하자. sskl660.tistory.com/48 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/49?category=879763&quot; data-og-url=&quot;https://sskl660.tistory.com/49&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/AB40S/hyJjUgVtpa/hjA48fzKLZjkdyaajqnrRk/img.png?width=800&amp;amp;height=368&amp;amp;face=0_0_800_368,https://scrap.kakaocdn.net/dn/cuHqvs/hyJjUBeQhO/YyOUiJjh5cG3pCnMPSW0N1/img.png?width=800&amp;amp;height=368&amp;amp;face=0_0_800_368,https://scrap.kakaocdn.net/dn/cgkmi0/hyJjO8RrAI/yGVK4eIWImPHmGcJzODRD1/img.png?width=936&amp;amp;height=431&amp;amp;face=0_0_936_431&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/49?category=879763&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/49?category=879763&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/AB40S/hyJjUgVtpa/hjA48fzKLZjkdyaajqnrRk/img.png?width=800&amp;amp;height=368&amp;amp;face=0_0_800_368,https://scrap.kakaocdn.net/dn/cuHqvs/hyJjUBeQhO/YyOUiJjh5cG3pCnMPSW0N1/img.png?width=800&amp;amp;height=368&amp;amp;face=0_0_800_368,https://scrap.kakaocdn.net/dn/cgkmi0/hyJjO8RrAI/yGVK4eIWImPHmGcJzODRD1/img.png?width=936&amp;amp;height=431&amp;amp;face=0_0_936_431');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] 중복 순열(Permutation with repetition)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*중복 순열(Permutation with repetition) -&amp;gt;순열을 이해했다면, 중복 순열은 이해하기 쉽다. 순열을 먼저 이해하도록 하자. sskl660.tistory.com/48 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/50?category=879763&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/50?category=879763&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613629775944&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 조합(Combination)&quot; data-og-description=&quot;조합은 기본적으로 순열을 이해하고 있어야 이해하기 더 수월하다. sskl660.tistory.com/48 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의&quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/50?category=879763&quot; data-og-url=&quot;https://sskl660.tistory.com/50&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bw4DKy/hyJjSckAPR/FtjkySk4zJwqkw01ftZZck/img.png?width=702&amp;amp;height=476&amp;amp;face=0_0_702_476,https://scrap.kakaocdn.net/dn/eOZIe/hyJjJGuON4/mu0DT6gnUEeU2l13kq9A91/img.png?width=702&amp;amp;height=476&amp;amp;face=0_0_702_476,https://scrap.kakaocdn.net/dn/clWhnW/hyJjRR2W8u/yQc27cQTzVetE8bKEe0Spk/img.png?width=702&amp;amp;height=476&amp;amp;face=0_0_702_476&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/50?category=879763&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/50?category=879763&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bw4DKy/hyJjSckAPR/FtjkySk4zJwqkw01ftZZck/img.png?width=702&amp;amp;height=476&amp;amp;face=0_0_702_476,https://scrap.kakaocdn.net/dn/eOZIe/hyJjJGuON4/mu0DT6gnUEeU2l13kq9A91/img.png?width=702&amp;amp;height=476&amp;amp;face=0_0_702_476,https://scrap.kakaocdn.net/dn/clWhnW/hyJjRR2W8u/yQc27cQTzVetE8bKEe0Spk/img.png?width=702&amp;amp;height=476&amp;amp;face=0_0_702_476');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] 조합(Combination)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;조합은 기본적으로 순열을 이해하고 있어야 이해하기 더 수월하다. sskl660.tistory.com/48 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*중복 조합(Combination with repetition)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 중복 조합이란, 임의의 집합을 &lt;b&gt;순서가 없이 선택하는데&amp;nbsp;&lt;/b&gt;일반 조합과 다르게&amp;nbsp;&lt;b&gt;집합의 원소를 중복해서 선택할 수 있는 차이가 존재&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ex) 이를 테면 집합 {1, 2, 3}중 2개의 원소를 선택한 중복 조합의 결과는 {11, 12, 13, 22, 23, 33} 총 6가지 경우의 수가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 중복 조합의 경우의 수(이 부분은 수학적인 내용이 많으니 경우의 수를 굳이 이해하고 싶지 않다면 스킵하셔도 무관합니다).&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 중복 조합의 경우의 수는 &lt;b&gt;조합에서 경우의 수를 구하는 것과 동일하게 생각하면 안된다!&lt;/b&gt; 조합에서 경우의 수를 구하는 것은&amp;nbsp;&lt;b&gt;순열로 뽑은 수에서 '순서를 제거하는 것'&lt;/b&gt;이라고 하였다.&amp;nbsp;&lt;b&gt;하지만 중복 조합에서는, 순서를 제거하는 경우 원치않는 경우의 수까지 제거해버리기 때문에 문제가 발생&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;315&quot; width=&quot;441&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EvrkD/btqXHfUEBKB/VOOz8DakgqasqKztKKaKs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EvrkD/btqXHfUEBKB/VOOz8DakgqasqKztKKaKs0/img.png&quot; data-alt=&quot;.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EvrkD/btqXHfUEBKB/VOOz8DakgqasqKztKKaKs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEvrkD%2FbtqXHfUEBKB%2FVOOz8DakgqasqKztKKaKs0%2Fimg.png&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;315&quot; width=&quot;441&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;조합의 경우의 수를 이해하기 위해 위의 그림을 참고하면, {1, 2, 3}에서 2개를 선택하는 순열은 &lt;b&gt;각 선택에 대하여, 순서가 존재함&lt;/b&gt;을 알 수 있다. 이를 테면, 12라는 선택은 순서를 부여하면 21이라는 새로운 경우를 도출할 수 있다. 마찬가지로 13은 순서를 부여하면 31이라는 새로운 경우를 도출할 수 있다. 따라서&lt;b&gt; 조합에서는 이러한 '순서'의 개념을 제거한 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;275&quot; width=&quot;418&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXp7sz/btqXFg0Bcbj/T7oOky5klAB0Q74SBX7jxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXp7sz/btqXFg0Bcbj/T7oOky5klAB0Q74SBX7jxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXp7sz/btqXFg0Bcbj/T7oOky5klAB0Q74SBX7jxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXp7sz%2FbtqXFg0Bcbj%2FT7oOky5klAB0Q74SBX7jxk%2Fimg.png&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;275&quot; width=&quot;418&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;마찬가지로 {1, 2, 3}에서 3개를 선택하는 순열은 123이라는 선택은 순서를 부여하면 132, 213, 231, 312, 321이라는 5가지 경우를 더 도출할 수 있다. 마찬가지로 조합에서는 이 '순서'의 개념을 제거한 것 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;b&gt;중복 조합의 경우의 수는 이와 다르다.&lt;/b&gt; 이를 테면 {1, 2, 3}에서 2개를 선택하는 중복 순열과 중복 조합을 그림을 통해 확인해보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;398&quot; width=&quot;380&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwLKLh/btqXMe1qrQj/kQMFU1jVFP8ee8QK8FXDoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwLKLh/btqXMe1qrQj/kQMFU1jVFP8ee8QK8FXDoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwLKLh/btqXMe1qrQj/kQMFU1jVFP8ee8QK8FXDoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwLKLh%2FbtqXMe1qrQj%2FkQMFU1jVFP8ee8QK8FXDoK%2Fimg.png&quot; data-origin-width=&quot;460&quot; data-origin-height=&quot;398&quot; width=&quot;380&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;중복 순열에서는&amp;nbsp;&lt;b&gt;'순서'라는 개념을 제거할 수 없다.&lt;/b&gt; 위의 예시를 그대로 활용하여 이해해보면, 12라는 선택은 순서를 부여하면 21이라는 새로운 경우의 수를 도출할 수 있지만,&amp;nbsp;&lt;b&gt;11이라는 선택은 순서를 부여하더라도 11이라는 똑같은 경우를 도출하기 때문에 의미가 없다.&lt;/b&gt; 따라서 무턱대고 모든 경우에 대하여 동등하게 순서를 제거해버린다면 문제가 발생할 수 밖에 없기 때문에, 조합에서 경우의 수를 구하는 것 처럼 생각하면 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 그렇다면 중복 조합의 경우의 수는 어떻게 구할 수 있을까? 먼저 중복 조합의 경우의 수는 다음과 같이 표현하고, 다음 공식을 활용하여 구할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;97&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bttqme/btqXHfNU33g/7t4FEAp9Qv1goDkkNALQO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bttqme/btqXHfNU33g/7t4FEAp9Qv1goDkkNALQO0/img.png&quot; data-alt=&quot;중복 조합 공식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bttqme/btqXHfNU33g/7t4FEAp9Qv1goDkkNALQO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbttqme%2FbtqXHfNU33g%2F7t4FEAp9Qv1goDkkNALQO0%2Fimg.png&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;97&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중복 조합 공식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;특히 빨간 부분을 집중해서 보면서 다음 내용들을 이해해보도록 하자. 이를 테면, {1, 2, 3}의 집합에서 중복 조합을 고르는 방식은 &lt;b&gt;다른 방법으로 치환하여 생각&lt;/b&gt;해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;118&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vjJQp/btqXJXe8WGh/akMCVM19kyp1osOZCMizmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vjJQp/btqXJXe8WGh/akMCVM19kyp1osOZCMizmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vjJQp/btqXJXe8WGh/akMCVM19kyp1osOZCMizmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvjJQp%2FbtqXJXe8WGh%2FakMCVM19kyp1osOZCMizmk%2Fimg.png&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;118&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;{1, 2, 3}이라는 집합에서 다음과 같이 1, 2, 3을 넣을 수 있는 영역을 각각&amp;nbsp;&lt;b&gt;막대기를 통해서&amp;nbsp;&lt;/b&gt;&lt;b&gt;구분&lt;/b&gt;한뒤, 2개를 선택하는 경우의 수를 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;312&quot; data-origin-height=&quot;323&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YTGKj/btqXQ5Qxyar/9PGMmK8uW6ycNaJvELa9Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YTGKj/btqXQ5Qxyar/9PGMmK8uW6ycNaJvELa9Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YTGKj/btqXQ5Qxyar/9PGMmK8uW6ycNaJvELa9Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYTGKj%2FbtqXQ5Qxyar%2F9PGMmK8uW6ycNaJvELa9Ck%2Fimg.png&quot; data-origin-width=&quot;312&quot; data-origin-height=&quot;323&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;막대기로 구분 된 각 영역에, &lt;b&gt;중복을 허용&lt;/b&gt;하여 집합에서 숫자를 선택한 뒤 영역에 넣는 경우의 수를 생각해보면 위와 같은 경우를 생각할 수 있다.&amp;nbsp;&lt;b&gt;이를 일반화하여 생각하면, n개의 원소를 가진 집합에서 r개를 선택하는 경우, 구분하는 영역을 n - 1개로 분할하는 막대기의 개수와 선택하고자하는 숫자 r개 중 숫자 r개를 선택하는 조합&lt;/b&gt;&lt;b&gt;으로 바꾸어 생각할 수 있다!&lt;/b&gt;(반대로, 숫자와 막대기 중 막대기를 둘 칸을 선택하는 경우로 바꾸어 생각해도 된다. nCr = nCn-r이므로, 두 가지 중 어떤 선택을 해도 상관이 없다. 중요한 것은, 선택해야하는 숫자와 막대기의 개수는 이미 정해져 있으므로(n - 1 + r칸), 그 칸 중 숫자를 어떤 칸에 넣을 것인지 혹은 막대기를 어떤 칸에 넣을 것인지를 고민하는 느낌을 이해하면 된다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*구현(Java)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 중복 조합은 조합에서&amp;nbsp;&lt;b&gt;중복 선택이 가능하도록 조치만 취해주면 되기 때문에&lt;/b&gt; 구현은 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 중복 조합 알고리즘&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 대상 집합을 순회하며 숫자를 하나 선택하는 것을 아래와 같이 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 집합을 순회하며 탐색을 하되,&lt;span&gt;&amp;nbsp;&lt;/span&gt;입력된 인덱스부터 탐색한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;수를 선택했다면, 해당 인덱스와 &lt;b&gt;같은 인덱스&lt;/b&gt;를 다음 재귀 함수에 넘겨준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 선택된 숫자가 r개가 된다면, 재귀를 종료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 예를 들어, 1부터 3까지의 자연수 3개 중 2개를 선택한 중복 조합은 다음과 같이 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1613633667307&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package cases;

import java.util.Arrays;

public class Combination_with_repetition {
	// 선택하고자 하는 대상 집합.
	static int[] target = new int[] { 1, 2, 3 };
	// 대상 숫자를 담아둘 배열.
	static int[] result = new int[2];

	public static void main(String[] args) {
		combination(0, 0);
	}

	// 조합 메서드(cnt는 선택 횟수, idx는 다음 대상을 선택할때 집합에서 탐색을 시작할 인덱스).
	private static void combination(int cnt, int idx) {
		// 2개를 선택했으므로, 결과를 출력하고 재귀를 종료한다.
		if (cnt == 2) {
			System.out.println(Arrays.toString(result));
			return;
		}
		// 대상 집합을 주어진 인덱스부터 순회하며 숫자를 하나 선택한다.
		for (int i = idx; i &amp;lt; 3; i++) {
			// 숫자를 담는다.
			result[cnt] = target[i];
			// 자신을 재귀 호출한다(자신의 수는 중복 선택이 가능하므로, 인덱스를 그대로 넘겨준다).
			combination(cnt + 1, i);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/완전 탐색</category>
      <category>Java Combination</category>
      <category>자바 중복 조합</category>
      <category>중복 조합</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/51</guid>
      <comments>https://sskl660.tistory.com/51#entry51comment</comments>
      <pubDate>Thu, 18 Feb 2021 16:35:08 +0900</pubDate>
    </item>
    <item>
      <title>[Java]조합(Combination)</title>
      <link>https://sskl660.tistory.com/50</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;조합은 기본적으로 순열을 이해하고 있어야 이해하기 더 수월하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/48&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613625609611&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 순열(Permutation)&quot; data-og-description=&quot;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231, &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/48&quot; data-og-url=&quot;https://sskl660.tistory.com/48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nwImZ/hyJjQFwkLU/bVKv2RKuyFWIYEfQaZLFbk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bZGRvt/hyJjL5hmKq/i5qPDUGRkXTSxxAXg18Ptk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/3dftQ/hyJjYKi9vg/UO9kuQXtbkhgJWmuUcLNS0/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nwImZ/hyJjQFwkLU/bVKv2RKuyFWIYEfQaZLFbk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bZGRvt/hyJjL5hmKq/i5qPDUGRkXTSxxAXg18Ptk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/3dftQ/hyJjYKi9vg/UO9kuQXtbkhgJWmuUcLNS0/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] 순열(Permutation)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*조합(Combination)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 조합이란, 임의의 집합을&amp;nbsp;&lt;b&gt;순서가 없이 선택하는 것&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ex) 이를 테면 집합 {1, 2, 3}중 2개의 원소를 선택한 조합을 구하시오라고 하면, 결과는 {12, 13, 23} 총 3가지의 경우의 수가 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;476&quot; width=&quot;415&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wKnbZ/btqXD3NMf0H/CkvdKKzkrAiWSqce21HWJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wKnbZ/btqXD3NMf0H/CkvdKKzkrAiWSqce21HWJk/img.png&quot; data-alt=&quot;조합 경우의 수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wKnbZ/btqXD3NMf0H/CkvdKKzkrAiWSqce21HWJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwKnbZ%2FbtqXD3NMf0H%2FCkvdKKzkrAiWSqce21HWJk%2Fimg.png&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;476&quot; width=&quot;415&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조합 경우의 수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 조합이 총 3가지가 나오는 이유는, 위의 예시에서 선택한 2가지 수를 박스에 하나씩 넣는 상황을 가정해보자.&amp;nbsp;&lt;b&gt;우선 3개의 숫자 중 2개의 숫자를 선택하여 나열하는 순열을 구한다. &lt;/b&gt;이후,&lt;b&gt; 2개의 공간에 나열된 숫자들은 '순서'를 부여 받은 상태이므로 그 '순서를 부여 받은 상태를 제거'&lt;/b&gt; 해준다면 조합의 경우의 수를 구할 수 있다. 즉, 2개중 2개를 선택하는 순열의 경우의 수로 나눠주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 위의 조합의 경우의 수를 일반화하면,&amp;nbsp;&lt;b&gt;n개의 수 중 r개를 선택하는 조합은 nPr의 순열을 구하고, rPr의 순열로 나눈 값을 경우의 수로 가짐을 알 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;91&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQEZNg/btq21L8ylyu/al7s6rnAwMCZLXZO4hoIC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQEZNg/btq21L8ylyu/al7s6rnAwMCZLXZO4hoIC0/img.png&quot; data-alt=&quot;조합 경우의 수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQEZNg/btq21L8ylyu/al7s6rnAwMCZLXZO4hoIC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQEZNg%2Fbtq21L8ylyu%2Fal7s6rnAwMCZLXZO4hoIC0%2Fimg.png&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;91&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조합 경우의 수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*구현(Java)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 조합은 순열에 비해 로직을 조금 더 고민해 보아야 이해할 수 있다. 순열은 &lt;b&gt;순서를 고려하였기 때문에, 재귀 호출을 하여 다음 수를 선택하는 경우 집합의 처음부터 탐색하며 다음 대상을 고려&lt;/b&gt;하였다. 하지만 조합은&amp;nbsp;&lt;b&gt;순서를 고려하지 않기 때문에, 다음 수를 선택하는 경우 집합의 처음부터 탐색하며 다음 대상을 고려하는 경우, 이미 선택했던 경우의 수를 또 선택하는 오류가 발생한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;210&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dX8BSX/btqXHfUyuuE/H8DkbtlUmHQkGoCvlWgvr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dX8BSX/btqXHfUyuuE/H8DkbtlUmHQkGoCvlWgvr0/img.png&quot; data-alt=&quot;조합에서 다음과 같이 다음 수를 선택할때 집합의 처음부터 탐색하면, 오류가 발생한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dX8BSX/btqXHfUyuuE/H8DkbtlUmHQkGoCvlWgvr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdX8BSX%2FbtqXHfUyuuE%2FH8DkbtlUmHQkGoCvlWgvr0%2Fimg.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;210&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조합에서 다음과 같이 다음 수를 선택할때 집합의 처음부터 탐색하면, 오류가 발생한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;따라서 조합은 다음과 같은 로직을 이용하면 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 조합 알고리즘&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 대상 집합을 순회하며 숫자를 하나 선택하는 것을 아래와 같이 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 집합을 순회하며 탐색을 하되, &lt;b&gt;입력된 인덱스부터 탐색&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) &lt;b&gt;수를 선택했다면, 해당 인덱스보다 큰 인덱스를 다음 재귀 함수에 넘겨준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 선택된 숫자가 r개가 된다면, 재귀를 종료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 예를 들어, 1부터 3까지의 자연수 3개 중 2개를 선택한 조합은 다음과 같이 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1613626903060&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;

public class Combination {
	// 선택하고자 하는 대상 집합.
	static int[] target = new int[] { 1, 2, 3 };
	// 대상 숫자를 담아둘 배열.
	static int[] result = new int[2];

	public static void main(String[] args) {
		combination(0, 0);
	}

	// 조합 메서드(cnt는 선택 횟수, idx는 다음 대상을 선택할때 집합에서 탐색을 시작할 인덱스).
	private static void combination(int cnt, int idx) {
		// 2개를 선택했으므로, 결과를 출력하고 재귀를 종료한다.
		if (cnt == 2) {
			System.out.println(Arrays.toString(result));
			return;
		}
		// 대상 집합을 주어진 인덱스부터 순회하며 숫자를 하나 선택한다.
		for (int i = idx; i &amp;lt; 3; i++) {
			// 숫자를 담는다.
			result[cnt] = target[i];
			// 자신을 재귀 호출한다(자신 이전의 수를 중복 선택하지 않도록 인덱스를 +1하여 재귀를 호출한다).
			combination(cnt + 1, i + 1);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/완전 탐색</category>
      <category>combination</category>
      <category>Java Combination</category>
      <category>자바 조합</category>
      <category>조합</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/50</guid>
      <comments>https://sskl660.tistory.com/50#entry50comment</comments>
      <pubDate>Thu, 18 Feb 2021 14:42:36 +0900</pubDate>
    </item>
    <item>
      <title>[Java]중복 순열(Permutation with repetition)</title>
      <link>https://sskl660.tistory.com/49</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*중복 순열(Permutation with repetition)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;순열을 이해했다면, 중복 순열은 이해하기 쉽다. 순열을 먼저 이해하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/48&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613624377204&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Java] 순열(Permutation)&quot; data-og-description=&quot;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231, &quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/48&quot; data-og-url=&quot;https://sskl660.tistory.com/48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nwImZ/hyJjQFwkLU/bVKv2RKuyFWIYEfQaZLFbk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bZGRvt/hyJjL5hmKq/i5qPDUGRkXTSxxAXg18Ptk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/3dftQ/hyJjYKi9vg/UO9kuQXtbkhgJWmuUcLNS0/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nwImZ/hyJjQFwkLU/bVKv2RKuyFWIYEfQaZLFbk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/bZGRvt/hyJjL5hmKq/i5qPDUGRkXTSxxAXg18Ptk/img.png?width=800&amp;amp;height=343&amp;amp;face=0_0_800_343,https://scrap.kakaocdn.net/dn/3dftQ/hyJjYKi9vg/UO9kuQXtbkhgJWmuUcLNS0/img.png?width=821&amp;amp;height=353&amp;amp;face=0_0_821_353');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Java] 순열(Permutation)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;*순열(Permutation) -&amp;gt; 순열이란, 임의의 집합을 순서를 부여하여 차례로 나열하는 것을 말한다. Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;중복 순열이란, 임의의 집합을&amp;nbsp;&lt;b&gt;순서를 부여하여 차례로 나열하는데 &lt;/b&gt;일반&amp;nbsp;순열과 다르게 &lt;b&gt;집합의 원소를 중복해서 선택할 수 있는 차이&lt;/b&gt;&lt;b&gt;가 존재&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 중복 순열의 결과는 {111, 112, 113, 121, ..., 333} 총 27가지 경우의 수가 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;431&quot; width=&quot;608&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXht9D/btqXLeUG5m7/5cIMancfgYFWNTtkmfvdpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXht9D/btqXLeUG5m7/5cIMancfgYFWNTtkmfvdpk/img.png&quot; data-alt=&quot;중복 순열 경우의 수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXht9D/btqXLeUG5m7/5cIMancfgYFWNTtkmfvdpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXht9D%2FbtqXLeUG5m7%2F5cIMancfgYFWNTtkmfvdpk%2Fimg.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;431&quot; width=&quot;608&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중복 순열 경우의 수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 중복 순열이 총 27가지가 나오는 이유는, 순열과는 다르게 &lt;b&gt;다음 수를 선택할때 중복 선택을 허용하기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 위의 중복 순열의 경우의 수를 일반화하면,&amp;nbsp;&lt;b&gt;n개의 수 중 r개를 선택하는 중복 순열은 n의 r승개의 경우의 수를 가짐을 알 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;304&quot; data-origin-height=&quot;128&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEXgcn/btqXHgTj0bZ/yRVUjDVE2lKqDweYIBHoX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEXgcn/btqXHgTj0bZ/yRVUjDVE2lKqDweYIBHoX1/img.png&quot; data-alt=&quot;중복 순열 경우의 수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEXgcn/btqXHgTj0bZ/yRVUjDVE2lKqDweYIBHoX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEXgcn%2FbtqXHgTj0bZ%2FyRVUjDVE2lKqDweYIBHoX1%2Fimg.png&quot; data-origin-width=&quot;304&quot; data-origin-height=&quot;128&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중복 순열 경우의 수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*구현(Java)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 순열과 마찬가지로 재귀를 이용하면 쉽게 구현&lt;span style=&quot;color: #333333;&quot;&gt;할 수 있다.&lt;span&gt;&amp;nbsp;&lt;b&gt;중복 선택할 수 있다는 점만 다르다는 것을 기억&lt;/b&gt;하면 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;※ 중복 순열 알고리즘&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 대상 집합을 순회하며 숫자를 하나 선택하고, &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;자신의 메서드를 재귀 호출한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 선택된 숫자가 r개가 된다면, 재귀를 종료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 예를 들어, 1부터 3까지의 자연수 3개 중 2개를 선택한 중복 순열은 다음과 같이 구현할 수 있다.&amp;nbsp;&lt;b&gt;일반 순열에서 중복 선택을 방지하기 위해 만들었던 visited배열과 관련 로직이 사라진 것을 확인할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613625136335&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package cases;

import java.util.Arrays;

public class Permutation_with_repetition {
	// 선택하고자 하는 대상 집합.
	static int[] target = new int[] { 1, 2, 3 };
	// 대상 숫자를 담아둘 배열을 만든다.
	static int[] result = new int[2];

	public static void main(String[] args) {
		permutation(0);
	}

	// 순열 메서드(cnt는 선택 횟수)
	private static void permutation(int cnt) {
		// 2개를 선택했으므로, 결과를 출력하고 재귀를 종료한다.
		if (cnt == 2) {
			System.out.println(Arrays.toString(result));
			return;
		}
		// 대상 집합을 순회하며 숫자를 하나 선택한다.
		for (int i = 0; i &amp;lt; 3; i++) {
			// 숫자를 담는다.
			result[cnt] = target[i];
			// 자신을 재귀 호출한다.
			permutation(cnt + 1);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/완전 탐색</category>
      <category>Java Permutation</category>
      <category>자바 중복 순열</category>
      <category>중복 순열</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/49</guid>
      <comments>https://sskl660.tistory.com/49#entry49comment</comments>
      <pubDate>Thu, 18 Feb 2021 14:13:42 +0900</pubDate>
    </item>
    <item>
      <title>[Java]순열(Permutation)</title>
      <link>https://sskl660.tistory.com/48</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*순열(Permutation)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 순열이란, 임의의 집합을 &lt;b&gt;순서를 부여하여 차례로 나열하는 것&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ex) 이를 테면 집합 {1, 2, 3}중 3개의 원소를 선택한 순열을 구하시오라고 하면, 결과는 {123, 132, 213, 231, 312, 321} 총 6가지의 경우의 수가 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;353&quot; width=&quot;512&quot; height=&quot;NaN&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wnxl4/btqXQ6g9Pwl/vtarvBEMO237RY2bKk2JZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wnxl4/btqXQ6g9Pwl/vtarvBEMO237RY2bKk2JZ0/img.png&quot; data-alt=&quot;순열 경우의 수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wnxl4/btqXQ6g9Pwl/vtarvBEMO237RY2bKk2JZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwnxl4%2FbtqXQ6g9Pwl%2FvtarvBEMO237RY2bKk2JZ0%2Fimg.png&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;353&quot; width=&quot;512&quot; height=&quot;NaN&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;순열 경우의 수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 순열이 총 6가지가 나오는 이유는, 위의 예시에서 선택한 3가지 수를 위 박스에 하나씩 넣는 상황을 가정해보면, 첫 번째 자리에는 {1, 2, 3}중 한 가지 숫자 어느것이든 올 수 있다. 두 번째 자리에는 앞에서 이미 한 가지 수를 선택했으므로, 그 선택한 수를 제외한 2가지 숫자가 어느 것이든 올 수 있다. 마지막 자리는 선택이 되지 않은 나머지 한 가지 수가 오게 될 것이다. 따라서 3개의 숫자를 3개선택한 순열의 경우의수는 총 6가지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 위의 순열의 경우의 수를 일반화하면, &lt;b&gt;n개의 수 중 r개를 선택하는 순열은 총 n!/(n - r)!개의 경우의수를 가짐을 알 수 있다&lt;/b&gt;(수학적으로 여러가지 방법으로 표현 가능하다).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;112&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cErpNj/btqXMe1l0qb/B8ip0bTc63gKHScIVihPgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cErpNj/btqXMe1l0qb/B8ip0bTc63gKHScIVihPgK/img.png&quot; data-alt=&quot;순열 경우의 수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cErpNj/btqXMe1l0qb/B8ip0bTc63gKHScIVihPgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcErpNj%2FbtqXMe1l0qb%2FB8ip0bTc63gKHScIVihPgK%2Fimg.png&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;112&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;순열 경우의 수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*구현(Java)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 로직은 위에 언급한 예시를 그대로 구현했다고 생각하면 된다. 따라서, 순열은&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;재귀를 이용하면 쉽게 구현&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;할 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;※ 순열 알고리즘&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 대상 집합을 순회하며 숫자를 하나 선택하는 것을 아래와 같이 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 만일, 숫자가 이미 선택되었다면 그 숫자는 선택할 수 없으므로 스킵한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 만일, 숫자가 선택되지 않았다면 그 숫자에 대하여 방문 표시를하고 자신의 메서드를 재귀 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 선택된 숫자가 r개가 된다면, 재귀를 종료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 예를 들어, 1부터 3까지의 자연수 3개중 2개를 선택한 순열을 다음과 같이 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1613623677825&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Permutation {
	// 선택하고자 하는 대상 집합.
	static int[] target = new int[] { 1, 2, 3 };
	// 대상 숫자를 선택했는지를 알려주는 집합.
	static boolean[] visited = new boolean[3];

	public static void main(String[] args) {
		permutation(0, &quot;&quot;);
	}

	// 순열 메서드(cnt는 선택 횟수, result는 결과)
	private static void permutation(int cnt, String result) {
		// 2개를 선택했으므로, 결과를 출력하고 재귀를 종료한다.
		if (cnt == 2) {
			System.out.println(result);
			return;
		}
		// 대상 집합을 순회하며 숫자를 하나 선택한다.
		for (int i = 0; i &amp;lt; 3; i++) {
			// 이미 해당 숫자를 선택한 경우에는 스킵.
			if (visited[i]) {
				continue;
			}
			// 선택하지 않은경우, 선택했다는 표시를 해준다.
			visited[i] = true;
			// 자신을 재귀 호출한다.
			permutation(cnt + 1, result + target[i]);
			// 선택을 해제한다.
			visited[i] = false;
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 다음과 같이, 매개변수를 1개만 사용하여 만들수도 있다. 위의 예시와 같이 상자라는 대상을 더욱 구체화 시킨 것이라고 볼 수 있다.&amp;nbsp;&lt;b&gt;매개변수의 수보다는, 순열을 구현하는 로직을 정확히&lt;/b&gt; &lt;b&gt;이해하도록 하자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613624078973&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;

public class Permutation {
	// 선택하고자 하는 대상 집합.
	static int[] target = new int[] { 1, 2, 3 };
	// 대상 숫자를 선택했는지를 알려주는 집합.
	static boolean[] visited = new boolean[3];
	// 대상 숫자를 담아둘 배열을 만든다.
	static int[] result = new int[2];

	public static void main(String[] args) {
		permutation(0);
	}

	// 순열 메서드(cnt는 선택 횟수)
	private static void permutation(int cnt) {
		// 2개를 선택했으므로, 결과를 출력하고 재귀를 종료한다.
		if (cnt == 2) {
			System.out.println(Arrays.toString(result));
			return;
		}
		// 대상 집합을 순회하며 숫자를 하나 선택한다.
		for (int i = 0; i &amp;lt; 3; i++) {
			// 이미 해당 숫자를 선택한 경우에는 스킵.
			if (visited[i]) {
				continue;
			}
			// 선택하지 않은경우, 선택했다는 표시를 해준다.
			visited[i] = true;
			// 숫자를 담는다.
			result[cnt] = target[i];
			// 자신을 재귀 호출한다.
			permutation(cnt + 1);
			// 선택을 해제한다.
			visited[i] = false;
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/완전 탐색</category>
      <category>Java Permutation</category>
      <category>permutation</category>
      <category>순열</category>
      <category>자바 순열</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/48</guid>
      <comments>https://sskl660.tistory.com/48#entry48comment</comments>
      <pubDate>Thu, 18 Feb 2021 13:55:30 +0900</pubDate>
    </item>
    <item>
      <title>[Java]해시맵(HashMap)</title>
      <link>https://sskl660.tistory.com/47</link>
      <description>&lt;p&gt;&lt;b&gt;*Java Collections : 맵(Map) 인터페이스&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;모든 데이터를&amp;nbsp;&lt;b&gt;'키(Key)'&lt;/b&gt;와&amp;nbsp;&lt;b&gt;'값(Value)'&lt;/b&gt;의&amp;nbsp;&lt;b&gt;'한 쌍(Pair)의 형태'&lt;/b&gt;로 연관지어 저장한다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;키(Key)는&amp;nbsp;&lt;b&gt;중복을 허용하지 않고&lt;/b&gt;, 값(Value)은 &lt;b&gt;중복을 허용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;순서는 중요하지 않다 : 순서가 없다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*해시맵(HashMap) 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;맵 인터페이스를 구현한 자바의 대표적인 Collections 클래스.&lt;/p&gt;
&lt;p&gt;-&amp;gt;해시(Hash)를 사용하기 때문에&amp;nbsp;&lt;b&gt;검색이 빠르다(리스트에서 검색하는 속도보다 빠르다).&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;키(Key)와 값(Value)을 저장하기 때문에, HashMap&amp;lt;Key, Value&amp;gt;의 형태로 선언한다.&lt;/p&gt;
&lt;pre id=&quot;code_1613207771063&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;Integer, String&amp;gt; hm = new HashMap&amp;lt;Integer, String&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-&amp;gt;기본적으로 삽입은 put, 삭제는 remove, 조회는 여러가지 방법으로 할 수 있다. 아래 API를 참고하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;718&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baYRC5/btqWU7Q0n2M/USBklTlwZDUIrpEmLlvl7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baYRC5/btqWU7Q0n2M/USBklTlwZDUIrpEmLlvl7k/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://docs.oracle.com/javase/7/docs/api/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baYRC5/btqWU7Q0n2M/USBklTlwZDUIrpEmLlvl7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaYRC5%2FbtqWU7Q0n2M%2FUSBklTlwZDUIrpEmLlvl7k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;718&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;nbsp;https://docs.oracle.com/javase/7/docs/api/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1613209536527&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.HashMap;
import java.util.Map.Entry;

public class test {
	public static void main(String[] args) {
		// 해시맵 선언
		HashMap&amp;lt;Integer, String&amp;gt; hm = new HashMap&amp;lt;Integer, String&amp;gt;();
		
		// 키, 값을 각각 추가한다.
		hm.put(1, &quot;kim&quot;);
		hm.put(2, &quot;lee&quot;);
		hm.put(3, &quot;park&quot;);
		// 키는 중복될 수 없다. 따라서 3번 키는 hong으로 갱신될 것이다.
		hm.put(3, &quot;hong&quot;);
		
		// 키를 기준으로 해당 데이터를 삭제할 수 있다.
		hm.remove(1);
		
		// 해시맵 전체 출력
		System.out.println(hm);
		// 해시맵의 키 전체 출력
		System.out.println(hm.keySet());
		// 해시맵의 값 전체 출력
		System.out.println(hm.values());
		
		// 반복을 이용하여 키와 그에 대응하는 값을 가져오는 코드
		for(Entry&amp;lt;Integer, String&amp;gt; h : hm.entrySet()) {
			System.out.println(h);
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/자료구조 for Algorithm</category>
      <category>HashMap</category>
      <category>java</category>
      <category>Map</category>
      <category>자바</category>
      <category>해시맵</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/47</guid>
      <comments>https://sskl660.tistory.com/47#entry47comment</comments>
      <pubDate>Sat, 13 Feb 2021 18:46:24 +0900</pubDate>
    </item>
    <item>
      <title>자바(Java) 싱글턴 패턴(Singleton Pattern)</title>
      <link>https://sskl660.tistory.com/46</link>
      <description>&lt;p&gt;&lt;b&gt;*싱글턴 패턴&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;&lt;b&gt;객체가 1개의 인스턴스만 가져야 하는 경우&lt;/b&gt; 사용하는 자바의 디자인 패턴 중 하나이다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;장점 : 인스턴스가 1개만 생성되기 때문에&amp;nbsp;&lt;b&gt;효율적인 메모리 관리가 가능&lt;/b&gt;하다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;단점 :&amp;nbsp;&lt;b&gt;동시에 해당 인스턴스를 공유하는 환경(특히, Multithread 환경)&lt;/b&gt;에서&amp;nbsp;&lt;b&gt;동시성(Concurrency) 문제 고려로 인하여 프로그램의 유연성&lt;/b&gt;&lt;b&gt;이 감소&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;※이러한&amp;nbsp;&lt;b&gt;동시성&lt;/b&gt;의 문제를 해결한 것을&amp;nbsp;&lt;b&gt;Thread-safe&lt;/b&gt;&lt;b&gt;하다 &lt;/b&gt;라고 한다. 여러가지 싱글턴 패턴(이른 초기화 방식, 게으른 초기화 방식...)이 존재하는데, 이 글에서는 이른 초기화 방식만 다룬다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*싱글턴 패턴 : 이른 초기화(Eager Initialization)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;이른 초기화는&amp;nbsp;&lt;b&gt;static 예약어를 사용&lt;/b&gt;하여&amp;nbsp;&lt;b&gt;정적 바인딩(Static binding)&lt;/b&gt;을 통해&amp;nbsp;&lt;b&gt;컴파일 시점에 인스턴스를 메모리에 등록&lt;/b&gt;하여 사용하는 방식이다. 최초로 클래스가 로딩 될 때 객체가 생성되기 때문에 Thread-safe하지만, static의 특성으로 인해 로딩 되는 시점부터 객체가 항상 생성되어 있기 때문에, 비효율적일 수 있는 문제가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1611372451200&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class BookMgr {
	// private 예약어를 사용하여 외부에서 해당 변수에 접근하지 못하도록 막는다.
	// static 예약어를 사용하여 클래스가 최초 로딩될 때 BookMgr 인스턴스가 생성된다.
	private static BookMgr manager = new BookMgr();
	
	// private 예약어를 사용하여 외부에서 BookMgr 생성자를 사용 못하도록 막는다. 
	private BookMgr() {

	}
	
	// public 예약어를 사용하여 해당 클래스 메서드를 통해서만 생성된 1개의 인스턴스를 반환하도록 한다.
	public static BookMgr getInstance() {
		return manager;
	}
}

public class SingletonTest{
	public static void main(String[] args) {
		// 클래스 메서드를 이용하여 1개 뿐인 BookMgr 인스턴스를 호출한다.
		BookMgr manager = BookMgr.getInstance();
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>ProgrammingLanguage/Java</category>
      <category>Eager Initialization</category>
      <category>Singleton Pattern</category>
      <category>싱글턴 패턴</category>
      <category>이른 초기화</category>
      <category>자바 싱글턴 패턴</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/46</guid>
      <comments>https://sskl660.tistory.com/46#entry46comment</comments>
      <pubDate>Sat, 23 Jan 2021 12:28:20 +0900</pubDate>
    </item>
    <item>
      <title>자바(Java) BufferedReader 클래스</title>
      <link>https://sskl660.tistory.com/45</link>
      <description>&lt;p&gt;자바의 &lt;b&gt;BufferedReader 클래스&lt;/b&gt;를 사용하기 전에, 먼저&amp;nbsp;&lt;b&gt;스트림(Stream)&lt;/b&gt;의 개념과,&amp;nbsp;&lt;b&gt;Scanner 클래스&lt;/b&gt;에 대해 먼저 간단히 이해 하는 것이 좋다. 잘 모른다면 아래 글을 참고하여 이해하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sskl660.tistory.com/44&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/44&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610976398547&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;스트림(Stream)과 자바(Java)의 Scanner 클래스&quot; data-og-description=&quot;*입출력 스트림(Stream) -&amp;gt;컴퓨터 공학에서 스트림은&amp;nbsp;연속적인 데이터의 흐름&amp;nbsp;혹은&amp;nbsp;데이터를 전송하는 소프트웨어 모듈을 말한다. 이름의 의미와 마찬가지로&amp;nbsp;스트림은 도착한 순서대로 데이터&quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/44&quot; data-og-url=&quot;https://sskl660.tistory.com/44&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ccKuRp/hyIYwO1Y1v/sZUPUKKkZzrATg3ibVjz31/img.png?width=69&amp;amp;height=53&amp;amp;face=0_0_69_53,https://scrap.kakaocdn.net/dn/bgrlwB/hyIYDm6hlS/UOr08CheHIaLyclv2TA4c1/img.png?width=69&amp;amp;height=53&amp;amp;face=0_0_69_53,https://scrap.kakaocdn.net/dn/Hd5cP/hyIZ10WHoi/yFSvjHJGl1UEi1aJGwkzG1/img.png?width=669&amp;amp;height=261&amp;amp;face=0_0_669_261&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/44&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/44&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ccKuRp/hyIYwO1Y1v/sZUPUKKkZzrATg3ibVjz31/img.png?width=69&amp;amp;height=53&amp;amp;face=0_0_69_53,https://scrap.kakaocdn.net/dn/bgrlwB/hyIYDm6hlS/UOr08CheHIaLyclv2TA4c1/img.png?width=69&amp;amp;height=53&amp;amp;face=0_0_69_53,https://scrap.kakaocdn.net/dn/Hd5cP/hyIZ10WHoi/yFSvjHJGl1UEi1aJGwkzG1/img.png?width=669&amp;amp;height=261&amp;amp;face=0_0_669_261');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;스트림(Stream)과 자바(Java)의 Scanner 클래스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;*입출력 스트림(Stream) -&amp;gt;컴퓨터 공학에서 스트림은&amp;nbsp;연속적인 데이터의 흐름&amp;nbsp;혹은&amp;nbsp;데이터를 전송하는 소프트웨어 모듈을 말한다. 이름의 의미와 마찬가지로&amp;nbsp;스트림은 도착한 순서대로 데이터&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*vs. Scanner&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;BufferedReader 와 Scanner 클래스는 대표적인 Java의 문자열을 입력받는 클래스이다. 특히&amp;nbsp;&lt;b&gt;알고리즘 문제 풀이시 대용량 데이터를 처리하는 경우, BufferedReader 클래스를 많이 사용&lt;/b&gt;하기 때문에, 우선은 알고리즘 문제 풀이시 참고할만한 수준에서 이 두 클래스의 용도를 구분하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;(1) &lt;b&gt;수행 시간(속도) 측면&lt;/b&gt; :&amp;nbsp;BufferedReader가 Scanner 클래스에 비하여 더 빠르게 입력을 처리할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H5XZe/btqTNA2Gd94/nCe0TVQUhZmLsNy1Skfw3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H5XZe/btqTNA2Gd94/nCe0TVQUhZmLsNy1Skfw3k/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://algospot.com/forum/read/2496/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H5XZe/btqTNA2Gd94/nCe0TVQUhZmLsNy1Skfw3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH5XZe%2FbtqTNA2Gd94%2FnCe0TVQUhZmLsNy1Skfw3k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;nbsp;https://algospot.com/forum/read/2496/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;※BufferedReader는 Scanner 클래스에 비해 더 큰 Buffer Size를 가지고 있으며, BufferedReader 클래스는 문자열을 단순히 읽어 들이는 방식이지만 Scanner 클래스는 문자열을 읽어 많은 정규식과 함께 구문 분석을 하는 용도로 사용되기 때문에 수행 시간의 차이가 발생한다! 정도로만 우선 알아두도록 하자.&lt;/p&gt;
&lt;p&gt;(참고 :&lt;a href=&quot;https://stackoverflow.com/questions/2231369/scanner-vs-bufferedreader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; stackoverflow.com/questions/2231369/scanner-vs-bufferedreader&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;※Buffer에 의한 수행 시간 차이 : Buffer는 데이터를 편리하게 이동시켜주는 수단이라고 생각하면 이해하기 좋다. 데이터를 스트림을 통해 이동한다고 하였는데, 이 데이터의 이동 자체가 자원이 드는 행위이다. 일상 생활에서 한 번에 많은 사람을 효율적으로 이동시키기 위하여 버스와 지하철을 이용하듯이, Buffer Size에 따라 한 번에 이동 시킬 수 있는 데이터의 양이 달라진다. 따라서, Buffer Size가 더 큰 BufferedReader 클래스가 더 빠른 처리 속도를 가지고 있는 것이다.&lt;/p&gt;
&lt;p&gt;(2) 사용성 측면 : Scanner 클래스가 BufferedReader 클래스에 비해 문자열을 파싱하는 여러 기능을 많이 가지고 있기 때문에,&amp;nbsp;사용하기 편하다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;쉽게 말해 간단한 문제의 경우 Scanner 클래스를 이용하여 간단하게 처리하면 되지만,&amp;nbsp;&lt;b&gt;알고리즘 문제를 풀 때 많은 입력 데이터로 인한 수행 시간 과부하를 방지하기 위해서는 BufferedReader 클래스를 사용&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*BufferedReader 클래스(알고리즘 문제에서 사용되는 예시)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;처음 사용하기는 까다롭지만 바이트 스트림과 문자 스트림, 그리고 버퍼에 대한 이해를 바탕으로 아래 단계를 이해하였다면 이후에는 암기하여 빠르게 입력 데이터를 처리하는 연습을 하도록 하자.&lt;/p&gt;
&lt;p&gt;(1) &lt;b&gt;InputStreamReader 클래스 이용&amp;nbsp;&lt;/b&gt;: 이 클래스는&amp;nbsp;&lt;b&gt;바이트 스트림과 문자 스트림을 연결시켜주는 다리 역할&lt;/b&gt;을 한다. 표준 입력(System.in)은 InputStream 형태로 지정되어 있으며, InputStream은 바이트 단위 입력 스트림의 취상위 클래스이다. 즉, &lt;b&gt;바이트 스트림인 System.in을 InputStreamReader 클래스를 이용하여 문자 스트림으로 변경시키는 작업&lt;/b&gt;을 먼저 해주어야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1610978532348&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;InputStreamReader in = new InputStreamReader(System.in);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(참고1. &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docs.oracle.com/javase/7/docs/api/java/io/InputStream.html).&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(참고2. &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/lang/System.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docs.oracle.com/javase/7/docs/api/java/lang/System.html&lt;/a&gt;).&lt;/p&gt;
&lt;figure id=&quot;og_1610978487119&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;InputStream (Java Platform SE 7 )&quot; data-og-description=&quot;Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown. If &quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html&quot; data-og-url=&quot;https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;InputStream (Java Platform SE 7 )&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown. If&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;(2) &lt;b&gt;BufferedReader 클래스 이용&lt;/b&gt; : InputStreamReader 클래스를 이용해 변환된 문자 스트림을 &lt;b&gt;버퍼 스트림에 저장&lt;/b&gt; 시킨다(쉽게 말해, 데이터를 버퍼라는 상자에 가공하여 적재시키는 단계).&lt;/p&gt;
&lt;pre id=&quot;code_1610978841747&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BufferedReader br = new BufferedReader(in);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;보통 앞선 1, 2 단계를 합쳐 아래와 같이 간단하게 작성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1610978890243&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BufferedReader br = new BufferedReader(new InputStreamReader(System.in));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(3) 적재된 데이터를 불러온다 : BufferedReader의 내부 메서드를 이용하여 데이터를 읽어온다. 보통 알고리즘 문제에서는 &lt;b&gt;1라인 단위 스트링 데이터&lt;/b&gt;로 많이 불러오기 때문에 &lt;b&gt;readLine() 메서드&lt;/b&gt;를 많이 사용한다.&lt;/p&gt;
&lt;p&gt;(BufferedReader 메서드 참고 :&amp;nbsp;&lt;b&gt;&lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html&lt;/a&gt;)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610979757962&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String line = br.readLine();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(4) &lt;b&gt;적재된 데이터를 가공한다&amp;nbsp;&lt;/b&gt;: 앞선 단계는 스트림을 적절히 변환 시키고, 적재된 데이터를 한 줄씩 불러오는 과정에 불과하다. 하지만&amp;nbsp;&lt;b&gt;대부분의&lt;/b&gt;&amp;nbsp;&lt;b&gt;알고리즘 문제를 푸는 경우, 불러온 데이터를 적절히 가공하여 사용하는 것이 주된 목표&lt;/b&gt;이다. 아래 두 방법은 보통 알고리즘 문제에서 BufferedReader에 적재된 데이터를 readLine() 메서드를 활용하여 한 줄 String 단위로 불러오고,&lt;b&gt; 해당 라인 내에서 '특정 문자'를 기준으로 데이터들을 분류하여 해석해야되는 경우가 많기&lt;/b&gt; &lt;b&gt;때문&lt;/b&gt;에 사용하는 것임을 알아두자. 즉, StringTokenizer 클래스와 String.split() 메서드는 &lt;b&gt;한 줄 String 데이터를 '특정 문자'를 기준으로 분류하기 편하기 때문에 사용&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(4 - 1)&amp;nbsp;&lt;b&gt;StringTokenizer 클래스 이용&amp;nbsp;&lt;/b&gt;: 생성된 객체에 &lt;b&gt;특정 문자를 기준으로 문자열을 분리하여 토큰 단위로 저장&lt;/b&gt;하고, 메서드를 이용해 저장된 문자열을 원하는 대로 불러올 수 있다.&lt;/p&gt;
&lt;p&gt;(StringTokenizer 메서드 참고 : &lt;a href=&quot;https://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Ex) StringTokenizer를 이용한 데이터의 가공과 사용 예.&lt;/p&gt;
&lt;pre id=&quot;code_1610981005547&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package practice;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class BufferedReaderTest {
	public static void main(String[] args) throws Exception {
		// 바이트 스트림인 System.in을 InputStreamReader 클래스를 이용하여 문자 스트림으로 바꾼다.
		// 바꾼 문자 스트림을 BufferedReader 클래스를 이용하여 버퍼 스트림으로 바꾼다.
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		// 버퍼 스트림에서 한 줄(Line) String 데이터를 불러온다.
		// 불러온 String 데이터를 공백을 기준으로 토큰단위로 나눈뒤 저장한다.
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		// hasMoreTokens() 메서드를 이용하여 st객체에 문자열이 남아있는지 확인한다.
		while(st.hasMoreTokens()) {
			// 남아있는 토큰을 하나씩 불러온다.
			String word = st.nextToken();
			System.out.print(word + &quot; &quot;);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;※만일 &lt;b&gt;불러온 &lt;/b&gt;&lt;b&gt;토큰 데이터를 정수로 변환&lt;/b&gt;하고 싶은 경우, Wrapper 클래스인 Integer 클래스를 적절히 활용하여 데이터를 가공할 수 있다!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(4 - 2)&amp;nbsp;&lt;b&gt;String.split() 메서드 이용&lt;/b&gt; : StringTokenizer 클래스와 마찬가지로 String.split() 메서드 또한&amp;nbsp;&lt;b&gt;특정 문자를 기준으로 문자열을 분리하여 토큰 단위로 저장&lt;/b&gt;할 수 있다. 다만,&amp;nbsp;&lt;b&gt;특정 배열을 생성하여 저장하여야하고, 해당 배열의 인덱스를 참조해서 불러오는등의&lt;/b&gt; &lt;b&gt;번거로움&lt;/b&gt;이 존재한다.&lt;/p&gt;
&lt;pre id=&quot;code_1610981562538&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package practice;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class BufferedReaderTest {
	public static void main(String[] args) throws Exception {
		// 바이트 스트림인 System.in을 InputStreamReader 클래스를 이용하여 문자 스트림으로 바꾼다.
		// 바꾼 문자 스트림을 BufferedReader 클래스를 이용하여 버퍼 스트림으로 바꾼다.
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		// 버퍼 스트림에서 한 줄(Line) String 데이터를 불러온다.
		// 불러온 String 데이터를 공백을 기준으로 나눈뒤  String 타입의 list 배열에 저장한다.
		String[] list = br.readLine().split(&quot; &quot;);
		
		// list 배열에 접근하여 데이터를 불러온다.
		for (int i = 0; i &amp;lt; list.length; i++) {
			System.out.println(list[i]);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>ProgrammingLanguage/Java</category>
      <category>BufferedReader Scanner</category>
      <category>BufferedReader 입력</category>
      <category>BufferedReader 클래스</category>
      <category>java</category>
      <category>String.split()</category>
      <category>StringTokenizer</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/45</guid>
      <comments>https://sskl660.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 18 Jan 2021 23:53:48 +0900</pubDate>
    </item>
    <item>
      <title>스트림(Stream)과 자바(Java)의 Scanner 클래스</title>
      <link>https://sskl660.tistory.com/44</link>
      <description>&lt;p&gt;&lt;b&gt;*입출력 스트림(Stream)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;컴퓨터 공학에서 스트림은&amp;nbsp;&lt;b&gt;연속적인 데이터의 흐름&lt;/b&gt;&amp;nbsp;혹은&amp;nbsp;&lt;b&gt;데이터를 전송하는 소프트웨어 모듈&lt;/b&gt;을 말한다. 이름의 의미와 마찬가지로&amp;nbsp;&lt;b&gt;스트림은 도착한 순서대로 데이터를 흘려&amp;nbsp;&lt;/b&gt;&lt;b&gt;보낸다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;스트림을 통해 흘러가는&amp;nbsp;&lt;b&gt;데이터의 기본 단위는 바이트(Byte)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;&lt;b&gt;입력 스트림(Input Stream) &lt;/b&gt;: 입력 장치(마우스, 키보드, 네트워크...)와 프로그램이 연결되어, &lt;b&gt;입력된 데이터가 프로그램으로 순서대로 흘러간다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cm9QqZ/btqTDbOhW87/1hKNibR7EMY6ghP8bq9jt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cm9QqZ/btqTDbOhW87/1hKNibR7EMY6ghP8bq9jt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cm9QqZ/btqTDbOhW87/1hKNibR7EMY6ghP8bq9jt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcm9QqZ%2FbtqTDbOhW87%2F1hKNibR7EMY6ghP8bq9jt1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt;&lt;b&gt;출력 스트림(Output Stream) &lt;/b&gt;: 프로그램과 출력 장치(모니터, 프린터, 네트워크...)가 연결되어, &lt;b&gt;출력 데이터가 출력 장치로 순서대로 흘러간다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8BIpi/btqTvQkhbVu/xJmUmiocGwiYTaTmX5FznK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8BIpi/btqTvQkhbVu/xJmUmiocGwiYTaTmX5FznK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8BIpi/btqTvQkhbVu/xJmUmiocGwiYTaTmX5FznK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8BIpi%2FbtqTvQkhbVu%2FxJmUmiocGwiYTaTmX5FznK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;※&lt;/b&gt;위의 그림을 통해&amp;nbsp;&lt;b&gt;스트림은 단방향&lt;/b&gt;이며,&amp;nbsp;&lt;b&gt;선입선출(FIFO) 구조&lt;/b&gt;임을 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-&amp;gt;자바는&amp;nbsp;&lt;b&gt;바이트 스트림&lt;/b&gt;과&amp;nbsp;&lt;b&gt;문자 스트림&lt;/b&gt;으로 나뉜다. 바이트 스트림은&amp;nbsp;&lt;b&gt;입출력되는 바이트의 바이너리 값을 있는 그대로 처리&lt;/b&gt;하므로 어떤 데이터가 들어와도 처리할 수 있다. 하지만 문자 스트림은&amp;nbsp;&lt;b&gt;오직 문자만 다룰 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;&lt;b&gt;자바의 표준 입출력 &lt;/b&gt;: 자바에서는 System 클래스를 이용하여 &lt;b&gt;표준 입력(System.in), 표준 출력(System.out), 표준 에러(System.err)&lt;/b&gt;&lt;b&gt;를 제공&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*Scanner 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;정규식을 사용하여&amp;nbsp;&lt;b&gt;기본 데이터 타입/문자열&lt;/b&gt;을&amp;nbsp;&lt;b&gt;구문 분석&lt;/b&gt;할 수 있는 간단한 텍스트 스캐너.&lt;/p&gt;
&lt;p&gt;※정규식(Regular expression, regex) : 특정한 규칙을 가진 문자열의 집합을 표현하는 형식 언어. 다양한 문자열의 검색과 치환을 위하여 지원된다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;쉽게 말해 Scanner 클래스는&amp;nbsp;&lt;b&gt;다양한 타입의 입력 값들을 읽어들이기 위한 편리한 방법을 제공하는 클래스&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;Scanner 클래스의 생성자에는 다양한 데이터가 들어갈 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1610623688782&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class ScannerTest {
	public static void main(String[] args) {
		// 표준 입력 스트림을 생성자로 Scanner 클래스를 선언한 예.
		Scanner scan = new Scanner(System.in);
		
		int a = scan.nextInt();
		String b = scan.next();
		
		System.out.println(a);
		System.out.println(b);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1610624038350&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ScannerTest {
	public static void main(String[] args) throws FileNotFoundException {
		// 텍스트 파일을 생성자로 Scanner 클래스를 선언한 예.
		Scanner scan = new Scanner(new File(&quot;./src/practice/myText.txt&quot;));
		
		while (scan.hasNext()) {
			int a = scan.nextInt();
			System.out.println(a);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-&amp;gt;Scanner은 &lt;b&gt;공백&lt;/b&gt; 또는 &lt;b&gt;개행 문자&lt;/b&gt;를 기준으로 입력 값들을 읽기 때문에,&amp;nbsp;&lt;b&gt;사용자의 편의에 따라 쉽게 입력을 받을 수 있는 장점&lt;/b&gt;이 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dO003m/btqTxCMLKDy/JBWdi1BkH2MKE6Q1fFASc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dO003m/btqTxCMLKDy/JBWdi1BkH2MKE6Q1fFASc1/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://docs.oracle.com/javase/7/docs/api/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dO003m/btqTxCMLKDy/JBWdi1BkH2MKE6Q1fFASc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdO003m%2FbtqTxCMLKDy%2FJBWdi1BkH2MKE6Q1fFASc1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;nbsp;https://docs.oracle.com/javase/7/docs/api/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;※nextLine() 메서드&amp;nbsp;&lt;/b&gt;: Scanner를 이용한 입력에서 특히 주의 해야하는 메서드이다. next(), nextInt() 등의 메서드는 &lt;b&gt;띄어쓰기를 기준&lt;/b&gt;으로 입력 값들을 읽고, nextLine() 메서드의 경우&amp;nbsp;&lt;b&gt;한 라인을 기준&lt;/b&gt;으로 입력 값들을 읽는다. 이 경우 문제가 발생할 수 있는데, next() 계열 메서드를 입력한 후&amp;nbsp;&lt;b&gt;Enter를 입력&lt;/b&gt;하는 경우, next()계열 메서드는 &lt;b&gt;Enter의 줄바꿈 문자를 처리하지 못하고 버퍼에 남겨 둔다. 이 남겨둔 개행 문자를 다음 라인에서 nextLine()이 인식하는 순간, 의도치 않은 출력 결과를 볼 수 있게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610626452644&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class ScannerTest {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);

		// 이름을 입력하고 Enter를 입력하면, Enter이전의 값들만 name에 입력되고 Enter 값은 버퍼에 남는다.
		String name = scan.next();
		// 버퍼에 남은 Enter값을 바로 인식해버려, grade에는 Enter값이 할당된다.
		String grade = scan.nextLine();

		System.out.println(name);
		System.out.println(grade);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXSoNm/btqTDc0NgPi/Xqi7bhrmAukf7ZB0PFpUj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXSoNm/btqTDc0NgPi/Xqi7bhrmAukf7ZB0PFpUj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXSoNm/btqTDc0NgPi/Xqi7bhrmAukf7ZB0PFpUj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXSoNm%2FbtqTDc0NgPi%2FXqi7bhrmAukf7ZB0PFpUj1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt;그림을 참고해보면, grade를 입력하기도 전에 프로그램이 종료된 것을 알 수 있다. 또한, 아래 공백문자가 grade의 값으로 출력된 것을 알 수 있다!(공백 문자를 인식하지 못했다면 아래 공백 부분은 출력되지 않는다). 이는 아래와 같은 두 가지 방법을 이용하여 해결 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;(1) 인위적인 개행 문자 제거&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610626884249&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;
import java.util.Scanner;

public class ScannerTest {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);

		
		int age = scan.nextInt();
		// 인위적으로 해당 라인을 삽입하여 개행 문자를 제거한다!
		scan.nextLine();
		String grade = scan.nextLine();

		System.out.println(age);
		System.out.println(grade);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;(2) Wrapper 클래스 활용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610626797210&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class ScannerTest {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);

		// 개행 문자까지 받은 뒤, Integer 클래스의 parseInt 메서드를 활용한다!
		int age = Integer.parseInt(scan.nextLine());
		String grade = scan.nextLine();

		System.out.println(age);
		System.out.println(grade);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>ProgrammingLanguage/Java</category>
      <category>scanner</category>
      <category>스트림(Stream)</category>
      <category>자바</category>
      <category>자바 표준입출력</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/44</guid>
      <comments>https://sskl660.tistory.com/44#entry44comment</comments>
      <pubDate>Thu, 14 Jan 2021 21:22:44 +0900</pubDate>
    </item>
    <item>
      <title>깊은 복사(Deep Copy)와 얕은 복사(Shallow Copy)</title>
      <link>https://sskl660.tistory.com/43</link>
      <description>&lt;p&gt;깊은 복사와 얕은 복사를 이해하기 위해서는 값 복사와 주소 복사를 이해해두어야 한다.&lt;/p&gt;
&lt;p&gt;잘 모른다면 아래 글을 참고하여 이해하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sskl660.tistory.com/37?category=866784&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sskl660.tistory.com/37?category=866784&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610542109221&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;메서드 Overloading과 매개변수&quot; data-og-description=&quot;*변수의 중복 선언 -&amp;gt;변수의 경우는&amp;nbsp;데이터의 타입이 달라도 변수 이름이 동일한 경우를 허용하지 않는다. Ex) 다음과 같은 경우는 컴파일 에러가 발생한다. class Employee { String name; // age 변수가 in&quot; data-og-host=&quot;sskl660.tistory.com&quot; data-og-source-url=&quot;https://sskl660.tistory.com/37?category=866784&quot; data-og-url=&quot;https://sskl660.tistory.com/37&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RQQV6/hyIVUnUEPK/5QEeEATsDscvqrqmNOkqf0/img.png?width=800&amp;amp;height=354&amp;amp;face=0_0_800_354,https://scrap.kakaocdn.net/dn/dxh6ba/hyIVXZeHdg/XjQrYAQXzTo1UOHYxgB9t0/img.png?width=800&amp;amp;height=354&amp;amp;face=0_0_800_354,https://scrap.kakaocdn.net/dn/U53P7/hyIVUBqBPe/AGe7zgNkmNj2KEGxVMHxR1/img.png?width=1045&amp;amp;height=775&amp;amp;face=0_0_1045_775&quot;&gt;&lt;a href=&quot;https://sskl660.tistory.com/37?category=866784&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sskl660.tistory.com/37?category=866784&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RQQV6/hyIVUnUEPK/5QEeEATsDscvqrqmNOkqf0/img.png?width=800&amp;amp;height=354&amp;amp;face=0_0_800_354,https://scrap.kakaocdn.net/dn/dxh6ba/hyIVXZeHdg/XjQrYAQXzTo1UOHYxgB9t0/img.png?width=800&amp;amp;height=354&amp;amp;face=0_0_800_354,https://scrap.kakaocdn.net/dn/U53P7/hyIVUBqBPe/AGe7zgNkmNj2KEGxVMHxR1/img.png?width=1045&amp;amp;height=775&amp;amp;face=0_0_1045_775');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;메서드 Overloading과 매개변수&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;*변수의 중복 선언 -&amp;gt;변수의 경우는&amp;nbsp;데이터의 타입이 달라도 변수 이름이 동일한 경우를 허용하지 않는다. Ex) 다음과 같은 경우는 컴파일 에러가 발생한다. class Employee { String name; // age 변수가 in&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;sskl660.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*얕은 복사(Shallow Copy)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;얕은 복사는 쉽게 말해 주소가 복사되는 것을 말한다.&lt;/p&gt;
&lt;pre id=&quot;code_1610542606529&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ShallowCopy {
	public static void main(String[] args) {
		int[] list = {1, 2, 3, 4};
		int[] shallow_copy = list;
		
		System.out.println(list);
		System.out.println(shallow_copy);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;272&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQsH6/btqTtqSKuBS/jgAR2qeVYQNdKKKTaIJt61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQsH6/btqTtqSKuBS/jgAR2qeVYQNdKKKTaIJt61/img.png&quot; data-alt=&quot;새로운 객체가 원본 객체와 동일한 주소를 바라본다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQsH6/btqTtqSKuBS/jgAR2qeVYQNdKKKTaIJt61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQsH6%2FbtqTtqSKuBS%2FjgAR2qeVYQNdKKKTaIJt61%2Fimg.png&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;272&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;새로운 객체가 원본 객체와 동일한 주소를 바라본다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt;장점 :&amp;nbsp;같은 객체를 공유하므로&amp;nbsp;&lt;b&gt;메모리를 절약&lt;/b&gt;하고,&amp;nbsp;&lt;b&gt;빠른&lt;/b&gt; 장점이 존재한다. 참조에 의한 호출(Call by Reference)에서 얕은 복사가 이루어 지는 이유 중 하나이기도 하다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;단점 :&amp;nbsp;두개 이상의 객체가 같은 대상을 가리키고 있기 때문에,&amp;nbsp;&lt;b&gt;의도치 않게 여러 개의 객체가 동시에 수정될 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;*깊은 복사(Deep Copy)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;-&amp;gt;얕은 복사가 주소 복사와 관련이 있듯이, 깊은 복사는 값 복사와 마찬가지로 생각하면 된다. 즉, 새로운 메모리 공간에 값을 복사하는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1610546078482&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DeepCopy {
	public static void main(String[] args) {
		int[] list = {1, 2, 3};
		int[] deep_copy = list.clone();
		
		System.out.println(list);
		System.out.println(deep_copy);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcO7Ix/btqTyBFMxox/tHaaeekZn9PIZmIIXe0gX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcO7Ix/btqTyBFMxox/tHaaeekZn9PIZmIIXe0gX1/img.png&quot; data-alt=&quot;새로운 객체는 새로운 메모리 공간에 값이 복사된다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcO7Ix/btqTyBFMxox/tHaaeekZn9PIZmIIXe0gX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcO7Ix%2FbtqTyBFMxox%2FtHaaeekZn9PIZmIIXe0gX1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;새로운 객체는 새로운 메모리 공간에 값이 복사된다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;-&amp;gt;장점 : 얕은 복사와 반대로&amp;nbsp;&lt;b&gt;여러 객체가 동시에 수정되는 일이 발생하지 않아, 변경에는 안전&lt;/b&gt;하다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;단점 : 객체 생성 &lt;b&gt;비용이 비싸며, 메모리를 많이 점유&lt;/b&gt;한다.&lt;/p&gt;
&lt;p&gt;-&amp;gt;특히, &lt;b&gt;특정 객체&lt;/b&gt;를 깊은 복사하는 경우 &lt;b&gt;Clonable 인터페이스를 활용하여, clone()메서드를 Overriding&lt;/b&gt;해주어야 깊은 복사가 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1610547131290&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A implements Cloneable {
	private String name;
	
	// Object 클래스는 자바의 최상위 클래스!
	// 새로운 Object를 넘겨주는 clone 메서드를 Overriding 한다.
	// CloneNotSupportedException은 해당 객체가 Clonable 인터페이스를 구현하고 있지 않는 경우를 대비한 예외이다.
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

public class DeepCopy {
	public static void main(String[] args) throws CloneNotSupportedException {
		A a = new A();
		// Object 클래스(부모 클래스)를 넘겨주므로, 캐스팅이 필요하다!
		A b = (A) a.clone();
		
		System.out.println(a);
		System.out.println(b);
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>ProgrammingLanguage/Java</category>
      <category>java</category>
      <category>값 복사</category>
      <category>깊은 복사</category>
      <category>얕은 복사</category>
      <category>주소 복사</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/43</guid>
      <comments>https://sskl660.tistory.com/43#entry43comment</comments>
      <pubDate>Wed, 13 Jan 2021 23:15:27 +0900</pubDate>
    </item>
    <item>
      <title>[Java]큐(Queue)</title>
      <link>https://sskl660.tistory.com/14</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*큐(Queue)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;큐란&lt;span&gt;&amp;nbsp;&lt;b&gt;선입&lt;/b&gt;&lt;/span&gt;&lt;b&gt;선출(FIFO : First In First Out)&lt;/b&gt;의 특성을 가진 자료구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;쉽게 말해&lt;b&gt;&lt;span&gt; 먼저&lt;/span&gt; 들어간 것이 먼저 나온다.&amp;nbsp;&lt;/b&gt;정거장에 들어오는 지하철이나, 놀이공원에 줄 서 있는 사람들을 생각하면 이해하기 쉽다.&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;346&quot; width=&quot;669&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ujXbr/btqXTmRQhKj/2BRzINJov42SxTHpfJm3I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ujXbr/btqXTmRQhKj/2BRzINJov42SxTHpfJm3I1/img.png&quot; data-alt=&quot;큐 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ujXbr/btqXTmRQhKj/2BRzINJov42SxTHpfJm3I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FujXbr%2FbtqXTmRQhKj%2F2BRzINJov42SxTHpfJm3I1%2Fimg.png&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;346&quot; width=&quot;669&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;큐 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*Java의 큐&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;-&amp;gt;큐&lt;/span&gt;&lt;/span&gt;&amp;nbsp;입력 연산은&lt;span&gt; 일반적으로 &lt;b&gt;offer&lt;/b&gt;&lt;/span&gt;&lt;b&gt;() &lt;/b&gt;메서드, 출력 연산은&lt;b&gt;&lt;span&gt; poll&lt;/span&gt;() &lt;/b&gt;메서드를 이용한다(add()와 remove()도 있지만, 이 메서드들은 Exception을 발생시키는 특징이 있다). &lt;b&gt;&amp;nbsp;head에 있는 원소(다음으로 나올 차례인 것)&lt;/b&gt;를&amp;nbsp;확인하는 연산은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;peek()&lt;/b&gt;메서드를 이용한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;274&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MYQe0/btqVH98P1Ii/sPA1TkLBFMxa1koOFeXZHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MYQe0/btqVH98P1Ii/sPA1TkLBFMxa1koOFeXZHK/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://docs.oracle.com/javase/7/docs/api/java/util/Queue.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MYQe0/btqVH98P1Ii/sPA1TkLBFMxa1koOFeXZHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMYQe0%2FbtqVH98P1Ii%2FsPA1TkLBFMxa1koOFeXZHK%2Fimg.png&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;274&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;nbsp;https://docs.oracle.com/javase/7/docs/api/java/util/Queue.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;자&lt;span style=&quot;color: #333333;&quot;&gt;바의 Queue관련 API를 살펴보면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인터페이스로 구현&lt;/b&gt;되어 있기 때문에,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;큐 인터페이스를 상속하여 구현해놓은 LinkedList&amp;lt;E&amp;gt;클래스를 이용하여 객체를 생성한다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※이외에도 큐는 여러 방면으로 활용되는 경우가 많아,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;우선순위큐(PriorityQueue)등의 다른 클래스들을 이용하여 객체를 생성하고 활용할수도 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1612354995390&quot; class=&quot;html xml&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.LinkedList;
import java.util.Queue;

public class test {
	public static void main(String[] args) {
		Queue&amp;lt;Integer&amp;gt; q = new LinkedList&amp;lt;Integer&amp;gt;();
		
        // 큐에 1, 2, 3, 4를 차례로 넣는다.
		q.offer(1);
		q.offer(2);
		q.offer(3);
		q.offer(4);
        // 제일 처음 넣은 1을 뺀다.
		q.poll();
        // 제일 head의 원소를 확인 : 결과는 2.
		System.out.println(q.peek());
		System.out.println(q);
		q.clear();
		System.out.println(q);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/자료구조 for Algorithm</category>
      <category>java</category>
      <category>Queue</category>
      <category>자료구조</category>
      <category>자바</category>
      <category>큐</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/14</guid>
      <comments>https://sskl660.tistory.com/14#entry14comment</comments>
      <pubDate>Fri, 25 Sep 2020 21:22:53 +0900</pubDate>
    </item>
    <item>
      <title>[Java]스택(Stack)</title>
      <link>https://sskl660.tistory.com/13</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*스택(Stack)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;스택이란 &lt;b&gt;후입선출(LIFO : Last In First Out)&lt;/b&gt;의 특성을 가진 자료구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;쉽게 말해 &lt;b&gt;나중에 들어간 것이 먼저 나온다.&lt;/b&gt; 마트의 진열대에 물건을 놓거나, 상자에 물건을 넣은 뒤 꺼내는 것을 예시로 생각해보면 이해하기 쉽다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;476&quot; data-origin-height=&quot;329&quot; width=&quot;450&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rnfWv/btqVJSZRdy1/kF4SUW7WzYob8KGvarZ160/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rnfWv/btqVJSZRdy1/kF4SUW7WzYob8KGvarZ160/img.png&quot; data-alt=&quot;스택 자료구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rnfWv/btqVJSZRdy1/kF4SUW7WzYob8KGvarZ160/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrnfWv%2FbtqVJSZRdy1%2FkF4SUW7WzYob8KGvarZ160%2Fimg.png&quot; data-origin-width=&quot;476&quot; data-origin-height=&quot;329&quot; width=&quot;450&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스택 자료구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*Java의 스택 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-&amp;gt;자&lt;span style=&quot;color: #333333;&quot;&gt;바의 Stack관련 API를 살펴보면 &lt;/span&gt;스택 입력 연산은 &lt;b&gt;push()&lt;/b&gt;, 출력 연산은 &lt;b&gt;pop()&lt;/b&gt;메서드를 이용하며, &lt;b&gt;top에 있는 원소(제일 마지막에 넣은 것)&lt;/b&gt;를&amp;nbsp;확인하는 연산은 &lt;b&gt;peek()&lt;/b&gt;메서드를 이용한다. 언급한 연산 이외에 스택이 비어있는지 확인하는 empty() 메서드, 스택안에 어떤 아이템이 있는지 확인하는 search()메서드가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;855&quot; data-origin-height=&quot;272&quot; width=&quot;720&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/04lsF/btqVJR0UIG2/p1SSjJcqYeLDihH7aFS2Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/04lsF/btqVJR0UIG2/p1SSjJcqYeLDihH7aFS2Ck/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/04lsF/btqVJR0UIG2/p1SSjJcqYeLDihH7aFS2Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F04lsF%2FbtqVJR0UIG2%2Fp1SSjJcqYeLDihH7aFS2Ck%2Fimg.png&quot; data-origin-width=&quot;855&quot; data-origin-height=&quot;272&quot; width=&quot;720&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;nbsp;https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;스택은 java.util.Vector&amp;lt;E&amp;gt; 클래스를 상속하기 때문에 여러 다양한 메서드를 호출하거나 재정의하여 편리하게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;자바의 스택 역시 객체를 생성하고 위의 연산을 적절히 활용하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612354961891&quot; class=&quot;html xml&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Stack;

public class Stack {
	public static void main(String[] args) {
		Stack&amp;lt;Integer&amp;gt; st = new Stack&amp;lt;Integer&amp;gt;();
		
        // 스택에 1, 2, 3, 4를 차례로 넣는다.
		st.push(1);
		st.push(2);
		st.push(3);
		st.push(4);
        // 제일 마지막에 넣은 4를 뺀다.
		st.pop();
        // 제일 위의 원소 확인 : 결과는 3.
		System.out.println(st.peek());
		System.out.println(st.search(3));
        // toString()이 정의되어 있어, 스택을 쉽게 확인할 수 있다.
		System.out.println(st);
		st.clear();
		System.out.println(st);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/자료구조 for Algorithm</category>
      <category>java</category>
      <category>스택</category>
      <category>자료구조</category>
      <category>자바</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/13</guid>
      <comments>https://sskl660.tistory.com/13#entry13comment</comments>
      <pubDate>Fri, 25 Sep 2020 21:22:30 +0900</pubDate>
    </item>
    <item>
      <title>[Java]좌표 이동/탐색</title>
      <link>https://sskl660.tistory.com/12</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*좌표 이동/탐색&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; DFS/BFS 문제를 접하다 보면, &lt;b&gt;좌표의 성질을 갖는 대상&lt;/b&gt;&lt;b&gt;의 원소&lt;/b&gt;에서 &lt;b&gt;다른 원소로 이동&lt;/b&gt;하거나, &lt;b&gt;그 주변을 탐색&lt;/b&gt;해야하는 로직이 빈번하게 사용된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*2차원 배열 좌표와 행렬&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 2차원 배열의 &lt;b&gt;인덱스별 값이 생기는 위치를 시각화&lt;/b&gt;하여 생각해보면 &lt;b&gt;평면&lt;/b&gt;을 떠올릴 수 있고, 평면은 일상 생활에서 보통 좌표를 이용하여 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 일반적으로 수학에서 좌표의 1사분면은, 다음과 같은 모양을 가진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;502&quot; width=&quot;348&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DC2Zm/btqXMdojhtx/VDsaCqgkniUAu9yVp0dbdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DC2Zm/btqXMdojhtx/VDsaCqgkniUAu9yVp0dbdk/img.png&quot; data-alt=&quot;수학의 좌표 평면 1사분면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DC2Zm/btqXMdojhtx/VDsaCqgkniUAu9yVp0dbdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDC2Zm%2FbtqXMdojhtx%2FVDsaCqgkniUAu9yVp0dbdk%2Fimg.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;502&quot; width=&quot;348&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수학의 좌표 평면 1사분면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp;&lt;b&gt;x값이 증가할수록 오른 쪽으로 이동&lt;/b&gt;하고, &lt;b&gt;&amp;nbsp;y값이 증가할수록 위 쪽으로 이동&lt;/b&gt;하는 구조를 가진다.&amp;nbsp;&lt;b&gt;&lt;u&gt;그렇지만, 일반적으로 2차원 배열을 형성하는 경우 인덱스 별 값이 생기는 위치는 논리적으로 좌표 평면 1사분면의 구조처럼 평면이 만들어지지 않는다.&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 2차원 배열을 형성하는 경우는 다음과 같이 좌표 평면의 3사분면의 모양과 같이 논리적 평면이 생기지만, 좌표 평면의 3사분면과 다른점은&amp;nbsp;&lt;b&gt;아래 쪽으로 이동할 수록 y값이 증가한다는 사실&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;498&quot; width=&quot;348&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yEdSE/btqXTmqJrwd/n4Xb2lsLbyRWqs1Ek544o1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yEdSE/btqXTmqJrwd/n4Xb2lsLbyRWqs1Ek544o1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yEdSE/btqXTmqJrwd/n4Xb2lsLbyRWqs1Ek544o1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyEdSE%2FbtqXTmqJrwd%2Fn4Xb2lsLbyRWqs1Ek544o1%2Fimg.png&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;498&quot; width=&quot;348&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;따라서 2차원 배열의 인덱스별 값의 위치를 평면화하여 생각하는 경우는&amp;nbsp;&lt;b&gt;행렬을 바탕으로 생각하는 것&lt;/b&gt;&lt;b&gt;이 더 편리하다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;261&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDWsgX/btqXJVonI8G/4HdvC8sDFROG5boqJgo6CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDWsgX/btqXJVonI8G/4HdvC8sDFROG5boqJgo6CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDWsgX/btqXJVonI8G/4HdvC8sDFROG5boqJgo6CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDWsgX%2FbtqXJVonI8G%2F4HdvC8sDFROG5boqJgo6CK%2Fimg.png&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;261&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*방향&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 어떤 대상을 기준으로&amp;nbsp;&lt;b&gt;어디로 움직일 것 인가&lt;/b&gt; 혹은&amp;nbsp;&lt;b&gt;어디로 탐색할 것 인가&lt;/b&gt;를 고민하기 위해서는&amp;nbsp;&lt;b&gt;방향&lt;/b&gt;&lt;b&gt;을 먼저 설정&lt;/b&gt;해주어야 한다. 방향을 표현하는 방법은 대표적으로 아래 두 가지 방법이 있다. 자신에게 맞는 방법을 적절히 활용하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 두 개의 일차원 배열을 이용하여 방향을 나타내는 방법&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613648173106&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 상하좌우
int[] dr = { -1, 1, 0, 0 };
int[] dc = { 0, 0, -1, 1 };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 2차원 배열의 인덱스 별 값의 위치는 행렬을 기반으로 생각하여야 한다고 했다. 즉, &lt;b&gt;행렬을 기준으로 어떤 수의 위에 있으면 행이 감소&lt;/b&gt;하고 &lt;b&gt;열은 그대로 유지&lt;/b&gt;할 것이기 때문에 dr[0] = -1, dc[0] = 0의 값을 갖는다. 마찬가지 방법을 통해 아래, 왼쪽, 오른쪽 방향도 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 이차원 배열을 이용하여 방향을 나타내는 방법&lt;/p&gt;
&lt;pre id=&quot;code_1613648356029&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 상하좌우
int[][] drdc = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 위의 로직과 다른 것이 없다. 2차원 배열의 1열이 행의 방향을 의미하고, 2열이 열의 방향을 의미한다고 생각한 뒤 이를 한 번에 저장해준 것 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*이동&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이를 테면, false으로 초기화된 boolean 2차원 배열에서 이동명령에 따라 이동하는 위치마다 true로 바꾸는 경우는 다음과 같이 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1613649412966&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.Scanner;

public class Move {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 상하좌우
		int[] dr = { -1, 1, 0, 0 };
		int[] dc = { 0, 0, -1, 1 };
		// 방향을 저장할 변수(기본 방향은 상).
		int dir = 0;
		// 맵
		boolean[][] map = new boolean[3][3];

		// 명령 입력, 0행 0열부터 시작.
		System.out.print(&quot;이동 명령을 입력하세요(Ex : RRDDRDL) : &quot;);
		String move = sc.nextLine();
		map[0][0] = true;
		int r = 0, c = 0;

		// 이동
		for (int i = 0; i &amp;lt; move.length(); i++) {
			char a = move.charAt(i);
			System.out.println(&quot;움직일 방향 출력 : &quot; + a);
			// 각 문자를 해석해 맞는 방향을 세팅 해준다.
			switch (a) {
			case 'U':
				dir = 0;
				break;
			case 'D':
				dir = 1;
				break;
			case 'L':
				dir = 2;
				break;
			case 'R':
				dir = 3;
				break;
			}
			// 이동.
			r += dr[dir];
			c += dc[dir];
			map[r][c] = true;
			// 현재 맵의 상태 출력
			for(int j = 0; j &amp;lt; 3; j++) {
				System.out.println(Arrays.toString(map[j]));
			}
			System.out.println();
		}
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;291&quot; width=&quot;292&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKVsBP/btqXSoI6oOb/RGn8JOQ3GWSduRQhUDpWw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKVsBP/btqXSoI6oOb/RGn8JOQ3GWSduRQhUDpWw0/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKVsBP/btqXSoI6oOb/RGn8JOQ3GWSduRQhUDpWw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKVsBP%2FbtqXSoI6oOb%2FRGn8JOQ3GWSduRQhUDpWw0%2Fimg.png&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;291&quot; width=&quot;292&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 보통 알고리즘 문제를 푸는 경우, &lt;b&gt;주어진 평면의 바깥으로 나가는 경우(인덱스 범위를 초과하는 경우)&lt;/b&gt;를 고려해야하는 로직이 많다. 이 경우,&amp;nbsp;&lt;b&gt;다음 인덱스를 미리 저장하고 테스트해볼 변수를 새로 선언&lt;/b&gt;하여 문제를 해결한다.&lt;/p&gt;
&lt;pre id=&quot;code_1613649752189&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.Scanner;

public class Move {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 상하좌우
		int[] dr = { -1, 1, 0, 0 };
		int[] dc = { 0, 0, -1, 1 };
		// 방향을 저장할 변수(기본 방향은 상).
		int dir = 0;
		// 맵
		boolean[][] map = new boolean[3][3];

		// 명령 입력, 0행 0열부터 시작.
		System.out.print(&quot;이동 명령을 입력하세요(Ex : RRDDRDL)(바깥으로 나가면 함수 종료) : &quot;);
		String move = sc.nextLine();
		map[0][0] = true;
		int r = 0, c = 0;
		// 임시로 이동할 좌표를 먼저 설정.
		int nr, nc;

		// 이동
		for (int i = 0; i &amp;lt; move.length(); i++) {
			char a = move.charAt(i);
			System.out.println(&quot;움직일 방향 출력 : &quot; + a);
			// 각 문자를 해석해 맞는 방향을 세팅 해준다.
			switch (a) {
			case 'U':
				dir = 0;
				break;
			case 'D':
				dir = 1;
				break;
			case 'L':
				dir = 2;
				break;
			case 'R':
				dir = 3;
				break;
			}
			// 임시로 이동
			nr = r + dr[dir];
			nc = c + dc[dir];
			// 바깥으로 이동하는지 체크하는 if 제어문!!
			if (0 &amp;lt;= nr &amp;amp;&amp;amp; nr &amp;lt; 3 &amp;amp;&amp;amp; 0 &amp;lt;= nc &amp;amp;&amp;amp; nc &amp;lt; 3) {
				r = nr;
				c = nc;
				map[r][c] = true;
			} else {
				System.out.println(&quot;바깥으로 이동할 수 없습니다.&quot;);
                sc.close();
				return;
			}
			// 현재 맵의 상태 출력
			for (int j = 0; j &amp;lt; 3; j++) {
				System.out.println(Arrays.toString(map[j]));
			}
			System.out.println();
		}
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;249&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lsmOW/btqXRu3SYuK/4R4TKOJbDZQ1GUKl1XhDN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lsmOW/btqXRu3SYuK/4R4TKOJbDZQ1GUKl1XhDN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lsmOW/btqXRu3SYuK/4R4TKOJbDZQ1GUKl1XhDN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlsmOW%2FbtqXRu3SYuK%2F4R4TKOJbDZQ1GUKl1XhDN0%2Fimg.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;249&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*탐색&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 탐색도 이동과 크게 다를 것 없다. &lt;b&gt;어떤 인덱스의 위치를 기준으로, 순차적으로 주변을 탐색하고 싶은 경우에는 우선 방향을 잘 설정해주면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 상하좌우 &lt;b&gt;&amp;lt;4방향&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613649958638&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 상하좌우
int[] dr = { -1, 1, 0, 0 };
int[] dc = { 0, 0, -1, 1 };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;※ 12시, 1시, 3시, 5시, 6시, 7시, 9시, 11시 &lt;b&gt;&amp;lt;8방향&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613649961848&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 12시, 1시, 3시, 5시, 6시, 7시, 9시, 11시
int[] dr = { -1, -1, 0, 1, 1, 1, 0, -1 };
int[] dc = { 0, 1, 1, 1, 0, -1, -1, -1};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이를 테면, 3x3 int 배열의 특정 인덱스의 8방향에 3이라는 숫자가 몇개 있는지 탐색하는 경우는 다음과 같이 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1613652051420&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Search {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		int[][] map = new int[3][3];
		System.out.println(&quot;배열에 넣을 숫자를 입력하세요.&quot;);
		// 3,3 int 배열에 입력된 숫자를 대입한다.
		for (int i = 0; i &amp;lt; 3; i++) {
			String line = sc.nextLine();
			for (int j = 0; j &amp;lt; 3; j++) {
				map[i][j] = line.charAt(j) - '0';
			}
		}

		// 탐색할 좌표 입력
		int r = sc.nextInt();
		int c = sc.nextInt();

		// 3의 개수 파악.
		int cnt = 0;
		// 12시, 1시, 3시, 5시, 6시, 7시, 9시, 11시
		int[] dr = { -1, -1, 0, 1, 1, 1, 0, -1 };
		int[] dc = { 0, 1, 1, 1, 0, -1, -1, -1 };
		for (int i = 0; i &amp;lt; 8; i++) {
			if (map[r + dr[i]][c + dc[i]] == 3) {
				cnt++;
			}
		}
		// 결과 출력
		System.out.println(cnt);
		sc.close();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;187&quot; data-origin-height=&quot;115&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l4Kvc/btqXTohP73E/EmsNYxvMiUlLJUXngzHKc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l4Kvc/btqXTohP73E/EmsNYxvMiUlLJUXngzHKc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l4Kvc/btqXTohP73E/EmsNYxvMiUlLJUXngzHKc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl4Kvc%2FbtqXTohP73E%2FEmsNYxvMiUlLJUXngzHKc0%2Fimg.png&quot; data-origin-width=&quot;187&quot; data-origin-height=&quot;115&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Algorithm/수학&amp;amp;기타</category>
      <category>4방 탐색</category>
      <category>8방 탐색</category>
      <category>java</category>
      <category>자바</category>
      <category>좌표 이동</category>
      <category>탐색</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/12</guid>
      <comments>https://sskl660.tistory.com/12#entry12comment</comments>
      <pubDate>Fri, 25 Sep 2020 21:21:00 +0900</pubDate>
    </item>
    <item>
      <title>시간 복잡도 측정</title>
      <link>https://sskl660.tistory.com/11</link>
      <description>&lt;p&gt;알고리즘 문제를 푸는 경우, 시간 복잡도를 분석해야하는 경우가 많다.&lt;/p&gt;
&lt;p&gt;기본적으로 시간 복잡도를 항상 생각하며 문제를 푸는 것을 우선으로 하고, 만일 직관적으로 자신의 코드가 어느정도 성능을 가지고 있는지 파악하고 싶다면 아래와 같은 코드를 활용해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1600530400369&quot; class=&quot;python&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import time # 시간 라이브러리 함수

start = time.time() # 시간 측정 함수

# 측정하고자 하는 code

end = time.time()
print(&quot;time :&quot;, end - start) # 수행 시간 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>ProgrammingLanguage/Python</category>
      <category>Python</category>
      <category>time</category>
      <category>시간 측정</category>
      <category>파이썬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/11</guid>
      <comments>https://sskl660.tistory.com/11#entry11comment</comments>
      <pubDate>Sun, 20 Sep 2020 00:47:27 +0900</pubDate>
    </item>
    <item>
      <title>딕셔너리(dictionary) 자료형</title>
      <link>https://sskl660.tistory.com/10</link>
      <description>&lt;p&gt;&lt;b&gt;딕셔너리&lt;/b&gt;는 &lt;b&gt;키(Key)와 값(Value)의 쌍을 데이터로 가지는 자료형&lt;/b&gt;이다. &lt;b&gt;이름 그대로 사전을 생각하면 이해하기 쉽다.&lt;/b&gt; 예를 들어 평일을 딕셔너리 자료형을 이용하여 영어 사전 처럼 저장하고 싶은 경우, 다음과 같은 코드를 작성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1600524334266&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;week = dict()
week['월'] = 'Monday'
week['화'] = 'Tuesday'
week['수'] = 'Wednesday'
week['목'] = 'Thursday'
week['금'] = 'Friday'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음과 같이 바로 초기화 할수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1600524437751&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;week = {'월' : 'Monday', '화' : 'Tuesday', '수' : 'Wednesday', '목' : 'Thursday', '금' : 'Friday'}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;딕셔너리 자료형이 중요한 이유는, &lt;b&gt;파이썬에서 해당 자료형은 해시 테이블(Hash table)을 이용&lt;/b&gt;하기 때문에 &lt;b&gt;데이터의 검색 및 수정에 있어서 O(1)의 시간밖에 소요하지 않기 때문&lt;/b&gt;이다(Set 자료형도 O(1)의 시간밖에 소요하지 않는다). 일반적으로 &lt;b&gt;리스트에서 어떤 대상을 검색하는 경우 O(n)시간이 걸리는 것&lt;/b&gt;을 생각하면, 특정 문제를 해결 할 때는 사전 자료형이 더욱 효과적일 수 있다.&lt;/p&gt;</description>
      <category>ProgrammingLanguage/Python</category>
      <category>Dictionary</category>
      <category>딕셔너리</category>
      <category>자료형</category>
      <category>파이썬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/10</guid>
      <comments>https://sskl660.tistory.com/10#entry10comment</comments>
      <pubDate>Sat, 19 Sep 2020 23:10:21 +0900</pubDate>
    </item>
    <item>
      <title>리스트 컴프리헨션/2차원 배열 초기화</title>
      <link>https://sskl660.tistory.com/9</link>
      <description>&lt;p&gt;파이썬은 &lt;b&gt;컴프리헨션(Comprehension)&lt;/b&gt;을 이용하여 &lt;b&gt;반복 되거나 특정 조건을 만족하는 리스트를 쉽게 만들어낼 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;이것을 &lt;b&gt;리스트 컴프리헨션(List Comprehension)&lt;/b&gt;이라고 한다. 이 외에도 딕셔너리 컴프리헨션, 셋 컴프리헨션이 있으니 참고하도록 하자. 리스트 컴프리헨션은 특히 파이썬에서 다차원 리스트를 초기화 하는 경우 유용하게 사용되므로 익숙해지도록 하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예를 들어, 0부터 9까지의 수를 1차원 리스트에 담고 싶은경우 일반적으로 다음과 같은 방법을 생각할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1600520688973&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = [0] * 10
for i in range(10):
	arr[i] = i&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만 컴프리헨션을 이용한다면, 다음과 같이 한 줄의 코드 만으로 1차원 리스트를 초기화 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1600520527374&quot; class=&quot;python&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = [i for i in range(10)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이와 같이 리스트 컴프리헨션은 &lt;b&gt;앞에 반복을 원하는 대상을 두고, 뒤의 for 문을 조작해 줌으로써 원하는 동작을 하도록 만들 수 있다.&lt;/b&gt; 다른 예시로 0부터 9까지의 수를 반복하여 출력하고 싶다면, 다음과 같이 작성해볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1600521196838&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[print(i) for i in range(10)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;여기서 더 나아가 &lt;b&gt;반복되는 대상에 조건을 달아주고 싶다면, for문 뒤에 조건문을 붙여주면 된다.&lt;/b&gt; 예를 들어 0부터 9까지의 숫자 중 짝수만을 출력하고 싶다면 다음과 같은 코드를 작성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1600521399326&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[print(i) for i in range(10) if i % 2 == 0]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;만일 &lt;b&gt;2중 for문을 이용하여 반복하고 싶다면, 뒤에 for문을 더 붙여주기만 하면 된다.&lt;/b&gt; 다음과 같은 코드를 작성해보고 결과를 출력해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1600521629436&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[i + j for i in range(3) for j in range(3)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;▶2차원 리스트 초기화&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;파이썬에서 2차원 리스트를 초기화 해주고 싶은 경우, 반드시 리스트 컴프리헨션을 이용해 주어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;예를 들어 다음과 같이 2차원 리스트를 초기화 한다면, 내부에 있는 리스트가 모두 같은 대상을 참조하기 때문에 리스트 내부의 값을 변경하는 경우 문제가 발생한다. 아래와 같이 코드를 작성해보고, 결과를 출력해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1600521946281&quot; class=&quot;python&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = [[0] * 5] * 5
arr[0][0] = 5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 문제에 대해 더 자세히 알고 싶다면, &lt;b&gt;얕은 복사와 깊은 복사&lt;/b&gt;의 개념에 대해서 공부하도록 하자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이러한 문제가 있기 때문에, 파이썬에서 2차원 리스트를 초기화 하는 경우 리스트 컴프리헨션을 이용한다. 일반적으로 코딩 문제를 풀 때 행렬을 표현하기 위하여 2차원 리스트를 활용하는 경우가 많은데, 여기서는 예를 들어 3x4행렬을 만든다고 가정하면 다음과 같은 코드를 작성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1600522144459&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr = [[0 for col in range(4)] for row in range(3)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마찬가지로 arr[0][0]에 아무 값이나 대입해보면, 원하는 인덱스의 값만 바뀌는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이처럼 컴프리헨션은 파이썬이 다른 언어에 비하여 코드를 간결하게 만들 수 있는 강력한 무기 중 하나이므로, 반드시 익숙해지도록 하자.&lt;/p&gt;</description>
      <category>ProgrammingLanguage/Python</category>
      <category>2차원 배열 초기화</category>
      <category>Python</category>
      <category>리스트</category>
      <category>컴프리헨션</category>
      <category>파이썬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/9</guid>
      <comments>https://sskl660.tistory.com/9#entry9comment</comments>
      <pubDate>Sat, 19 Sep 2020 22:30:52 +0900</pubDate>
    </item>
    <item>
      <title>e 혹은 E를 이용한 지수 표현</title>
      <link>https://sskl660.tistory.com/8</link>
      <description>&lt;p&gt;코딩 테스트를 준비하다보면, 매우 크거나 작은 수를 표현해야 하는 경우가 있다.&lt;/p&gt;
&lt;p&gt;이런 경우 &lt;b&gt;e나 E를 이용한 지수 표현 방식&lt;/b&gt;을 이용하면 &lt;b&gt;이를 쉽게 표현할 수 있고, 수를 표기할 때 실수를 줄일 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;이렇게 표현된 수는 &lt;span style=&quot;color: #ee2323;&quot;&gt;실수형&lt;/span&gt;으로 인식된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;유효숫자e지수(or 유효숫자E지수) == 유효숫자 * 10^지수&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ex1) 2020.0919 == 20200919e-4&lt;/p&gt;
&lt;p&gt;Ex2) 10000000000.0 == 1e10&lt;/p&gt;</description>
      <category>ProgrammingLanguage/Python</category>
      <category>Python</category>
      <category>지수 표현식</category>
      <category>파이썬</category>
      <author>sskl660</author>
      <guid isPermaLink="true">https://sskl660.tistory.com/8</guid>
      <comments>https://sskl660.tistory.com/8#entry8comment</comments>
      <pubDate>Sat, 19 Sep 2020 21:36:51 +0900</pubDate>
    </item>
  </channel>
</rss>