<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발 공부 기록</title>
    <link>https://dev-ocean.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 18:45:59 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>깊은바다거북</managingEditor>
    <item>
      <title>12/5 (화) D3.js로 그래프 자료구조 시각화하기 TIL</title>
      <link>https://dev-ocean.tistory.com/235</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;dedb8871-fe40-4e4d-af99-4f0b623fed3c&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;p class=&quot;&quot; id=&quot;8ad4e78b-a072-45b6-9545-e0f2d807bb5e&quot;&gt;
&lt;/p&gt;&lt;p class=&quot;&quot; id=&quot;276dd7a3-9c3b-4375-8ac1-66e70c12a3b3&quot;&gt;다음과 같이 생긴 노드-간선 그래프를 그리려고 한다. &lt;/p&gt;&lt;figure class=&quot;image&quot; id=&quot;8c6a5120-663e-4f69-92f8-43e01304642a&quot;&gt;&lt;a href=&quot;https://assets.leetcode.com/uploads/2021/05/02/reduntant1-2-graph.jpg&quot;&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/05/02/reduntant1-2-graph.jpg&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;toggle&quot; id=&quot;8d3f1c91-63e0-4e8d-9661-71dae7043b52&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;간선 데이터가 &lt;code&gt;edges = [[1,2],[2,3],[3,4],[1,4],[1,5]]&lt;/code&gt; 와 같은 식으로 주어진다고 할 때, 그래프(Graph) 자료구조를 시각화하는 HTML, JS, CSS 코드는 다음과 같다(&lt;strong&gt;D3.js&lt;/strong&gt; 라이브러리 활용): &lt;/summary&gt;&lt;pre class=&quot;code HTML&quot; id=&quot;55f464d8-6bc5-4bde-a069-13551b9e8751&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;

&amp;lt;head&amp;gt;
	&amp;lt;title&amp;gt;Graph Visualization&amp;lt;/title&amp;gt;
	&amp;lt;script src=&quot;https://d3js.org/d3.v3.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
	&amp;lt;style&amp;gt;
		.link {
			stroke: #999;
			stroke-opacity: 0.6;
		}

		.node {
			fill: #ccc;
			stroke: #fff;
			stroke-width: 1.5px;
		}
	&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
	&amp;lt;script&amp;gt;
		// 간선 데이터
		var edges = [
			{ source: 1, target: 2 },
			{ source: 2, target: 3 },
			{ source: 3, target: 4 },
			{ source: 1, target: 4 },
			{ source: 1, target: 5 }
		];

		// 노드 데이터 생성
		var nodes = {};
		edges.forEach(function (edge) {
			edge.source = nodes[edge.source] || (nodes[edge.source] = { id: edge.source });
			edge.target = nodes[edge.target] || (nodes[edge.target] = { id: edge.target });
		});

		// SVG 요소의 크기
		var width = 800, height = 600;

		// D3.js force layout 설정
		var force = d3.layout.force()
			.nodes(d3.values(nodes))
			.links(edges)
			.size([width, height])
			.linkDistance(150)
			.charge(-800)
			.on(&quot;tick&quot;, tick)
			.start();

		// SVG 요소 추가
		var svg = d3.select(&quot;body&quot;).append(&quot;svg&quot;)
			.attr(&quot;width&quot;, width)
			.attr(&quot;height&quot;, height);

		// 간선을 SVG 선으로 표현
		var link = svg.selectAll(&quot;.link&quot;)
			.data(force.links())
			.enter().append(&quot;line&quot;)
			.attr(&quot;class&quot;, &quot;link&quot;);

		// 노드를 SVG 원으로 표현
		var node = svg.selectAll(&quot;.node&quot;)
			.data(force.nodes())
			.enter().append(&quot;g&quot;)
			.attr(&quot;class&quot;, &quot;node&quot;);

		node.append(&quot;circle&quot;)
			.attr(&quot;r&quot;, 20);  // 원의 반지름

		// 노드에 번호 표시
		node.append(&quot;text&quot;)
			.attr(&quot;dx&quot;, -4)
			.attr(&quot;dy&quot;, &quot;.35em&quot;)
			.style(&quot;fill&quot;, &quot;black&quot;)  // 글자 색을 검정색으로 설정
			.text(function (d) { return d.id; });

		// 애니메이션을 위한 tick 함수
		function tick() {
			link.attr(&quot;x1&quot;, function (d) { return d.source.x; })
				.attr(&quot;y1&quot;, function (d) { return d.source.y; })
				.attr(&quot;x2&quot;, function (d) { return d.target.x; })
				.attr(&quot;y2&quot;, function (d) { return d.target.y; });

			node.attr(&quot;transform&quot;, function (d) { return &quot;translate(&quot; + d.x + &quot;,&quot; + d.y + &quot;)&quot;; });
		}
	&amp;lt;/script&amp;gt;
	&amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;839d8862-9ca5-4d42-bca1-d8adde478044&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;codePen에서 보기: &lt;/summary&gt;&lt;figure id=&quot;96e5f15c-dd7b-4b61-b92f-5a47051b468a&quot;&gt;&lt;div class=&quot;source&quot;&gt;&lt;a href=&quot;https://codepen.io/soa6318/pen/qBgLaxP&quot;&gt;https://codepen.io/soa6318/pen/qBgLaxP&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;p class=&quot;&quot; id=&quot;64253f7f-6de9-4f47-9000-25252a240fc9&quot;&gt;
&lt;/p&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;796bfaaf-ec6e-4291-8006-aa0f16439622&quot;&gt;
&lt;/p&gt;&lt;p class=&quot;&quot; id=&quot;96468dc1-b2a5-4312-9a80-88c877cc458c&quot;&gt;출처: LeetCode &lt;strong&gt;&lt;strong&gt;#684. Redundant Connection&lt;/strong&gt;&lt;/strong&gt; 와 Edge Copilot&lt;/p&gt;&lt;p class=&quot;&quot; id=&quot;bb4f59cf-d5a2-425d-a803-3bf755f29621&quot;&gt;
&lt;/p&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Graph(그래프)</category>
      <category>Til</category>
      <category>코드 조각 모음</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/235</guid>
      <comments>https://dev-ocean.tistory.com/235#entry235comment</comments>
      <pubDate>Tue, 5 Dec 2023 15:04:50 +0900</pubDate>
    </item>
    <item>
      <title>11/14 (화) 대소문자를 모두 가지는 최장 부분 문자열 구하기 TIL</title>
      <link>https://dev-ocean.tistory.com/234</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;c3b5ebc1-4fce-49b2-9ba5-224832f1cf78&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;c88d5019-815b-4039-9443-6d040ec09d9f&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;c9eb4127-2f02-4845-89c9-ee7cb709adb9&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#1763. Longest Nice Substring&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;e1df1f74-8c74-412f-849d-768d8ca76dde&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/longest-nice-substring/description/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Longest Nice Substring - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Longest Nice Substring - A string s is nice if, for every letter of the alphabet that s contains, it appears both in uppercase and lowercase. For example, &quot;abABB&quot; is nice because 'A' and 'a' appear, and 'B' and 'b' appear. However, &quot;abA&quot; is not because 'b' appears, but 'B' does not.  Given a string s, return the longest substring of s that is nice. If there are multiple, return the substring of the earliest occurrence. If there are none, return an empty string.     Example 1:   Input: s = &quot;YazaAay&quot; Output: &quot;aAa&quot; Explanation: &quot;aAa&quot; is a nice string because 'A/a' is the only letter of the alphabet in s, and both 'A' and 'a' appear. &quot;aAa&quot; is the longest nice substring.   Example 2:   Input: s = &quot;Bb&quot; Output: &quot;Bb&quot; Explanation: &quot;Bb&quot; is a nice string because both 'B' and 'b' appear. The whole string is a substring.   Example 3:   Input: s = &quot;c&quot; Output: &quot;&quot; Explanation: There are no nice substrings.      Constraints:   * 1 &amp;lt;= s.length &amp;lt;= 100  * s consists of uppercase and lowercase English letters.&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/longest-nice-substring/description/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;327e4220-93e4-48d9-82c3-48056a966784&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;Divide and Conquer(분할 정복법)를 이해하기에 아주 좋은 다이어그램이 있어 가져와보았다: &lt;figure class=&quot;image&quot; id=&quot;6c1d0c14-da55-4c8e-a929-f4dfab3acc04&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/loH1w/btsAjsnuSQE/Aq1zsTmHLKR2XBw1XZowzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/loH1w/btsAjsnuSQE/Aq1zsTmHLKR2XBw1XZowzK/img.png&quot; style=&quot;width:1000px&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;출처: &lt;a href=&quot;https://leetcode.com/problems/longest-nice-substring/solutions/2237699/javascript-brute-force-and-divide-and-conquer-with-illustrations/&quot;&gt;https://leetcode.com/problems/longest-nice-substring/solutions/2237699/javascript-brute-force-and-divide-and-conquer-with-illustrations/&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;16791944-a2f8-4da7-bac4-1338b9b36e63&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;해답 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;513208c6-c0f1-4f71-a69e-5f91b27329aa&quot;&gt;&lt;code&gt;// Divide and Conquer 풀이: 
function longestNiceSubstring2(s: string): string {
	// 탈출 조건: s의 길이가 0 혹은 1인 경우, 대-소문자 짝이 있을 수 없으므로 (최장 부분 문자열은)빈 문자열 반환.
	if (s.length &amp;lt; 2)
		return '';

	let arr = [...s];
	let set = new Set(arr);

	for (let i = 0; i &amp;lt; arr.length; i++) {
		const c = arr[i];
		// 현재 문자 c의 대소문자 버전이 모두 현재 부분 문자열 s에 존재하면: 현재 부분 문자열 s의 다음 문자 검사를 계속한다(=s를 둘로 쪼개지 않는다).  
		if (set.has(c.toUpperCase()) &amp;amp;&amp;amp; set.has(c.toLowerCase()))
			continue;

		// 현재 문자 c의 대소문자가 현재 부분 문자열 s에 들어있지 않으면: 현재 문자 c를 기준으로 반절을 가른 부분 문자열 각각에서 최장 부분 문자열을 추출한다. s의 길이가 &amp;lt; 2에 도달할 때까지 반복하게 됨.
		const sub1: string = longestNiceSubstring2(s.substring(0, i));
		const sub2: string = longestNiceSubstring2(s.substring(i + 1));

		// 두 (최장)부분 문자열 중 길이가 더 긴 쪽을 반환한다.
		return sub1.length &amp;gt;= sub2.length ? sub1 : sub2;
	}

	return s;
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;61f68a01-2c17-40f8-b147-a530d671c7e5&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Divide and Conquer(분할 정복법)</category>
      <category>Til</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/234</guid>
      <comments>https://dev-ocean.tistory.com/234#entry234comment</comments>
      <pubDate>Tue, 14 Nov 2023 17:44:21 +0900</pubDate>
    </item>
    <item>
      <title>11/3 (금) 합이 가장 큰 부분 배열 TIL</title>
      <link>https://dev-ocean.tistory.com/233</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;a125d520-b36b-4ca2-a375-aee8708f2561&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;ebd80f68-2dd0-4120-91a0-d5a788cc8d4b&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;6aea6447-d6c7-40f1-929b-4894817d836d&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#53. Maximum Subarray&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;f89da80b-47fc-4cb3-8beb-6d5e2bc5cdf4&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/maximum-subarray/description/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Maximum Subarray - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Maximum Subarray - Given an integer array nums, find the subarray with the largest sum, and return its sum.     Example 1:   Input: nums = [-2,1,-3,4,-1,2,1,-5,4] Output: 6 Explanation: The subarray [4,-1,2,1] has the largest sum 6.   Example 2:   Input: nums = [1] Output: 1 Explanation: The subarray [1] has the largest sum 1.   Example 3:   Input: nums = [5,4,-1,7,8] Output: 23 Explanation: The subarray [5,4,-1,7,8] has the largest sum 23.      Constraints:   * 1 &amp;lt;= nums.length &amp;lt;= 105  * -104 &amp;lt;= nums[i] &amp;lt;= 104     Follow up: If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/maximum-subarray/description/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;cf731e70-9be0-4ccd-b235-86e6900948b3&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;가장 신기하고 간결하다고 생각된 풀이를 첨부한다. &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;0972d2a7-562f-450c-b668-d7ad35767d73&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;해답 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;3fb4e25b-85c9-4092-b3d5-94f174a82234&quot;&gt;&lt;code&gt;// Time complexity: O(N)
// Space complexity: O(1) 
function maxSubArray3(nums: number[]): number {
	let localSum = 0;
	let maxSum = -Infinity;

	for (const num of nums) {
		// 지금 수와 지금 수를 부분 합계에 더한 값 중 더 큰 쪽을 새로운 부분 합계로 삼는다. 
		localSum = Math.max(num, localSum + num);
		// 만약 새로운 부분 합계가 최고 합계보다 더 크면 최고 합계를 업데이트한다. 
		if (localSum &amp;gt; maxSum) {
			maxSum = localSum;
		}
	}

	return maxSum;
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;d6019e42-8310-44b4-8e46-c7474b0babaf&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/233</guid>
      <comments>https://dev-ocean.tistory.com/233#entry233comment</comments>
      <pubDate>Fri, 3 Nov 2023 20:31:55 +0900</pubDate>
    </item>
    <item>
      <title>11/2 (목) 쿼리를 포함하기 위한 최소 인터벌 TIL</title>
      <link>https://dev-ocean.tistory.com/232</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;aef157c0-a214-4102-8ae9-bdbe5c194637&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;8dff743c-2967-460b-bd3a-bb0dd7ebfa19&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;dc8eda8d-d372-451e-87d2-783aaa72f9e0&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#1851. Minimum Interval to Include Each Query&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;aabf13bb-ca4d-490b-a478-b88d26965cb7&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/minimum-interval-to-include-each-query/description/?source=submission-noac&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Minimum Interval to Include Each Query - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Minimum Interval to Include Each Query - You are given a 2D integer array intervals, where intervals[i] = [lefti, righti] describes the ith interval starting at lefti and ending at righti (inclusive). The size of an interval is defined as the number of integers it contains, or more formally righti - lefti + 1.  You are also given an integer array queries. The answer to the jth query is the size of the smallest interval i such that lefti &amp;lt;= queries[j] &amp;lt;= righti. If no such interval exists, the answer is -1.  Return an array containing the answers to the queries.     Example 1:   Input: intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5] Output: [3,3,1,4] Explanation: The queries are processed as follows: - Query = 2: The interval [2,4] is the smallest interval containing 2. The answer is 4 - 2 + 1 = 3. - Query = 3: The interval [2,4] is the smallest interval containing 3. The answer is 4 - 2 + 1 = 3. - Query = 4: The interval [4,4] is the smallest interval containing 4. The answer is 4 - 4 + 1 = 1. - Query = 5: The interval [3,6] is the smallest interval containing 5. The answer is 6 - 3 + 1 = 4.   Example 2:   Input: intervals = [[2,3],[2,5],[1,8],[20,25]], queries = [2,19,5,22] Output: [2,-1,4,6] Explanation: The queries are processed as follows: - Query = 2: The interval [2,3] is the smallest interval containing 2. The answer is 3 - 2 + 1 = 2. - Query = 19: None of the intervals contain 19. The answer is -1. - Query = 5: The interval [2,5] is the smallest interval containing 5. The answer is 5 - 2 + 1 = 4. - Query = 22: The interval [20,25] is the smallest interval containing 22. The answer is 25 - 20 + 1 = 6.      Constraints:   * 1 &amp;lt;= intervals.length &amp;lt;= 105  * 1 &amp;lt;= queries.length &amp;lt;= 105  * intervals[i].length == 2  * 1 &amp;lt;= lefti &amp;lt;= righti &amp;lt;= 107  * 1 &amp;lt;= queries[j] &amp;lt;= 107&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/minimum-interval-to-include-each-query/description/?source=submission-noac&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;22668727-ab61-47e8-a345-795533d77dd9&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;최소 힙을 사용하니 걸리는 시간이 대폭 줄어들었다. ‘최소값’이라는 키워드가 나왔을 때 최소 힙을 떠올렸어야 했는데.  &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;31e480f7-3a51-47db-8f91-2ec8fdcaf297&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;해답 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;2dcd7c32-723f-40ba-a24f-7111a076ee00&quot;&gt;&lt;code&gt;function minInterval3(intervals: number[][], queries: number[]): number[] {
	const sortedQueries = queries.map((q, i) =&amp;gt; [q, i]).sort((a, b) =&amp;gt; a[0] - b[0]);
	intervals.sort((a, b) =&amp;gt; a[0] - b[0]);

	const heap = new MinHeap();
	const result = new Array(queries.length);

	let i = 0; 

	for (const [query, index] of sortedQueries) {
		while (i &amp;lt; intervals.length &amp;amp;&amp;amp; intervals[i][0] &amp;lt;= query) {
			const [start, end] = intervals[i];
			heap.insert([end - start + 1, end]);
			i++;
		}

		while (heap.size &amp;amp;&amp;amp; query &amp;gt; heap.min[1]) {
			heap.remove();
		}

		result[index] = heap.size ? heap.min[0] : -1;
	}
	
	return result;
}


class MinHeap {
	private heap: [number, number][] = [];

	get min() {
		return this.heap[0];
	}

	get size() {
		return this.heap.length;
	}

	insert(val: [number, number]) {
		this.heap.push(val);
		this.bubbleUp(this.size - 1);
	}

	remove() {
		if (!this.size) return;

		this.swap(0, this.size - 1);
		const min = this.heap.pop();
		this.bubbleDown(0);
		return min;
	}

	// 현재 index 자리의 노드를 min heap 규칙에 맞도록 끌어올린다.
	private bubbleUp(index: number) {
		// 지금 자리가 루트(root)에 도달하거나, 부모의 size값 이상이 될 때까지 반복 
		while (index &amp;gt; 0) {
			const parentIndex = Math.floor((index - 1) / 2);

			// 지금 자리의 size값이 부모 자리의 size값보다 작을 때만 자리 교체
			if (this.heap[index][0] &amp;lt; this.heap[parentIndex][0]) {
				this.swap(index, parentIndex);
				index = parentIndex;
			} else {
				break;
			}
		}
	}

	// 현재 index 자리의 노드를 min heap 규칙에 맞도록 끌어내린다.
	private bubbleDown(index: number) {
		// 지금 자리가 힙의 끝에 도달하거나, 두 자식의 size값 미만이 될 때까지 반복
		while (index &amp;lt; this.size) {
			const leftChildIndex = index * 2 + 1;
			const rightChildIndex = index * 2 + 2;
			let smallest = index;

			if (leftChildIndex &amp;lt; this.size &amp;amp;&amp;amp; this.heap[leftChildIndex][0] &amp;lt; this.heap[smallest][0])
				smallest = leftChildIndex;
			
			if (rightChildIndex &amp;lt; this.size &amp;amp;&amp;amp; this.heap[rightChildIndex][0] &amp;lt; this.heap[smallest][0])
				smallest = rightChildIndex;

			if (index === smallest) break;

			this.swap(index, smallest);
			index = smallest;
		}
	}

	private swap(i: number, j: number) {
		[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
	}
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;69176552-e03f-4614-aa21-7a785b27cbd9&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <category>최소 힙(Min Heap)</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/232</guid>
      <comments>https://dev-ocean.tistory.com/232#entry232comment</comments>
      <pubDate>Thu, 2 Nov 2023 17:49:06 +0900</pubDate>
    </item>
    <item>
      <title>10/28 (토) (완료)인터벌이 안 겹치도록 삭제해야 하는 최소 인터벌 개수 TIL</title>
      <link>https://dev-ocean.tistory.com/231</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;a50601da-3721-4dd1-b904-07fbdb4e2206&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;ba088091-8883-4cc2-bc73-0d6eeeb99a7a&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;c0c00edd-3dc3-43db-a362-9b0499422c37&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#435. Non-overlapping Intervals&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;fc44041e-ffd1-4ca3-b011-7bc564f4e51d&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/non-overlapping-intervals/description/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Non-overlapping Intervals - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Non-overlapping Intervals - Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.     Example 1:   Input: intervals = [[1,2],[2,3],[3,4],[1,3]] Output: 1 Explanation: [1,3] can be removed and the rest of the intervals are non-overlapping.   Example 2:   Input: intervals = [[1,2],[1,2],[1,2]] Output: 2 Explanation: You need to remove two [1,2] to make the rest of the intervals non-overlapping.   Example 3:   Input: intervals = [[1,2],[2,3]] Output: 0 Explanation: You don't need to remove any of the intervals since they're already non-overlapping.      Constraints:   * 1 &amp;lt;= intervals.length &amp;lt;= 105  * intervals[i].length == 2  * -5 * 104 &amp;lt;= starti &amp;lt; endi &amp;lt;= 5 * 104&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/non-overlapping-intervals/description/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;a3abe412-d15a-423a-98a9-e0c352a73ea6&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 2(포기): 시작점 기준으로 오름차순 정렬한 후에, 인접한 두 인터벌이 겹치면 둘 중 길이가 더 긴 쪽을 삭제하는 식으로 전체 인터벌을 순회하는 방법. 두 인터벌이 겹치는데 두 길이가 같으면 둘 중 더 뒤쪽에 있는 인터벌을 삭제한다. ⇒ 다음 경우와 같이 이미 삭제하고 지나친 인터벌이 나중에 필요해지는 경우가 생긴다. &lt;figure class=&quot;image&quot; id=&quot;4f09d300-0939-46c3-9f3e-2944999ee6f3&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/uOnc3/btszj7dI0aj/4o8FftozhdwT4XwQUhn5t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uOnc3/btszj7dI0aj/4o8FftozhdwT4XwQUhn5t1/img.png&quot; style=&quot;width:1360px&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;c173590b-15dc-4dca-978e-b7fa14e72677&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 3(성공): 끝점 기준으로 오름차순 정렬하고 첫 인터벌을 선택한 후, 그 다음부터 '이전 인터벌의 끝'과 겹치지 않는 가장 가까운 인터벌을 찾아 선택하기를 반복한다. 마지막에는 총 인터벌 개수에서 선택한 인터벌 수를 뺀 값을 반환하면 된다.&lt;ul class=&quot;toggle&quot; id=&quot;c3832654-6705-4ea0-b9b9-aae32b5a5fb5&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;방법 3 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;acc5bcf1-9d86-4cc3-8c8a-dbbbec994256&quot;&gt;&lt;code&gt;// Time Complexity: O(n log n)
// Space Complexity: O(log n) 
function eraseOverlapIntervals(intervals: number[][]): number {
	if (intervals.length === 1) return 0;

	intervals.sort((a, b) =&amp;gt; a[1] - b[1]);
	let end = intervals[0][1]; // 정렬 후 첫 인터벌은 선택하고 시작
	let count = 1; // result[]에 넣는 대신 숫자로 셈(=제거하지 않는 인터벌의 수 = '선택'한 인터벌의 수)

	for (let i = 1; i &amp;lt; intervals.length; i++) {
		const currentStart = intervals[i][0];

		// 현재 인터벌이 이전 인터벌과 겹치지 안으면 현재 인터벌을 (제거하지 않는 것으로) '선택'한다. 
		if (currentStart &amp;gt;= end) {
			// '선택': count를 1 늘이고 end를 업데이트함
			count++;
			end = intervals[i][1]; 
		}
	}

	// 전체 인터벌에서 제거하지 않는 총 인터벌 수를 빼 반환한다. 
	return intervals.length - count;
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;739e7d33-6003-4b28-ab15-750ded62447a&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/231</guid>
      <comments>https://dev-ocean.tistory.com/231#entry231comment</comments>
      <pubDate>Sat, 28 Oct 2023 10:48:27 +0900</pubDate>
    </item>
    <item>
      <title>10/27 (금) 인터벌이 안 겹치도록 삭제해야 하는 최소 인터벌 개수 TIL</title>
      <link>https://dev-ocean.tistory.com/230</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;c2918db1-a399-4c57-a0cb-aa950b36030c&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;70f06a1d-96dc-4f8d-856c-08e0c518b6a8&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;2c79f11c-046c-4fa3-a63c-37787109d3cb&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#435. Non-overlapping Intervals&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;2bf517cd-49fa-4d02-add9-e6106ecfbe9b&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/non-overlapping-intervals/description/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Non-overlapping Intervals - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Non-overlapping Intervals - Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.     Example 1:   Input: intervals = [[1,2],[2,3],[3,4],[1,3]] Output: 1 Explanation: [1,3] can be removed and the rest of the intervals are non-overlapping.   Example 2:   Input: intervals = [[1,2],[1,2],[1,2]] Output: 2 Explanation: You need to remove two [1,2] to make the rest of the intervals non-overlapping.   Example 3:   Input: intervals = [[1,2],[2,3]] Output: 0 Explanation: You don't need to remove any of the intervals since they're already non-overlapping.      Constraints:   * 1 &amp;lt;= intervals.length &amp;lt;= 105  * intervals[i].length == 2  * -5 * 104 &amp;lt;= starti &amp;lt; endi &amp;lt;= 5 * 104&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/non-overlapping-intervals/description/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;9f9725a3-4dd6-4576-be60-c3b898c204c9&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 1(포기): 인터벌이 어떤 인터벌과 겹치는지 인터벌 각각에 대하여 ‘겹침 목록’을 만든다. 예를 들어 인덱스 0번 인터벌이 1번, 2번, 10번 인덱스의 인터벌과 겹친다면 0과 set(1, 2, 10)을 묶어두는 자료구조를 사용한다. 그 후 가장 겹침이 많은 인터벌을 삭제하고, 연관된 다른 인터벌들에서도 이 인덱스 번호를 전부 삭제한다. 그 다음으로 겹침 수가 많은 인터벌을 삭제하고 연관된 목록에서도 이 인덱스를 삭제하기를 반복해서, 모든 인터벌의 겹침 수가 0이 되면 반복을 중지한다. 남은 인터벌의 개수를 전체 개수에서 뺀 수가 제거한 인터벌의 수가 되며, 이 것을 반환한다. &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;06f79a16-7717-4bd0-a561-f55ba76f24e2&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 2(진행중): 시작점 기준으로 오름차순 정렬한 후에, 인접한 두 인터벌이 겹치면 둘 중 길이가 더 긴 쪽을 삭제하는 식으로 전체 인터벌을 순회하는 방법. 두 인터벌이 겹치는데 두 길이가 같으면 둘 중 더 뒤쪽에 있는 인터벌을 삭제한다. ⇒ 규칙에 뭔가 허점이 있지 않을까 했는데 아니나 다를까 에러 케이스에 걸려 파악 중이다.&lt;ul class=&quot;toggle&quot; id=&quot;689076c6-4c1e-4db4-9548-296b4373bb55&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;코드&lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;734988c1-6862-4813-92a5-4f339c553c8c&quot;&gt;&lt;code&gt;function eraseOverlapIntervals(intervals: number[][]): number {
	// 0. 인터벌이 하나 뿐이면 삭제할 것 없음. 0을 조기 리턴.
	if (intervals.length === 1) return 0;

	// 1. 정렬
	intervals.sort((a, b) =&amp;gt; a[0] - b[0]);

	// 2. 순회
	const result = [intervals[0]];
	for (let i = 1; i &amp;lt; intervals.length; i++) {
		let pre = result[result.length - 1];
		let post = intervals[i];

		if (pre[1] &amp;gt; post[0]) { // 두 인터벌이 겹침
			// pre가 변경되어야 하는 경우: pre 간격이 더 길 때
			// (post가 '빠져야' 하는 경우라면 그냥 result에 안 넣으면 되므로 아무 조치 x)
			if (pre[1] - pre[0] &amp;gt; post[1] - post[0]) {
				// pre를 삭제하고 post를 넣는다. 
				result.pop();
				result.push(post);
			}	
		}
		else { // 두 인터벌이 겹치지 않음
			// 지금 post 넣기
			result.push(post);
		}
	}

	// 3. 반환
	return intervals.length - result.length;
};&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;716fccfa-a5b1-4a1b-bb9a-e18539af1f80&quot;&gt;
&lt;/p&gt;&lt;p class=&quot;&quot; id=&quot;26507a64-4d1e-4c19-9992-b0905bc6758f&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/230</guid>
      <comments>https://dev-ocean.tistory.com/230#entry230comment</comments>
      <pubDate>Fri, 27 Oct 2023 19:26:27 +0900</pubDate>
    </item>
    <item>
      <title>10/26 (목) 겹치는 인터벌 합치기 TIL</title>
      <link>https://dev-ocean.tistory.com/229</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;db359c8d-ab60-44e6-ac43-2905c726d08f&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;aa0ee3f3-061e-4f20-b300-0890e62e13e4&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;047d1c65-49c3-4f81-aa84-112a8147330f&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#56. Merge Interval&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;4fe4ea7e-9cb6-4bbe-9fda-ab152313f456&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/merge-intervals/submissions/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;LeetCode - The World's Leading Online Programming Learning Platform&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/merge-intervals/submissions/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;1b7c62dc-8fdd-4afa-974f-85bf9fd5d82b&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;어제는 이미 정렬된 인터벌들에 새 인터벌을 하나 끼우는 방식으로, 전체를 한 번만 순회하기 때문에 시간 복잡도는 &lt;code&gt;&lt;style&gt;@import url('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.13.2/katex.min.css')&lt;/style&gt;&lt;span class=&quot;notion-text-equation-token&quot; contenteditable=&quot;false&quot; data-token-index=&quot;0&quot; style=&quot;user-select:all;-webkit-user-select:all;-moz-user-select:all&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(n)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02778em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&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;/code&gt;이면 되었다.  &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;bda6453d-9889-4a9d-a44b-6fb616a4cdd5&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;오늘은 정렬되지 않은 전체 인터벌을 겹치는 것끼리 병합하는 문제로, 먼저 정렬 후 전체를 한 번 순회해야 하기 때문에 시간 복잡도가 &lt;code&gt;&lt;style&gt;@import url('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.13.2/katex.min.css')&lt;/style&gt;&lt;span class=&quot;notion-text-equation-token&quot; contenteditable=&quot;false&quot; data-token-index=&quot;0&quot; style=&quot;user-select:all;-webkit-user-select:all;-moz-user-select:all&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(n log n)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;katex-html&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02778em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.01968em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&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;/code&gt;이다. &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;9fe4784c-20c0-408d-acbe-4b0d1bdc2783&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;방법 1: 반환할 인터벌들을 새 배열 result에 넣는 방법 &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;7a0536b0-3032-4b96-b341-bc52b131cda9&quot;&gt;&lt;code&gt;// Time Complexity: O(n log n)
// Space Complexity: O(n) 
function merge1(intervals: number[][]): number[][] {
	if (intervals.length === 1) return intervals;
	
	// 1. start 기준으로 오름차순 정렬하기: O(N logN)
	intervals.sort((a, b) =&amp;gt; a[0] - b[0]);
	const result = [intervals[0]];

	// 2. 어느 두 연이은 인터벌 중 앞의 end가 뒤의 start보다 크거나 같으면 병합한다: O(N)
	for (let i = 1; i &amp;lt; intervals.length; i++) {
		const pre = result[result.length - 1];
		const post = intervals[i];
		if (pre[1] &amp;gt;= post[0]) { // 병합하기
			pre[1] = Math.max(pre[1], post[1]);
		} else { // 새 인터벌 등장. result에 넣기
			result.push(post);
		}
	}

	return result;
};&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;618813c2-ae6d-4072-9ebd-d0b830810efb&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;방법 2: result 배열을 사용하지 않는 방법&lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;ac0589d0-30a9-4433-b2d7-7d7fbf58b2b7&quot;&gt;&lt;code&gt;// 새 result 배열 없이 해보기:
// Time Complexity: O(n log n)
// Space Complexity: O(log n) (in-place sorting을 하므로)
function merge(intervals: number[][]): number[][] {
	if (intervals.length === 1) return intervals;	
	
	// 1. start 기준으로 오름차순 정렬하기: O(N logN)
	intervals.sort((a, b) =&amp;gt; a[0] - b[0]);

	// 2. 어느 두 연이은 인터벌 중 앞의 end가 뒤의 start보다 크거나 같으면 병합한다: O(N)
	let pre = intervals[0];
	for (let i = 1; i &amp;lt; intervals.length; i++) {
		const post = intervals[i];
		if (pre[1] &amp;gt;= post[0]) { // 병합하기
			pre[1] = Math.max(pre[1], post[1]);
			delete intervals[i]; // delete post;는 안 됨 주의
		} else { // 새 인터벌 등장. pre를 새 인터벌로 옮긴다.
			pre = post;			
		}
	}

	return intervals.filter(x =&amp;gt; true);
};&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;519b4072-f53a-44c2-9636-1277a45cdd9b&quot;&gt;
&lt;/p&gt;&lt;p class=&quot;&quot; id=&quot;2d23eeaf-7b96-4794-877a-0aed0251ae78&quot;&gt;결과: 방법 1과 방법 2에서 유의미한 메모리 차이는 발생하지 않음. &lt;/p&gt;&lt;p class=&quot;&quot; id=&quot;81415aef-f4bb-4f87-8008-7ee9383e3bd7&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/229</guid>
      <comments>https://dev-ocean.tistory.com/229#entry229comment</comments>
      <pubDate>Thu, 26 Oct 2023 14:22:21 +0900</pubDate>
    </item>
    <item>
      <title>10/25 (수) (완료)인터벌 끼워넣기 TIL</title>
      <link>https://dev-ocean.tistory.com/228</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;68349646-173b-40ff-a5ae-fc1e63f3bef7&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;7a58b805-6af8-4469-8c77-1756a9bad682&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;b370bdd2-f712-4ad2-b1d0-39ccd5f5fa93&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#57. Insert Interval&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;3bc20a21-8693-4475-a0ea-663deedc87b6&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/insert-interval/description/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Insert Interval - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Insert Interval - You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval.  Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if necessary).  Return intervals after the insertion.     Example 1:   Input: intervals = [[1,3],[6,9]], newInterval = [2,5] Output: [[1,5],[6,9]]   Example 2:   Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] Output: [[1,2],[3,10],[12,16]] Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].      Constraints:   * 0 &amp;lt;= intervals.length &amp;lt;= 104  * intervals[i].length == 2  * 0 &amp;lt;= starti &amp;lt;= endi &amp;lt;= 105  * intervals is sorted by starti in ascending order.  * newInterval.length == 2  * 0 &amp;lt;= start &amp;lt;= end &amp;lt;= 105&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/insert-interval/description/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;fe27e67f-8806-4222-8884-6c7a2fa5454f&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 2(통과): 반환할 새 배열을 만들고, 통합된 새 시작점과 새 끝점을 구하여 이 사이의 점
들을 제외한 나머지 점들을 옮겨담아 반환하는 방식. 방법 1보다 확실히 빨라졌다. 다만 메모리 사용이 조금 많음. &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;ea793937-56a4-4cf7-92a8-4a06577c5bad&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법3(통과): 시간, 공간, 가독성 모두 좋은데 가독성이 가장 발군인 풀이법. 방법1이나 방법2와 아이디어가 같은데 &lt;code&gt;math.Max()&lt;/code&gt;와 &lt;code&gt;math.Min()&lt;/code&gt;을 활용해 새 인터벌의 시점과 끝점을 점점 양옆으로 확장해나가는 방식을 사용한 것이 눈에 띈다.&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;32aa0eb2-8fb6-40e2-87cc-e5d14f3061c0&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;방법 2 풀이 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;e20f5c48-eae1-4d70-8d30-84cf364427fb&quot;&gt;&lt;code&gt;/* 대략적인 아이디어: 
	 새롭게 배열을 만든다. 통합된 시작점 전의 점까지를 넣고, 통합된 시작점을 넣고, 이후 점들은 건너뜀. 이후 통합된 끝점와 그 이후의 점들을 넣고서 두 짝씩 묶는다. 틀림없이 두 짝이 맞게 되며, 반환한다. 
*/ 
function insert2(intervals: number[][], newInterval: number[]): number[][] {
	// 0. 
	if (!intervals.length) return [newInterval];

	// 편하게 하기 위해 intervals를 평면화시킴([[1,3],[6,9]] =&amp;gt; [1,3,6,9])
	const dots = intervals.flatMap((interval) =&amp;gt; interval);

	const result = [];
	const [newStart, newEnd] = newInterval;
	let newStartFound = false, newEndFound = false;
	let i = 0; 
	
	// newStart이 나타나는 지점 찾기
	for (; i &amp;lt; dots.length; i++) {
		if (dots[i] &amp;gt;= newStart) {
			if (dots[i] !== newStart &amp;amp;&amp;amp; i % 2 === 0) { // 간격 '외'임
				result.push(newStart);
			} else { // 간격 '내'임. 
				if (dots[i] === newStart &amp;amp;&amp;amp; i % 2 === 0) { // 지금 i를 '시작점'으로 삼고 이후 나타나는 점들을 건너뛴다. 
					// = i번째 점은 넣어줌.
					result.push(dots[i]);
				} else { // i 이전 점을 '시작점'으로 삼는다
					// = i부터 건너뜀	
				}
			}
			newStartFound = true;
			break;
		}
		// newStart이 나타나기 전까지는 점들을 다 넣어준다. 
		else {
			result.push(dots[i]);
		}
	}

	// newEnd가 나타나는 지점 찾기
	for (; i &amp;lt; dots.length; i++) {
		if (dots[i] &amp;gt;= newEnd) {
			if (dots[i] !== newEnd &amp;amp;&amp;amp; i % 2 === 0) { // 간격 '외'임
				result.push(newEnd);
			} else {
				if (dots[i] === newEnd &amp;amp;&amp;amp; i % 2 === 0) { // i 다음 점을 '끝점'으로 삼는다 = i까지 건너뛴다
					i++;
				} else { // i를 '끝점'으로 삼는다 = 점 i는 추가한다.
					// result.push(dots[i]);
				}
			}
			newEndFound = true;
			break;
			// FIXME: break하기 전에 점이 겹치지 않았으면 i--를 해줘야 함.
			// 		=&amp;gt; i++를 넣어주고, result.push(dots[i])를 주석 처리해준 후, 루프 바깥에서 result.push(...dots.slice(i+1))을 slice(i)로 바꿔줌으로써 달성함. 
		}
		// newEnd가 나타나기 전까지는 점들을 다 건너뛴다.
	}

	// newEnd 이후 점들을 다 넣어주기
	result.push(...dots.slice(i));
	
	// dots의 끝점에 도달할때까지 newStart이나 newEnd를 찾을 수 없는 경우
	if (!newStartFound)
		// 제일 마지막에 newIntervals의 두 점을 넣어준다
		result.push(newStart, newEnd);
	else if (!newEndFound)
		// 끝점 newEnd만 추가해준다. 
		result.push(newEnd);
	
	// 최종 점들을 두 짝씩 묶어서 반환하기
	const newIntervals = []
	for (let i = 0; i &amp;lt; result.length; i += 2) {
		newIntervals.push([result[i], result[i + 1]]);
	}
	return newIntervals;
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;19c84874-86e0-4f59-b48f-bf3eaa876541&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;방법 3 풀이 코드:&lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;b7263772-8fd5-43fb-90a0-998c3896de9d&quot;&gt;&lt;code&gt;// 전과 같은 아이디어이나 가독성이 좋은: 
function insert4(intervals: number[][], newInterval: number[]): number[][] {
	const newIntervals = [];
	const m = intervals.length;
	let i = 0;

	while (i &amp;lt; m &amp;amp;&amp;amp; intervals[i][1] &amp;lt; newInterval[0]) {
		newIntervals.push(intervals[i]);
		i++;
	}
	
	while (i &amp;lt; m &amp;amp;&amp;amp; intervals[i][0] &amp;lt;= newInterval[1]) {
		newInterval[0] = Math.min(intervals[i][0], newInterval[0]);
		newInterval[1] = Math.max(intervals[i][1], newInterval[1]);
		i++;
	}

	newIntervals.push(newInterval);

	while (i &amp;lt; m) {
		newIntervals.push(intervals[i]);
		i++;
	}

	return newIntervals;
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;19a47ba7-e5ba-4313-9445-6f6dca0b8dd2&quot;&gt;
&lt;/p&gt;&lt;p class=&quot;&quot; id=&quot;4c014ca1-a148-4a6a-a301-a9ee97fc7f69&quot;&gt;결과: &lt;/p&gt;&lt;figure class=&quot;image&quot; id=&quot;c7077448-75b1-42a0-90c5-3721d344a265&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/mqcja/btsy9RPKx3j/4oLvO69FlGKnn8JQZymIKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mqcja/btsy9RPKx3j/4oLvO69FlGKnn8JQZymIKK/img.png&quot; style=&quot;width:848px&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p class=&quot;&quot; id=&quot;27e7d5ec-c7e2-4a5d-9140-ee9bde956131&quot;&gt;풀이 1과 비교: &lt;/p&gt;&lt;figure class=&quot;image&quot; id=&quot;cb7601b6-9230-4d0f-9f07-e78c64c14db5&quot; style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/I8ieT/btszdoep04X/8fjnzW4AmymBi1FhPBLNPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I8ieT/btszdoep04X/8fjnzW4AmymBi1FhPBLNPK/img.png&quot; style=&quot;width:576px&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p class=&quot;&quot; id=&quot;45af5f27-71a2-40c2-9e9d-c18c5c98ee63&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/228</guid>
      <comments>https://dev-ocean.tistory.com/228#entry228comment</comments>
      <pubDate>Wed, 25 Oct 2023 22:04:31 +0900</pubDate>
    </item>
    <item>
      <title>10/24 (화) 인터벌 끼워넣기 TIL</title>
      <link>https://dev-ocean.tistory.com/227</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;10e29dc6-2bbb-46bc-b22f-6bd070bd58cc&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;063df69e-6788-4e97-97fc-41085be8b388&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;d7f00338-b753-479d-8c39-edb782568865&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#57. Insert Interval&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;b0d7e38f-8d9a-4065-8fb1-2c0b291a2a8d&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/insert-interval/description/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Insert Interval - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Insert Interval - You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval.  Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if necessary).  Return intervals after the insertion.     Example 1:   Input: intervals = [[1,3],[6,9]], newInterval = [2,5] Output: [[1,5],[6,9]]   Example 2:   Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] Output: [[1,2],[3,10],[12,16]] Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].      Constraints:   * 0 &amp;lt;= intervals.length &amp;lt;= 104  * intervals[i].length == 2  * 0 &amp;lt;= starti &amp;lt;= endi &amp;lt;= 105  * intervals is sorted by starti in ascending order.  * newInterval.length == 2  * 0 &amp;lt;= start &amp;lt;= end &amp;lt;= 105&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/insert-interval/description/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;409fe112-76cc-4fe7-87e0-3cafe51890f8&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 1: 생각의 흐름대로 로직을 구성하여 답을 내놓음 ⇒ intervals 목록을 필요할 때마다 반복해서 순회하기 때문에 테스트에 통과는 하지만 시간 효율이 좋지 못함. 리팩토링 필요. &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;2395e9d7-e0c7-40f1-903d-92fdc915d97b&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;방법 1 풀이 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;2a2fed3e-07f2-46b9-882a-b818160fc764&quot;&gt;&lt;code&gt;/* 대략적인 아이디어: 
	^ 1. 새로 들어오는 인터벌의 시작과 끝을 재정립하기
				1) 새 인터벌의 시점: 
					만약 기존의 인터벌의 간격 이내라면(시작과 끝 포함), 그 인터벌의 시작지점으로 새 인터벌의 시작을 옮긴다. 새 인터벌의 시점이 어떤 인터벌에도 속하지 않는다면 그대로 둔다. 
				2) 새 인터벌의 종점: 
					만약 어떤 인터벌의 중간 지점이거나 시작지점과 만난다면 그 인터벌의 끝을 새로운 종점으로 설정한다. 만약 어떤 인터벌의 끝과 만나거나 어떤 인터벌과도 접하지 않는다면, 그대로 둔다. 
	^ 2. 수정한 '새 인터벌'의 시점과 종점을 기존 목록과 비교하기
				1) 기존 목록의 종점이 새 것의 종점보다 작은 동안 루프를 돈다:
					시점이 새 것의 시점과 같거나 큰 경우 그 인터벌을 삭제 대상으로 포함.
	^ 3. 찾은 '삭제 대상' 지우기 및 수정한 '새 인터벌' 삽입
				어떻게 하면 더 효과적으로 처리할 수 있을까
*/
function insert2(intervals: number[][], newInterval: number[]): number[][] {
	if (intervals.length === 0) return [newInterval];
	
	// 1-1. 새 인터벌의 시점 수정하기
	let [newStart, newEnd] = newInterval;
	let i = 0;
	for (; i &amp;lt; intervals.length; i++) {
		let [start, end] = intervals[i];
		if (newStart &amp;gt;= start &amp;amp;&amp;amp; newStart &amp;lt;= end) {
			// 기존 인터벌의 간격 이내일 때, 시점 수정
			newStart = start;
			break;
		}
	}
	// 1-2. 새 인터벌의 종점 수정하기
	for (; i &amp;lt; intervals.length; i++) { // 새 인터벌이 '시작'한 부분부터 검사 시작
		let [start, end] = intervals[i];
		if (newEnd &amp;gt;= start &amp;amp;&amp;amp; newEnd &amp;lt;= end) {
		// 기존 인터벌의 시점과 같거나 간격 내일 때(종점 미포함)(종점 포함해도 상관없음)
			newEnd = end;
			break;
		}
	}
	// 1-3. 새 인터벌의 시작점은 기존 인터벌에 포함되지 않지만 종점은 포함되어 있을 때: 새 인터벌의 시점은 그대로 두고 종점만 그 지점으로 옮긴다
	for (let i = 0; i &amp;lt; intervals.length; i++) {
		let [start, end] = intervals[i];
		if (newEnd &amp;gt;= start &amp;amp;&amp;amp; newEnd &amp;lt;= end) {
			newEnd = end;
			break;
		}
	}
	// 2. 수정한 '새 인터벌'의 시점과 종점을 기존 목록과 비교하기
	let j = 0; 
	let [start, end] = intervals[j];
	let hasReplaced = false;

	// 기존 인터벌의 종점이 새것과 같은 것을 발견할 때까지
	while (end &amp;lt;= newEnd &amp;amp;&amp;amp; j &amp;lt; intervals.length) {
		if (start &amp;gt;= newStart) {
			// 처음 '삭제 대상'을 발견한 자리에 수정한 '새 인터벌'을 덮어씌운다.
			if (!hasReplaced) {
				intervals[j] = [newStart, newEnd];
				hasReplaced = true;
			} 
			// 이후 발견하는 '삭제 대상'들은 그냥 삭제한다.
			else 
				delete intervals[j];
			// 이후 .filter(x=&amp;gt;true)로 반환
		}
		[start, end] = intervals[++j] ?? [null, null];
	}

	intervals = intervals.filter(x =&amp;gt; true)

	// 3. '대체할' 기존 인터벌을 찾지 못했어도 넣어야 한다.
	if (!hasReplaced) {
		for (let j = 0; j &amp;lt; intervals.length; j++) {
			if (newStart &amp;lt; intervals[j][0]) {
				intervals = [...intervals.slice(0, j), [newStart, newEnd], ...intervals.slice(j)];
				hasReplaced = true;
				break;
			}
		}
	}
	if (!hasReplaced)
		intervals.push([newStart, newEnd]);

	return intervals;
};&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;0ad34125-d7f5-449b-ab1a-66e69c5d63ee&quot;&gt;
&lt;/p&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/227</guid>
      <comments>https://dev-ocean.tistory.com/227#entry227comment</comments>
      <pubDate>Tue, 24 Oct 2023 21:02:34 +0900</pubDate>
    </item>
    <item>
      <title>10/23 (월) (완료)스트림에서 중위값 찾기 TIL</title>
      <link>https://dev-ocean.tistory.com/226</link>
      <description>&lt;body&gt;&lt;html&gt;&lt;head&gt;&lt;link href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/stackoverflow-dark.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;&lt;/head&gt;&lt;/html&gt;&lt;link href=&quot;https://rawcdn.githack.com/ppuep94/n2t/5ef4dc01e9d6336341e9ab95bb71672f9d3a3dc9/assets/css/style2.css&quot; rel=&quot;stylesheet&quot;/&gt;&lt;article class=&quot;page sans Notion&quot; id=&quot;e1cc0411-e1ee-46b7-961e-8539f5aae738&quot;&gt;&lt;header&gt;&lt;p class=&quot;page-description&quot;&gt;&lt;/p&gt;&lt;/header&gt;&lt;div class=&quot;page-body Tistory&quot;&gt;&lt;h3 class=&quot;&quot; id=&quot;b5930ee3-34a1-4190-87d5-2095ba820ed7&quot;&gt;공부한 것&lt;/h3&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;a8f88f2a-5b5c-4c23-8eba-0776b4cfe7a5&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LeetCode &lt;strong&gt;&lt;strong&gt;#295. Find Median from Data Stream&lt;/strong&gt;&lt;/strong&gt;&lt;figure id=&quot;78ae864d-02e0-4b1f-9e9a-463f6af6675b&quot;&gt;&lt;a class=&quot;bookmark source&quot; href=&quot;https://leetcode.com/problems/find-median-from-data-stream/&quot;&gt;&lt;div class=&quot;bookmark-info&quot;&gt;&lt;div class=&quot;bookmark-text&quot;&gt;&lt;div class=&quot;bookmark-title&quot;&gt;Find Median from Data Stream - LeetCode&lt;/div&gt;&lt;div class=&quot;bookmark-description&quot;&gt;Can you solve this real interview question? Find Median from Data Stream - The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value, and the median is the mean of the two middle values.   * For example, for arr = [2,3,4], the median is 3.  * For example, for arr = [2,3], the median is (2 + 3) / 2 = 2.5.  Implement the MedianFinder class:   * MedianFinder() initializes the MedianFinder object.  * void addNum(int num) adds the integer num from the data stream to the data structure.  * double findMedian() returns the median of all elements so far. Answers within 10-5 of the actual answer will be accepted.     Example 1:   Input [&quot;MedianFinder&quot;, &quot;addNum&quot;, &quot;addNum&quot;, &quot;findMedian&quot;, &quot;addNum&quot;, &quot;findMedian&quot;] [[], [1], [2], [], [3], []] Output [null, null, null, 1.5, null, 2.0]  Explanation MedianFinder medianFinder = new MedianFinder(); medianFinder.addNum(1);    // arr = [1] medianFinder.addNum(2);    // arr = [1, 2] medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2) medianFinder.addNum(3);    // arr[1, 2, 3] medianFinder.findMedian(); // return 2.0      Constraints:   * -105 &amp;lt;= num &amp;lt;= 105  * There will be at least one element in the data structure before calling findMedian.  * At most 5 * 104 calls will be made to addNum and findMedian.     Follow up:   * If all integer numbers from the stream are in the range [0, 100], how would you optimize your solution?  * If 99% of all integer numbers from the stream are in the range [0, 100], how would you optimize your solution?&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;bookmark-href&quot;&gt;&lt;img class=&quot;icon bookmark-icon&quot; src=&quot;https://leetcode.com/favicon.ico&quot;/&gt;https://leetcode.com/problems/find-median-from-data-stream/&lt;/div&gt;&lt;/div&gt;&lt;img class=&quot;bookmark-image&quot; src=&quot;https://leetcode.com/static/images/LeetCode_Sharing.png&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;7298fc94-49ff-48ea-8397-46c3fa699db9&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 1: 이진 트리로 스트림 데이터(숫자들)를 넣은 후 중위 순회를 반 진행하여 중위값을 반환하기 ⇒ 시간 초과로 해답이 통과하지 못함. &lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;bulleted-list&quot; id=&quot;bca5680f-4eed-40cd-8e1e-63bc0613ea3a&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;방법 2: 최대 힙에 더 작은 수를, 최소 힙에 더 큰 수들을 나누어 담은 후 각 힙에서 O(1) 시간으로 얻을 수 있는 최대값과 최소값으로 중위값을 구하기 ⇒ 통과함&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;da6722fa-0a61-4719-9cb3-6e2491093ef9&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;방법 2 풀이 코드: &lt;/summary&gt;&lt;p class=&quot;&quot; id=&quot;4f8d987e-29af-41f3-a607-df7167c3fb35&quot;&gt;최대 힙과 최소 힙을 따로 구현하였다. leetcode에서 직접 풀 때는 디폴트로 제공되는 priority queue나 queue를 사용할 수도 있다(참고: “&lt;a href=&quot;https://support.leetcode.com/hc/en-us/articles/360011833974-What-are-the-environments-for-the-programming-languages-&quot;&gt;언어별 환경(사용 가능한 라이브러리 구성)에 대하여&lt;/a&gt;”)&lt;/p&gt;&lt;ul class=&quot;toggle&quot; id=&quot;153229b4-ac72-4a5f-8583-f276eb55b0a2&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;최소 힙 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;e237035b-232f-401f-9704-285705a56177&quot;&gt;&lt;code&gt;class MinHeap {
    private heap: number[];

    constructor() {
        this.heap = [];
    }

    //^ 삽입한 요소를 힙 구조에 맞게 위치 조정(heapify) - Bubble up
    // Time complexity: O(log N)
    // Space complexity: O(1)
    private bubbleUp() {
        // 마지막 요소에서 시작. 부모와 교체할 때마다 그 위치로 index 값이 조정됨. 그렇게 업데이트되는 바뀌는 위치가 root 노드에 도달하기까지 아래 루프를 반복한다.
        let index = this.heap.length - 1;
        while (index &amp;gt; 0) {
            // 해당 요소의 부모 노드 위치를 계산해서 그 값을 parent로 지정한다. heap은 왼쪽부터 꽉꽉 채워서 차례로 들어가는 반 완전 이진 트리(?)로 본다. 
            const element = this.heap[index];
            const parentIndex = Math.floor((index - 1) / 2);
            const parent = this.heap[parentIndex];

            // 새로 삽입한 요소와 부모 노드를 비교하여 위치를 조정:
            // 만약 지금 요소가 부모보다 크거나 같으면 전체 루프를 멈춘다. 
            if (element &amp;gt;= parent) break;

            // 만약 부모보다 값이 작으면 자리를 바꾼다.
            this.heap[index] = parent;
            this.heap[parentIndex] = element;

            // (부모와 바꿔서) 새롭게 위치한 자리를 새로운 index로 삼는다. 
            index = parentIndex;
            
            // 자신보다 작은 부모를 만나거나 루트에 도달하기까지 과정을 반복한다.
        }
    }

    //^ 추출한 요소를 힙 구조에 맞게 위치 조정(heapify) - Bubble Down
    // Time complexity: O(log N)
    // Space complexity: O(1)
    private bubbleDown() {
        // 앞의 요소부터 시작한다.
        let index = 0;
        const element = this.heap[index];

        // 무한 루프를 돌면서
        while (true) {
            // 현재 요소의 두 자식 위치를 구한다.
            const leftChildIndex = index * 2 + 1;
            const rightChildIndex = index * 2 + 2;
            let leftChild, rightChild;
            let swapTarget = null;

            // 각 자식마다, 자식의 위치가 실제 존재하는 노드라면(=heap의 길이 내라면) 그 값을 leftChild, rightChild에 저장한다. 또 각 자식이 현재 요소보다 작으면 자리를 바꿔야 하므로, 바꿀 타겟이 되는 위치 변수 swapTarget에 자식의 위치를 따로 저장한다. 
            if (leftChildIndex &amp;lt; this.heap.length) {
                leftChild = this.heap[leftChildIndex];
                if (leftChild &amp;lt; element) {
                    swapTarget = leftChildIndex;
                }
            }

            // 그래서 만약 &quot;왼 자식은 그대로 두고 오른 자식만 바꿔야 하든지&quot;, &quot;왼 자식도 바꿔야 하는데 오른 자식이 왼보다 더 작다면(더 작은 쪽을 위로 올려야 하므로)&quot; 오른 자식을 바꿀 대상 swapTarget으로 삼는다. 
            if (rightChildIndex &amp;lt; this.heap.length) {
                rightChild = this.heap[rightChildIndex];
                if ((!swapTarget &amp;amp;&amp;amp; rightChild &amp;lt; element) ||
                    (swapTarget &amp;amp;&amp;amp; rightChild &amp;lt; leftChild)) {
                    swapTarget = rightChildIndex;
                }
            }
            
            // 교체할 대상이 없다면 현재 루프를 break한다. 루프 전체에서 break하는 부분이 여기뿐으로, 두 자식 중 더이상 바꿀 대상이 없는 경우에만 무한 루프를 멈추게 된다. 
            if (!swapTarget) break;

            // 교체할 대상이 있다면 현재 노드와 교체한다. 
            this.heap[index] = this.heap[swapTarget];
            this.heap[swapTarget] = element;

            // 다시 '현재 요소'의 위치를 바꾼 타겟 위치로 지정하고 루프를 계속한다. 
            index = swapTarget;
        }
    }

    //^ 요소를 삽입
    // Time &amp;amp; Space complexity: bubbleUp()과 동일
    insert(value: number) {
        // heap배열의 마지막에 요소를 삽입하고, 알맞은 위치로 찾아가도록 this.bubbleUp() 활용
        this.heap.push(value);
        this.bubbleUp();
    }

    //^ 최소 요소 추출
    // Time &amp;amp; Space complexity: bubbleDown()과 동일
    popMin() {
        // 제일 앞의 요소가 반환 대상이다.(아직 안뽑음)
        const min = this.heap[0];
        // 제일 뒤의 요소를 뽑고서(?) 만약 heap이 비게 됐다면 이게 곧 반환할 최소값이라는 소리이므로 그대로 반환한다. 
        const end = this.heap.pop();

        // 만약 heap 길이가 아직 0이 아니면 뽑은 수를 제일 앞 자리로 덮어씌워준다. 그리고 거기서부터 bubbleDown해서 제자리를 찾도록 한다.
        if (this.heap.length &amp;gt; 0) {
            this.heap[0] = end;
            this.bubbleDown();
        }

        return min;
    }

    //^ 힙의 길이를 반환
    getLength() {
        return this.heap.length;
    }

    //^ 최소값을 반환(추출 없이)
    getMin() {
        return this.heap[0];
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot;toggle&quot; id=&quot;97dc2346-7704-49ff-9c37-0221894ac9a1&quot;&gt;&lt;li&gt;&lt;details open=&quot;&quot;&gt;&lt;summary&gt;최대 힙 코드: &lt;/summary&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;04945d00-c099-4f0d-a06a-49f1c932581c&quot;&gt;&lt;code&gt;// MinHeap과 거의 비슷하므로 주석은 생략한다.
class MaxHeap {
	private heap: number[]

	constructor() {
		this.heap = [];
	}

	//^ heap의 맨 끝 요소를 제자리로 끌어올리기
	private bubbleUp() {
		// 부모와 비교하여 더 클 때만 자리를 교체한다.
		let index = this.heap.length - 1;

		while (index &amp;gt; 0) {
			let element = this.heap[index];
			let parentIndex = Math.floor((index - 1) / 2);
			let parent = this.heap[parentIndex];
			
			if (element &amp;lt;= parent) break;
			
			this.heap[parentIndex] = element;
			this.heap[index] = parent;
			
			index = parentIndex;
		}
	}
	
	//^ heap의 맨 앞 요소를 제자리로 끌어내리기
	private bubbleDown() {
		// 존재하는 자식 중 나보다 더 큰 최대 자식과 자리를 교체한다. 
		let index = 0;
		const element = this.heap[index];
		
		while (true) {
			let leftChildIndex = index * 2 + 1;
			let rightChildIndex = index * 2 + 2;
			let leftChild, rightChild;
			let swapTarget = null;

			if (leftChildIndex &amp;lt; this.heap.length) {
				leftChild = this.heap[leftChildIndex];
				if (element &amp;lt; leftChild) {
					swapTarget = leftChildIndex;
				}
			}
			if (rightChildIndex &amp;lt; this.heap.length) {
				rightChild = this.heap[rightChildIndex];
				if ((swapTarget === null &amp;amp;&amp;amp; element &amp;lt; rightChild) ||
					(swapTarget !== null &amp;amp;&amp;amp; leftChild &amp;lt; rightChild)) {
					swapTarget = rightChildIndex;
				}
			}

			if (swapTarget === null) break;

			this.heap[index] = this.heap[swapTarget];
			this.heap[swapTarget] = element;

			index = swapTarget;
		}

	}

	//^ 요소를 삽입
	insert(num: number) {
		this.heap.push(num);
		this.bubbleUp();
	}

	//^ 최대 요소 추출
	popMax() {
		const max = this.heap[0];
		const end = this.heap.pop();
		if (this.heap.length &amp;gt; 0) {
			this.heap[0] = end;
			this.bubbleDown();
		}
		return max;
	}

	getLength() {
		return this.heap.length;
    }
    
    getMax() {
        return this.heap[0];
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;code code-wrap TypeScript&quot; id=&quot;ffa6f4e2-f899-4393-89a4-11385ef03730&quot;&gt;&lt;code&gt;/* 
 ^ 필요 자료 구조: Min heap과 Max heap
 ^ addNum의 로직: 
    1. 추가하려는 수가 현재 min heap의 .getMin()과 같거나 더 크면 min heap에 넣고, 더 작으면 max heap에 넣는다. 
    2. 새 수를 추가하고서 두 힙의 길이가 2 이상 차이 나면, 더 긴 쪽에서 .pop()하여 반대쪽에 넣어준다.
    3. 처음엔(두 힙 모두 길이가 0이면) min heap에 넣어준다. 
	  =&amp;gt; O(2 log N)

 ^ findMedian의 로직: 
    1. finMdeian()이 불린 시점에서 두 힙의 길이가 같으면 각각의 min과 max를 get()하여 평균을, 둘의 길이가 다르면 더 긴 쪽에서 get()한 값을 반환한다. 
    =&amp;gt; O(1)
*/
class MedianFinder {
    minHeap: MinHeap
    maxHeap: MaxHeap
    constructor() {
        this.minHeap = new MinHeap();
        this.maxHeap = new MaxHeap();
    }

    addNum(num: number) {
        if (num &amp;lt; this.minHeap.getMin())
            this.maxHeap.insert(num);
        else
            this.minHeap.insert(num);
        // initially(when both lengths are 0), the number goes to the min heap naturally. 

        const minLength = this.minHeap.getLength();
        const maxLength = this.maxHeap.getLength();
        if (minLength - maxLength &amp;gt;= 2) { // min heap에서 뽑아서 max heap으로
            const popped = this.minHeap.popMin();
            this.maxHeap.insert(popped);
        }
        if (maxLength - minLength &amp;gt;= 2) { // max heap에서 뽑아서 min heap으로
            const popped = this.maxHeap.popMax();
            this.minHeap.insert(popped);
        }
    }

    findMedian(): number {
        const minLength = this.minHeap.getLength();
        const maxLength = this.maxHeap.getLength();
        const min = this.minHeap.getMin();
        const max = this.maxHeap.getMax();
        if (minLength === maxLength)
            return (min + max) / 2;
        return (minLength &amp;gt; maxLength) ? min : max;
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;&quot; id=&quot;114bd716-bd6f-49f4-98bd-5fbec42abd20&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;html&gt;&lt;body&gt;&lt;br/&gt;&lt;p class=&quot;&quot;&gt;Uploaded by &lt;mark class=&quot;highlight-orange&quot;&gt;&lt;a href=&quot;https://github.com/jmjeon94/N2T&quot;&gt;N2T&lt;/a&gt;&lt;/mark&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;&lt;/div&gt;&lt;/article&gt;&lt;span class=&quot;sans&quot; style=&quot;font-size:14px;padding-top:2em&quot;&gt;&lt;/span&gt;&lt;/body&gt;</description>
      <category>TIL | WIL</category>
      <category>Til</category>
      <category>최대 힙(Max Heap)</category>
      <category>최소 힙(Min Heap)</category>
      <author>깊은바다거북</author>
      <guid isPermaLink="true">https://dev-ocean.tistory.com/226</guid>
      <comments>https://dev-ocean.tistory.com/226#entry226comment</comments>
      <pubDate>Mon, 23 Oct 2023 22:35:05 +0900</pubDate>
    </item>
  </channel>
</rss>