<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>망구스 blog</title>
    <link>https://jschoi96.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 20 Jul 2026 13:59:32 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>미네구스</managingEditor>
    <item>
      <title>2차원 배열에서 회전</title>
      <link>https://jschoi96.tistory.com/218</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;90도 시계방향으로 회전하거나 반시계 방향으로 회전할 때 방식은 외워놓으면 도움이 많이 될 것 같다.&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;/p&gt;
&lt;pre id=&quot;code_1750565494042&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;newBoard[j][n - 1 - i] = board[i][j];&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;반시계 방향&lt;/p&gt;
&lt;pre id=&quot;code_1750565513789&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;newBoard[size - j - 1][i] = board[i][j];&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;특정 시작 좌표(x,y)를 기준으로 돌리고 싶다면&lt;/p&gt;
&lt;pre id=&quot;code_1750565834255&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;newBoard[y + j][x + n - 1 - i] = board[y + i][x + j];&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&gt;&amp;nbsp;&lt;/span&gt;(y1, x1)&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;/p&gt;
&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://velog.io/@danbibibi/2%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-90%EB%8F%84-%ED%9A%8C%EC%A0%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@danbibibi/2%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-90%EB%8F%84-%ED%9A%8C%EC%A0%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1750565425506&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;2차원 배열에서 90도 회전 알고리즘&quot; data-og-description=&quot;N * N 크기의 2차원 배열 전체를 시계방향으로 회전 시키는 방법은 생각보다 간단하다. 우선 이해를 돕기위해 1~25의 숫자를 가지는 5x5 크기의 2차원 배열을 그려 두었다. 회전 전후를 비교해서 보&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@danbibibi/2%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-90%EB%8F%84-%ED%9A%8C%EC%A0%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-url=&quot;https://velog.io/@danbibibi/2차원-배열에서-90도-회전-알고리즘&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cVBkwU/hyZcqdglHc/kcSqDKAkJePK4Wr85vNnP0/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500,https://scrap.kakaocdn.net/dn/ho7j8/hyZcqEj297/W54dGwcVaHuMv7VQeKSUjK/img.png?width=1785&amp;amp;height=811&amp;amp;face=0_0_1785_811,https://scrap.kakaocdn.net/dn/dmHr0M/hyY8S3xoMa/8QcVxWWQFfvMnImdLPvYJk/img.png?width=1491&amp;amp;height=655&amp;amp;face=0_0_1491_655&quot;&gt;&lt;a href=&quot;https://velog.io/@danbibibi/2%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-90%EB%8F%84-%ED%9A%8C%EC%A0%84-%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://velog.io/@danbibibi/2%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-90%EB%8F%84-%ED%9A%8C%EC%A0%84-%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/cVBkwU/hyZcqdglHc/kcSqDKAkJePK4Wr85vNnP0/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500,https://scrap.kakaocdn.net/dn/ho7j8/hyZcqEj297/W54dGwcVaHuMv7VQeKSUjK/img.png?width=1785&amp;amp;height=811&amp;amp;face=0_0_1785_811,https://scrap.kakaocdn.net/dn/dmHr0M/hyY8S3xoMa/8QcVxWWQFfvMnImdLPvYJk/img.png?width=1491&amp;amp;height=655&amp;amp;face=0_0_1491_655');&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;2차원 배열에서 90도 회전 알고리즘&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;N * N 크기의 2차원 배열 전체를 시계방향으로 회전 시키는 방법은 생각보다 간단하다. 우선 이해를 돕기위해 1~25의 숫자를 가지는 5x5 크기의 2차원 배열을 그려 두었다. 회전 전후를 비교해서 보&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&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/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/218</guid>
      <comments>https://jschoi96.tistory.com/218#entry218comment</comments>
      <pubDate>Sun, 22 Jun 2025 13:17:44 +0900</pubDate>
    </item>
    <item>
      <title>연산자 끼워넣기, 스타트와 링크</title>
      <link>https://jschoi96.tistory.com/217</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;삼성 기출문제들을 풀면서 이전에 풀었던 실버I 두문제를 풀어보았다. 이전에는 풀지 못하고 답을 참고했던 기억이 나는데, 이번엔 상대적으로 쉽게 풀어서 나름 성장한것을(?) 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;연산자 끼워넣기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14888&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/14888&lt;/a&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;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67257&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/67257&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748883122899&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67257&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/T6aTl/hyY5gVHM22/RB3Qja2AkkMlJKDEXWdOYk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bwHd21/hyY1jmfWs1/V8nAnmihWuAEZogCcRwQX0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67257&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67257&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/T6aTl/hyY5gVHM22/RB3Qja2AkkMlJKDEXWdOYk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bwHd21/hyY1jmfWs1/V8nAnmihWuAEZogCcRwQX0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&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;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;/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;백준 문제는 수열을 앞에서 부터 순회하며, 4가지 연산에 따라서 모든 경우의 수를 구해서 계산해주면 되는 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N=11일 때 연산자의 개수는 10개 이므로, 백트래킹으로 계산했을 때 시간복잡도는 10! = 360만이 되어 충분히 1초안에 통과 가능하다.&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;앞에서부터 순회하며 연산자의 수가 1이상일 때 해당 연산자에 맞는 계산을 해주고, 횟수 -1을 해준다. 탐색이 끝난 뒤에는 +1을 해줘서 원복을 시켜줘야 한다.&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;이렇게 해서 쉽게 최소, 최대값을 구할 수 있는데, 로직이 맞는데 자꾸 틀려서 봤더니 최소값의 초기값 설정을 0으로 둬서 생긴 문제였다. 음수가 생길수도 있으니 이 부분을 빠르게 캐치하지 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스타트와 링크&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14889&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/14889&lt;/a&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;N=20이고, 각 스타트와 링크는 n=10이기 때문에 해당 문제 역시 백트래킹으로 탐색이 가능하다.&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;백트래킹을 돌며 depth가 n/2일 때 return하며 팀이 될수 있는 모든 경우의 수를 찾는다. 이 때, 방문처리 되었다면 스타트 팀 아니라면 링크 팀으로 구분해주었다.&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;팀을 나누었다고 해서 끝이 아닌데, 예를 들어 (0,1,2)가 같은 팀의 경우 계산을 어떻게 해줘야하나 처음에 헷갈렸다. 다시한번 천천히 살펴보니 (0,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;개인적으로 아쉬웠던 점은, dfs(0, 0) 이렇게 시작값을 정해주었을 때 중복이 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타트 (0,1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크 (2,3)&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,3)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크 (0,1)&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;gpt의 도움을 빌려보니,&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748883918506&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;visited[0] = true;
dfs(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;이런식으로 0번 인덱스를 무조건 스타트에 포함시키면, 중복 조합이 제거가 가능했다.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-06-03 오전 2.05.54.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9svkh/btsOmo0bvYF/fFLhd9o7yjMJJk1Jx35jZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9svkh/btsOmo0bvYF/fFLhd9o7yjMJJk1Jx35jZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9svkh/btsOmo0bvYF/fFLhd9o7yjMJJk1Jx35jZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9svkh%2FbtsOmo0bvYF%2FfFLhd9o7yjMJJk1Jx35jZK%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;380&quot; height=&quot;232&quot; data-filename=&quot;스크린샷 2025-06-03 오전 2.05.54.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;232&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;/p&gt;</description>
      <category>Algorithm/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/217</guid>
      <comments>https://jschoi96.tistory.com/217#entry217comment</comments>
      <pubDate>Tue, 3 Jun 2025 02:06:27 +0900</pubDate>
    </item>
    <item>
      <title>[카카오 인턴] 경주로 건설</title>
      <link>https://jschoi96.tistory.com/216</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/67259&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1748782282741&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b8kZmm/hyY30ZHSwo/4JZPLYBNUWhPZbNkar1lY0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/fc3MH/hyY1ekDIzm/yDjnXzkWroDu7Go6CanwB0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b8kZmm/hyY30ZHSwo/4JZPLYBNUWhPZbNkar1lY0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/fc3MH/hyY1ekDIzm/yDjnXzkWroDu7Go6CanwB0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&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;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;접근 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(0,0)부터 (n-1, n-1)까지 도달한다고 할 때, 모든 경우의 수를 고려하는 것을 어떻게 할까? 가 첫번째 관문이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백트래킹을 떠올렸으나, 25 x 25인 경우엔 시간초과가 날 것이기 때문에 제외했다.&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;boolean visited를 사용하여 코드를 짰지만, 당연히 하나의 최단경로만 탐색했다. 문제에서 원하는 것은 모든 경우의 수에서 최소 값이다.&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;따라서, int visited를 통해서 현재 값들을 배열에 저장해두고, 최소 비용이 갱신되는 경우에만 다음 칸으로 탐색이 가능하게 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 방향에 따라서 100, 600값이 달라지므로 현재 방향을 저장하는 값을 큐에 넣어서 다음 탐색 방향이 같은 경우 +100, 아닌경우 +600 이런식으로 구현했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;pre id=&quot;code_1748784165137&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;
class Solution {
    static int n;
    static int[] dx = {1, 0, -1, 0};
    static int[] dy = {0, 1, 0, -1};
    static int min_cost = Integer.MAX_VALUE;
    public int solution(int[][] board) {
        int answer = 0;
        n = board.length;
        
        bfs(0, board);
        bfs(1, board);
        
        return min_cost;
    }
    
    public void bfs(int direction, int[][] board) {
        Queue&amp;lt;Point&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
        q.add(new Point(0, 0, direction, 0));
        
        int[][] visited = new int[n][n];
        visited[0][0] = 100;
        
        while(!q.isEmpty()) {
            Point cur = q.poll();
            int x = cur.x;
            int y = cur.y;
            int curDir = cur.dir;
            int cost = cur.cost;
            
            if (x == n - 1 &amp;amp;&amp;amp; y == n - 1) {
                //System.out.println(cost);
                min_cost = Math.min(min_cost, cost);
                continue;
            }
            
            for(int dir = 0; dir &amp;lt; 4; dir++) {
                int nx = x + dx[dir];
                int ny = y + dy[dir];
                if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= n || ny &amp;gt;= n) continue;
                if (board[nx][ny] == 1) continue;
                
                int nextCost = 0;
                if (curDir == dir) nextCost = cost + 100;
                else nextCost = cost + 600;
                
                if (visited[nx][ny] == 0 || nextCost &amp;lt; visited[nx][ny]) {
                    visited[nx][ny] = nextCost;
                    q.add(new Point(nx, ny, dir, nextCost));
                }
            }
        }
    }
    
    public class Point {
        int x;
        int y;
        int dir;
        int cost;
        public Point(int x, int y, int dir, int cost) {
            this.x = x;
            this.y = y;
            this.dir = dir;
            this.cost = cost;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;후기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bfs만 보면 반사적으로 visited.. 이렇게 생각했는데 최소 cost를 계산하는 경우에는 int 배열을 통해 다음 탐색 지점을 찾도록 하자.&lt;/p&gt;</description>
      <category>Algorithm/프로그래머스</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/216</guid>
      <comments>https://jschoi96.tistory.com/216#entry216comment</comments>
      <pubDate>Sun, 1 Jun 2025 22:23:45 +0900</pubDate>
    </item>
    <item>
      <title>boj14891: 톱니바퀴</title>
      <link>https://jschoi96.tistory.com/215</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14891&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/14891&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;접근 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 4개의 톱니바퀴를 어떤 자료구조로 저장할지 고민하고, 이동시키는게 상대적으로 편한 리스트를 고민했으나 다른 사람들의 풀이를 참고하여 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;움직이는 톱니바퀴를 찾고, 해당 톱니바퀴의 왼쪽 및 오른쪽을 순회하며 움직이는 경우엔 현재 방향에서 -1을 곱해주고 아닌 경우엔 멈췄다는 의미이므로 탐색을 중지했다. 4개 톱니바퀴의 이동 방향을 저장해둔 다음에, 시계 방향 및 반시계 방향에 따라서 재배열을 진행하면 되는 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;pre id=&quot;code_1748781917706&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&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;

public class boj14891 {
    static int [][] wheels = new int[4][8];
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        for(int i = 0; i &amp;lt; 4; i++) {
            String input = br.readLine();
            for(int j = 0; j &amp;lt; 8; j++) {
                wheels[i][j] = input.charAt(j) - '0';
            }
        }

        int k = Integer.parseInt(br.readLine());
        for(int i = 0; i &amp;lt; k; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int target = Integer.parseInt(st.nextToken());
            int dir = Integer.parseInt(st.nextToken());

            target -= 1;
            int [] arr = new int[4];
            arr[target] = dir;

            for(int j = target - 1; j &amp;gt;= 0; j--) { // 왼쪽 방향으로
                if (wheels[j+1][6] != wheels[j][2]) { // 만약에 방향이 다르다면 반대로 회전
                    arr[j] = arr[j+1] * -1;
                }
                else break; // 움직이지 않는다면 고정
            }

            for(int j = target; j &amp;lt; 3; j++) {
                if (wheels[j][2] != wheels[j+1][6]) {
                    arr[j+1] = arr[j] * -1;
                }
                else break;
            }

            for(int j = 0; j &amp;lt; 4; j++) {
                if (arr[j] == 1) wheels[j] = turnRight(j);
                else if (arr[j] == -1) wheels[j] = turnLeft(j);
            }

//            for(int j = 0; j &amp;lt; 4; j++) {
//                for(int t = 0; t &amp;lt; 8; t++) {
//                    System.out.print(wheels[j][t]);
//                }
//                System.out.println();
//            }
        }
        System.out.println(getScore());
    }

    public static int getScore() {
        int score = 0;
        if (wheels[0][0] == 1) score += 1;
        if (wheels[1][0] == 1) score += 2;
        if (wheels[2][0] == 1) score += 4;
        if (wheels[3][0] == 1) score += 8;
        return score;
    }

    // 01111101
    // 1 0111110
    public static int[] turnRight(int target) { // 1일때 시계방향 회전
        int[] tmp = new int[8];
        for(int i = 1; i &amp;lt; 8; i++) { //
            tmp[i] = wheels[target][i-1];
        }
        tmp[0] = wheels[target][7];
        return tmp;
    }

    // 01111101
    // 1111101 0
    public static int[] turnLeft(int target) { // -1일때 역방향 회전
        int[] tmp = new int[8];
        for(int i = 0; i &amp;lt; 7; i++) {
            tmp[i] = wheels[target][i+1];
        }
        tmp[7] = wheels[target][0];
        return tmp;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/215</guid>
      <comments>https://jschoi96.tistory.com/215#entry215comment</comments>
      <pubDate>Sun, 1 Jun 2025 21:45:20 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 감시</title>
      <link>https://jschoi96.tistory.com/213</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/15683&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/15683&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;접근 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간복잡도 최악의 케이스에는: 4^8 * 8 * 8으로, 1초에 충분히 풀어낼 수 있다.&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;문제를 풀며 헷갈렸던 것 두가지는, 어떻게 각 cctv 방향 경우의 수 만큼 백트래킹을 돌려주는 것과 board의 값들을 계속해서 업데이트 시켜주는 것이 헷갈렸다.&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;경우의 수는, 단순히 해당 cctv의 direction 경우의 수를 가져와서 for문을 돌면 해결되었고, 배열 복사같은 경우 문제가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1748158462674&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[][] tmp = copyBoard(board);

public static int[][] copyBoard(int[][] board) {
    int[][] tmp = new int[n][m];
    for(int i = 0; i &amp;lt; n; i++) {
        for(int j = 0; j &amp;lt; m; j++) {
            tmp[i][j] = board[i][j];
        }
    }
    return tmp;
}&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;기존에는 파라미터 없이 int[][] tmp = copyBoard() 이렇게 해주고 있었는데, 이런식으로 하면 계속해서 원본 배열만 복사하고 초기화하고 이런 형식이라 지속적으로 업데이트를 해줘야한다. 그렇기 때문에, 값을 저장할 수 있는 매개변수를 통해 전달해주었다.&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;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;pre id=&quot;code_1748158207296&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&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.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class boj15683 {
    static int n, m;
    static int[][] board;
    static List&amp;lt;CCTV&amp;gt; cctvList = new ArrayList&amp;lt;&amp;gt;();
    static int[] dx = {0, 1, 0, -1};
    static int[] dy = {1, 0, -1, 0};
    static int res = Integer.MAX_VALUE;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        board = new int[n][m];

        for(int i = 0; i &amp;lt; n; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j = 0; j &amp;lt; m; j++) {
                board[i][j] = Integer.parseInt(st.nextToken());
                if (board[i][j] == 1) cctvList.add(new CCTV(1, 4, new int[]{i,j}));
                else if (board[i][j] == 2) cctvList.add(new CCTV(2, 2, new int[]{i,j}));
                else if (board[i][j] == 3) cctvList.add(new CCTV(3, 4, new int[]{i,j}));
                else if (board[i][j] == 4) cctvList.add(new CCTV(4, 4, new int[]{i,j}));
                else if (board[i][j] == 5) cctvList.add(new CCTV(5, 1, new int[]{i,j}));
            }
        }

        dfs(0, board);
        System.out.println(res);
    }

    public static void dfs(int depth, int[][] board) {
        if (depth == cctvList.size()) {
            // printBoard(board);
            res = Math.min(res, calculateArea(board));
            return;
        }

        CCTV cur = cctvList.get(depth);
        for(int i = 0; i &amp;lt; cur.dir; i++) { // cctv의 방향 케이스만큼 순회
            int[][] tmp = copyBoard(board);
            apply(tmp, cur, i);
            dfs(depth + 1, tmp);
        }
    }

    public static void apply(int[][] tmp, CCTV cur, int dir) {
        int type = cur.type;

        if (type == 1) {
            applyBoard(tmp, cur, dir);
        }

        else if (type == 2) {
            applyBoard(tmp, cur, dir);
            applyBoard(tmp, cur, (dir + 2) % 4);
        }

        else if (type == 3) {
            applyBoard(tmp, cur, (dir + 3) % 4);
            applyBoard(tmp, cur, dir);
        }

        else if (type == 4) {
            applyBoard(tmp, cur, (dir + 3) % 4);
            applyBoard(tmp, cur, (dir + 2) % 4);
            applyBoard(tmp, cur, dir);
        }

        else if (type == 5) {
            applyBoard(tmp, cur, (dir + 3) % 4);
            applyBoard(tmp, cur, (dir + 2) % 4);
            applyBoard(tmp, cur, (dir + 1) % 4);
            applyBoard(tmp, cur, dir);
        }
    }

    public static void applyBoard(int[][] tmp, CCTV cur, int dir) {
        int x = cur.pos[0];
        int y = cur.pos[1];

        while (true) {
            int nx = x + dx[dir];
            int ny = y + dy[dir];

            if (nx &amp;lt; 0 || ny &amp;lt; 0 || nx &amp;gt;= n || ny &amp;gt;= m) break;
            if (tmp[nx][ny] == 6) break;
            if (tmp[nx][ny] == 0) tmp[nx][ny] = -1;
            x = nx;
            y = ny;
        }
    }

    public static int calculateArea(int[][] board) {
        int area = 0;
        for(int i = 0; i &amp;lt; n; i++) {
            for(int j = 0; j &amp;lt; m; j++) {
                if (board[i][j] == 0) area++;
            }
        }
        return area;
    }

    public static void printBoard(int[][] tmp) {
        for(int i = 0; i &amp;lt; n; i++) {
            for(int j = 0; j &amp;lt; m; j++) {
                System.out.print(tmp[i][j] + &quot; &quot;);
            }
            System.out.println();
        }
        System.out.println();
    }

    public static int[][] copyBoard(int[][] board) {
        int[][] tmp = new int[n][m];
        for(int i = 0; i &amp;lt; n; i++) {
            for(int j = 0; j &amp;lt; m; j++) {
                tmp[i][j] = board[i][j];
            }
        }
        return tmp;
    }

    public static class CCTV {
        public int type;
        public int dir;
        public int[] pos;
        public CCTV(int type, int dir, int[] pos) {
            this.type = type;
            this.dir = dir;
            this.pos = pos;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/213</guid>
      <comments>https://jschoi96.tistory.com/213#entry213comment</comments>
      <pubDate>Sun, 25 May 2025 16:36:07 +0900</pubDate>
    </item>
    <item>
      <title>boj21939: 문제 추천 시스템 Version 1</title>
      <link>https://jschoi96.tistory.com/211</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/21939&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/21939&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;접근 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 본 코테와 비슷한 문제였다. 우선순위 큐에 [문제번호, 난이도] 형태로 값을 집어넣고 문제번호나 난이도 조건에 의해 정렬이 되어있다고 가정하자. 만약에, 이 때 무작위의 문제번호를 제거하라고 한다면 어떻게 할 것인가?&lt;br /&gt;&lt;br /&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;문제에서 recommend가 1과 -1일 때 각각 조건이 다른데, 어려운 문제를 우선적으로 뽑는 큐와 쉬운 문제를 우선적으로 뽑는 큐가 필요했다. 나는 max_pq, min_pq로 선언해서 각각의 조건에 맞게 세팅을 해주었다.&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;해쉬맵을 만든 이유는 간단하다. 문제에서 `solved`를 수행할 때, 문제번호 P를 제거를 해야하는데 우선순위 큐의 특성 상 P를 바로 지울 수 없다. 그렇기 때문에 해쉬맵에서 해당 P를 삭제를 먼저 해주는 것이다.&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;solved가 계속해서 수행되고나서 recommend가 수행되면 해쉬맵과 큐의 불일치가 발생할 것이다.&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;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;직관적인 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;max_pq = [1000, 1], [1001,2], [19998, 78], [2667,37], [2042,55]가 있을 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map 또한 [1000, 1], [1001,2], [19998, 78], [2667,37], [2042,55] 이렇게 가지고 있을 것이다.&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;solved 19998가 실행되면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map = [1000, 1], [1001,2], [2667,37], [2042,55]&lt;span&gt;&amp;nbsp;&lt;/span&gt;으로 문제번호 19998이 삭제되지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;max_pq = [1000, 1], [1001,2], [19998, 78], [2667,37], [2042,55]는 그대로이다.&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;이 때, recommend 1을 실행했을 때, max_pq에 있는 문제번호 19998이 map에는 없다. &lt;b&gt;따라서, max_pq의 현재 문제번호와 난이도가 map과 일치할 때 까지 큐를 삭제하면 된다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 과정을 max_pq, min_pq 동시에 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;pre id=&quot;code_1747320141128&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&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.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class boj21939_2 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());

        // 문제번호, 난이도 형태
        PriorityQueue&amp;lt;int[]&amp;gt; max_pq = new PriorityQueue&amp;lt;&amp;gt;((a,b) -&amp;gt; {
            if (a[1] == b[1]) return b[0] - a[0];
            return b[1] - a[1];
        });

        PriorityQueue&amp;lt;int[]&amp;gt; min_pq = new PriorityQueue&amp;lt;&amp;gt;((a, b) -&amp;gt; {
            if (a[1] == b[1]) {
                return a[0] - b[0];
            }
            return a[1] - b[1];
        });

        Map&amp;lt;Integer, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;(); // 제거할 때 쓰는 용도

        for(int i = 0; i &amp;lt; n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            max_pq.add(new int[]{a,b});
            min_pq.add(new int[]{a,b});
            map.put(a,b);
        }

        int m = Integer.parseInt(br.readLine());
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i &amp;lt; m; i++) {
            String input = br.readLine();
            String [] arr = input.split(&quot; &quot;);

            if (arr[0].equals(&quot;add&quot;)) {
                int a = Integer.parseInt(arr[1]);
                int b = Integer.parseInt(arr[2]);
                max_pq.add(new int[]{a,b});
                min_pq.add(new int[]{a,b});
                map.put(a,b); // 모두 다 추가해줌
            }

            else if (arr[0].equals(&quot;solved&quot;)) {
                int a = Integer.parseInt(arr[1]);
                map.remove(a); // 맵에서만 제거해준다.
            }

            else if (arr[0].equals(&quot;recommend&quot;)) {
                int a = Integer.parseInt(arr[1]);
                if (a == 1) { // 추천리스트에 가장 어려운 번호를 출력
                    while (true) {
                        int num = max_pq.peek()[0];
                        int diff = max_pq.peek()[1];
                        if (map.containsKey(num) &amp;amp;&amp;amp; map.get(num) == diff) {
                            sb.append(max_pq.peek()[0]).append(&quot;\n&quot;);
                            break;
                        }

                        max_pq.poll();
                    }
                }

                else {
                    while (true) {
                        int num = min_pq.peek()[0];
                        int diff = min_pq.peek()[1];
                        if (map.containsKey(num) &amp;amp;&amp;amp; map.get(num) == diff) {
                            sb.append(min_pq.peek()[0]).append(&quot;\n&quot;);
                            break;
                        }

                        min_pq.poll();
                    }
                }
            }
        }
        System.out.println(sb);
    }
}&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;</description>
      <category>Algorithm/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/211</guid>
      <comments>https://jschoi96.tistory.com/211#entry211comment</comments>
      <pubDate>Thu, 15 May 2025 23:48:19 +0900</pubDate>
    </item>
    <item>
      <title>boj13904: 과제</title>
      <link>https://jschoi96.tistory.com/210</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/13904&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/13904&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;접근 방법&lt;/h2&gt;
&lt;pre id=&quot;code_1747299719658&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());

        PriorityQueue&amp;lt;int []&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;((a,b) -&amp;gt; {
            if (a[0] == b[0]) {
                return b[1] - a[1]; // 날짜가 같다면 큰 값
            };
            return b[0] - a[0]; // 날짜 큰 순서대로
        });
        for(int i = 0; i &amp;lt; n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int d = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());
            pq.add(new int [] {d,w});
        }

        int total = 0;
        while(!pq.isEmpty()) {
            int [] cur = pq.poll();
            int day = cur[0];
            int score = cur[1];

            total += score;

            List&amp;lt;Integer&amp;gt; tmp = new ArrayList&amp;lt;&amp;gt;();
            while (true) {
                if (pq.isEmpty() || pq.peek()[0] != day) break;
                int [] nxt = pq.poll();
                tmp.add(nxt[1]);
            }

            if (!pq.isEmpty()) for(Integer next : tmp) pq.add(new int[]{pq.peek()[0], next});
        }

        System.out.println(total);
    }
}&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;/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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;올바른 풀이&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;입력값을 리스트 형태에 저장하고, 리스트를 날짜 기준 내림차순 순서대로 정렬한다.&lt;/li&gt;
&lt;li&gt;우선순위 큐를 선언하고, 내림차순으로 정렬해준다.&lt;/li&gt;
&lt;li&gt;for문을 돌 때, 마감일이 제일 느린 날짜부터 순회한다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이 때, &lt;b&gt;아직 처리하지 않은 과제들 중에 day일 이상인 과제를&lt;/b&gt; 모두 우선순위 큐에 넣어준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;큐가 비어있지 않다면, 결과값에 큐를 뺀 값을 더해준다.&lt;/li&gt;
&lt;/ol&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;6: [5]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4: [60, 40, 10]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3: [30]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2: [50]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1: [20]&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;6일차: 5 -&amp;gt; 4일차: 60 -&amp;gt; 3일차: 40 -&amp;gt; 2일차: 50 -&amp;gt; 1일차: 30&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;이렇게 계산이 되며, 결과값인 185를 얻을 수 있다.&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;/h3&gt;
&lt;pre id=&quot;code_1747300359615&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&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.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class boj13904 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());

       List&amp;lt;int[]&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

       int maxDay = 0;
        for(int i = 0; i &amp;lt; n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int d = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());
            list.add(new int[]{d, w});
            maxDay = Math.max(maxDay, d);
        }

        list.sort((a,b) -&amp;gt; b[0] - a[0]); // 마감일 높은 순서대로 정렬

        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());
        int total = 0;
        int idx = 0;

        for(int i = maxDay; i &amp;gt;= 1; i--) {
            while(idx &amp;lt; n &amp;amp;&amp;amp; list.get(idx)[0] &amp;gt;= i) {
                pq.add(list.get(idx)[1]);
                idx++;
            }

            if (!pq.isEmpty()) {
                total += pq.poll();
            }
        }
        System.out.println(total);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/210</guid>
      <comments>https://jschoi96.tistory.com/210#entry210comment</comments>
      <pubDate>Thu, 15 May 2025 18:12:42 +0900</pubDate>
    </item>
    <item>
      <title>인덱스란? ?</title>
      <link>https://jschoi96.tistory.com/207</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;인덱스를 쓰는 이유&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;특정 조건을 만족하는 데이터를 빠르게 찾기 위해&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 Full Text 검색을 하게 되면 O(N)의 시간이 걸리는데, B-tree 기반 인덱스를 사용한다면 O(logN)까지 줄어들게 된다.&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;복합 인덱스에서 설정을 잘못했다고 가정하자. INDEX(a)라는 테이블이 있고 쿼리는 a = 95 and b = 70 이렇게 있다고 가정할 때, a를 찾는 과정은 이전과 동일하게 O(logN)일 것이다. 하지만, b에는 인덱스가 걸려있지 않기 때문에 테이블을 전체 다 조회해야하고 이 때의 시간복잡도는 O(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;따라서, INDEX(a, b)를 설정해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복합 인덱스에서 column의 정렬 순서는 `a`, 그 다음에 `b` 를 정렬한다.&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;복합 인덱스 (a,b)가 걸려있을 때 b만 조회하려고 할 때에도 full text scan을 한다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인덱스를 매번 생성해도 될까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스가 생성될 때 인덱스를 위한 부가적인 데이터가 생성된다. 따라서, 기존 테이블에 데이터가 write가 발생할 때마다 인덱스에도 변경이 발생하기 때문에 그로인한 `오버헤드`가 발생한다.&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;/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;또한, 데이터가 너무 적은 경우에는 굳이 인덱스를 사용하는 것과 full scan의 성능 차이가 없다.&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;full scan의 성능이 더 좋은 경우도 있는데&lt;/b&gt;,&lt;/p&gt;
&lt;pre id=&quot;code_1746361939442&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM customer WHERE mobile_career = 'SK';&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;이런 쿼리문이 있다고 할 때, 백만건의 데이터에서 조회하려는 데이터의 대부분이 SK라면 full scan이 더 빠를 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 인덱스와 full scan의 속도를 비교하여 실행시켜주는 역할은 optimzer가 대신 판단해준다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;B-tree&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B tree의 최대 자녀 노드 수가 M개일 때, key 수는 M-1개가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차 B tree라고 생각했을 때, 자녀 노드 갯수가 3개일 때 부모는 2개이므로 자녀 노드 갯수가 정해진다면 다른 값들도 자연스럽게 정해진다고 볼 수 있다.&amp;nbsp;&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B tree 삽입은 두가지 기준을 따른다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추가는 항상 leaf 노드에 한다.&lt;/li&gt;
&lt;li&gt;노드가 넘치면 가운데 (median) key를 기준으로 좌우 key들은 분할하고 가운데 key는 승진한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 과정을 통해 삽입됐을 때 노드가 넘쳤을 때 key를 위로 올려주기 때문에, &lt;b&gt;모든 leaf 노드들은 같은 레벨에 존재한다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 것은 balanced tree라고도 이야기 할 수 있고, &lt;/b&gt;검색에서의 worst/best case에서 O(logN)을 보장한다.&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제도 마찬가지로,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삭제는 항상 leaf 노드에서 발생한다&lt;/li&gt;
&lt;li&gt;삭제 후 최소 key보다 작아졌다면 재조정을 해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;root 노드에서 각 노드의 최소 key 수는 [M/2] - 1개 이다. 3차 B tree임을 가정하면, 최소 Key는 1개이고, &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;/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;그래서 왜 인덱스에 B tree를 사용할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B tree를 언급하기에 앞서, BST를 알아보자. BST의 삽입, 삭제, 조회의 시간복잡도는 평균적으로 O(logN)이나, 최악의 케이스에는 O(n)이 된다. 왜 그럴까?&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w7W2D/btsNJ1YLXgR/D1AQV0doGGKbmLZDcMQttk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w7W2D/btsNJ1YLXgR/D1AQV0doGGKbmLZDcMQttk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w7W2D/btsNJ1YLXgR/D1AQV0doGGKbmLZDcMQttk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw7W2D%2FbtsNJ1YLXgR%2FD1AQV0doGGKbmLZDcMQttk%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;354&quot; height=&quot;390&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;390&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;해당 케이스가 BST의 worst case인데, 이런식으로 balance하지 않게 한쪽으로 치우치게 된다면 삽입, 삭제, 조회에 드는 시간 복잡도가 O(n)이 되버린다. 이런 경우에서 B tree의 성능이 BST보다 좋다고 할 수 있는것이다.&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;반면에, BST중에서도 스스로 균형을 잡는(balanced) AVL tree나 Red-Black tree가 있는데 해당 자료구조는 항상 balance를 유지하기 때문에 최악의 경우에도 O(logN)을 보장한다. 그렇다면, &lt;b&gt;왜 AVL tree를 안쓰고 B-tree를 쓰는걸까?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJHIE8/btsNL9t0YMZ/Dat2S7hCFtlGiTrNUVvosk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJHIE8/btsNL9t0YMZ/Dat2S7hCFtlGiTrNUVvosk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJHIE8/btsNL9t0YMZ/Dat2S7hCFtlGiTrNUVvosk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJHIE8%2FbtsNL9t0YMZ%2FDat2S7hCFtlGiTrNUVvosk%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;231&quot; height=&quot;218&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;218&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;h3 data-ke-size=&quot;size23&quot;&gt;Computer System에 대한 이해&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-05 오후 3.18.44.png&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ictm2/btsNLp5hqBC/4q2OuseKvH2ZxVViuIG5V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ictm2/btsNLp5hqBC/4q2OuseKvH2ZxVViuIG5V0/img.png&quot; data-alt=&quot;컴퓨터 시스템 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ictm2/btsNLp5hqBC/4q2OuseKvH2ZxVViuIG5V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIctm2%2FbtsNLp5hqBC%2F4q2OuseKvH2ZxVViuIG5V0%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;397&quot; height=&quot;306&quot; data-filename=&quot;스크린샷 2025-05-05 오후 3.18.44.png&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;676&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;CPU&lt;/b&gt;: 프로그램 코드가 강제로 실행되는 곳&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Main memory&lt;/b&gt;: 실행중인 코드들과 결과로 나온 데이터들이 상주하는 곳&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Secondary storage&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;Secondary storage의 특징으로는&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터를 처리하는 속도가 가장 느리다.&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RAM의 평균 속도: 40 ~ 50인 반면, SSD와 HDD의 속도는 3 ~ 5, 0.2 ~ 0.3이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터를 저장하는 용량이 가장 크다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;block&lt;/b&gt; 단위로 데이터를 읽고 쓴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB의 데이터는 중요한 데이터이기 때문에, 컴퓨터를 꺼도 지속적으로 데이터가 내부에 남아있어야 한다. 그렇기 때문에 Secondary Stroage에 저장이 된다. 핵심 데이터의 몇 개는 Main memory에 올려놓고, 나머지는 Secondary storage에 넣어둔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로, DB에서 데이터를 조회할 때 secondary storage를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;최대한 적게 조회하는 방식이 성능 면에서 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, block 단위로 읽고 쓰기 때문에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;연관된 데이터를 모아서 저장하면 더 효율적으로 읽고 쓸 수 있다.&amp;nbsp;&lt;/b&gt;&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;color: #000000;&quot;&gt;AVL tree vs B-tree 시간 복잡도 비교&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 비교하기 전에, 루트 노드만 메인 메모리에 올라와있고, 나머지 데이터들은 Secondary Storage에 존재한다고 가정하자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-05 오후 3.47.05.png&quot; data-origin-width=&quot;1752&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XWmNS/btsNLqC85EE/0KDxEkkyvAvLqfKRSeKTK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XWmNS/btsNLqC85EE/0KDxEkkyvAvLqfKRSeKTK0/img.png&quot; data-alt=&quot;AVL tree&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XWmNS/btsNLqC85EE/0KDxEkkyvAvLqfKRSeKTK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXWmNS%2FbtsNLqC85EE%2F0KDxEkkyvAvLqfKRSeKTK0%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;444&quot; height=&quot;224&quot; data-filename=&quot;스크린샷 2025-05-05 오후 3.47.05.png&quot; data-origin-width=&quot;1752&quot; data-origin-height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AVL tree&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;`b = 5`인 데이터를 조회를 한다고 할 때, 처음에 루트 노드에서 시작을 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6 -&amp;gt; 3 -&amp;gt; 4 -&amp;gt; 5 -&amp;gt; Secondary Storage에 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;이를 통해 화살표가 4개 이므로, Secondary Storage에 4번 접근한 것을 알 수 있다.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-05-05 오후 3.50.34.png&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;836&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8Wd10/btsNLURousc/AlghfeEAbKvWyhQRjpt9eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8Wd10/btsNLURousc/AlghfeEAbKvWyhQRjpt9eK/img.png&quot; data-alt=&quot;B tree&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8Wd10/btsNLURousc/AlghfeEAbKvWyhQRjpt9eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8Wd10%2FbtsNLURousc%2FAlghfeEAbKvWyhQRjpt9eK%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;523&quot; height=&quot;252&quot; data-filename=&quot;스크린샷 2025-05-05 오후 3.50.34.png&quot; data-origin-width=&quot;1734&quot; data-origin-height=&quot;836&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;B tree&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;B tree에서도 `b = 5`인 데이터를 조회한다고 할 때, 4 &amp;lt; b &amp;lt; 8이므로,&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;root node -&amp;gt; 5,6,7 leaf node -&amp;gt; Secondary Storage에 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;화살표가 2개 이므로, Secondary Storage에 2번 접근한 것을 알 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;결과&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AVL tree: 4번 vs B tree: 2번 이므로, Secondary Storage에 적게 접근하는 B tree의 성능이 더 뛰어나다고 할 수 있다. 이러한 차이는 트리가 가질 수 있는 자녀 노드 수에 기인하는데, 5차 B-tree는 3 ~ 5개를 가질 수 있는 반면 AVL tree는 항상 1 ~ 2개 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 &lt;b&gt;B tree는 데이터를 찾을 때 탐색 범위를 빠르게 줄일 수 있다는 강점이 있다.&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;또한, secondary storage에서는 block 단위로 데이터를 읽는다고 했는데, B tree인 경우엔 한 block에 [1,2,3]이 포함되는 반면,&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 59.7674%; height: 25px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AVL tree에서는 한 block에 [1]만 들어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 60.2326%; height: 13px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%; text-align: center;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;둘다 똑같은 공간을 차지하고 있지만 AVL 트리에선 공간이 좀 더 낭비되고 있는 것을 볼 수 있다. 따라서, &lt;b&gt;B-tree가 block 단위에 대한 저장 공간 활용도 또한 좋은 것을 확인할 수 있다.&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;&amp;nbsp;&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;Hash Index&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해쉬 인덱스를 사용한다면 삽입/삭제/조회를 O(1)에 수행할 수 있어 B-tree보다도 더 강력한 성능을 자랑하지만, &lt;b&gt;equality (=) 조회만 가능하고 범위 기반 검색이나 정렬에는 사용될 수 없는 단점이 있다.&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;따라서, equality 조회만 한다고 가정할 때는 Hash Index를 사용하는 것이 효율적일 것이다.&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;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인덱스가 무엇이고, 언제 사용하는지 설명해 주세요.&lt;/h3&gt;
&lt;a id=&quot;user-content-5-인덱스가-무엇이고-언제-사용하는지-설명해-주세요&quot; style=&quot;color: #4493f8;&quot; href=&quot;https://github.com/VSFe/Tech-Interview/blob/main/04-DATABASE.md#5-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EA%B3%A0-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%B4-%EC%A3%BC%EC%84%B8%EC%9A%94&quot;&gt;&lt;/a&gt;&lt;/div&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;li&gt;앞 꼬리질문에 대해, 그렇다면 인덱스에서 사용하지 않겠다고 선택한 값은 위 정책을 그대로 따라가나요?&lt;/li&gt;
&lt;li&gt;ORDER BY/GROUP BY 연산의 동작 과정을 인덱스의 존재여부와 연관지어서 설명해 주세요.&lt;/li&gt;
&lt;li&gt;기본키는 인덱스라고 할 수 있을까요? 그렇지 않다면, 인덱스와 기본키는 어떤 차이가 있나요?&lt;/li&gt;
&lt;li&gt;그렇다면 외래키는요?&lt;/li&gt;
&lt;li&gt;인덱스가 데이터의 물리적 저장에도 영향을 미치나요? 그렇지 않다면, 데이터는 어떤 순서로 물리적으로 저장되나요?&lt;/li&gt;
&lt;li&gt;우리가 아는 RDB가 아닌 NoSQL (ex. Redis, MongoDB 등)는 인덱스를 갖고 있나요? 만약 있다면, RDB의 인덱스와는 어떤 차이가 있을까요?&lt;/li&gt;
&lt;li&gt;(A, B) 와 같은 방식으로 인덱스를 설정한 테이블에서, A 조건 없이 B 조건만 사용하여 쿼리를 요청했습니다. 해당 쿼리는 인덱스를 탈까요?&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;참고자료&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=liPSnc6Wzfk&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=liPSnc6Wzfk&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=liPSnc6Wzfk&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/c3h7V5/hyYPfb8m3t/KpxvAQ9Jjvn1gaCEccgxH1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;BJ.54-3 B tree가 왜 DB 인덱스(index)로 사용되는지를 설명합니다&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/liPSnc6Wzfk&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&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://github.com/VSFe/Tech-Interview/blob/main/04-DATABASE.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/VSFe/Tech-Interview/blob/main/04-DATABASE.md&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1746428898276&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Tech-Interview/04-DATABASE.md at main &amp;middot; VSFe/Tech-Interview&quot; data-og-description=&quot;Contribute to VSFe/Tech-Interview development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/VSFe/Tech-Interview/blob/main/04-DATABASE.md&quot; data-og-url=&quot;https://github.com/VSFe/Tech-Interview/blob/main/04-DATABASE.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EokxB/hyYMTBitt3/7fSLzPRTKU5MApdAZy2Bbk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bJSwVa/hyYRvS3GjA/MSoKaBcRKSO6fZQ0gAMZYk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/VSFe/Tech-Interview/blob/main/04-DATABASE.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/VSFe/Tech-Interview/blob/main/04-DATABASE.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EokxB/hyYMTBitt3/7fSLzPRTKU5MApdAZy2Bbk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bJSwVa/hyYRvS3GjA/MSoKaBcRKSO6fZQ0gAMZYk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;Tech-Interview/04-DATABASE.md at main &amp;middot; VSFe/Tech-Interview&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to VSFe/Tech-Interview development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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;</description>
      <category>CS</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/207</guid>
      <comments>https://jschoi96.tistory.com/207#entry207comment</comments>
      <pubDate>Sun, 4 May 2025 17:40:49 +0900</pubDate>
    </item>
    <item>
      <title>Upperbound , Lowerbound</title>
      <link>https://jschoi96.tistory.com/204</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2805&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2805&lt;/a&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;a href=&quot;https://www.acmicpc.net/problem/1654&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1654&lt;/a&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;a href=&quot;https://www.acmicpc.net/problem/10816&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/10816&lt;/a&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;LG CNS 사전 코딩테스트 문제를 가벼운 마음으로 풀었는데, 두번째 문제를 테스트 케이스만 통과하고 전체 히든 케이스는 다 틀렸다. 나의 접근 방법이 아예 틀렸음을 깨닫고 구글링을 해서 유형을 찾아보니 up, lb 문제와 똑같았다. 이번 기회에 다시 복습을 해야겠다고 느꼈다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;숫자카드 2&lt;/h2&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;-10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;-10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서 10의 등장 횟수를 구하려면 어떻게 해야할까? 배열을 순회하며 등장횟수를 계산해줄 수도 있지만, 더 간단하게 풀 수 있다.&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;-10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;-10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 10%;&quot;&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬을 해주면, 10이 있는 위치가 더욱 명확해진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10이 처음 등장하는 index와 10을 초과하는 index를 각각 구한 다음에, 빼주면 등장 횟수를 간단하게 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 10을 초과하는 index는 배열 길이를 넘어가기 때문에 `int hi = arr.length` 이런식으로 설정을 해야한다.&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;int k = upperbound(arr, 10) - lowerbound(arr, 10); 를 해주면 등장 횟수를 구할 수 있다.&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://st-lab.tistory.com/267&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://st-lab.tistory.com/267&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744980614441&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;[백준] 10816번 : 숫자 카드 2 - JAVA [자바]&quot; data-og-description=&quot;https://www.acmicpc.net/problem/10816 10816번: 숫자 카드 2 첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 &amp;le; N &amp;le; 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드&quot; data-og-host=&quot;st-lab.tistory.com&quot; data-og-source-url=&quot;https://st-lab.tistory.com/267&quot; data-og-url=&quot;https://st-lab.tistory.com/267&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eJ1f1/hyYHdmfP5d/G5HWz5XX3qCZS14mvLp7Z1/img.png?width=800&amp;amp;height=573&amp;amp;face=0_0_800_573,https://scrap.kakaocdn.net/dn/c3V7b4/hyYHdzKRBD/LchhyujkWlcgiDxO7INUWK/img.png?width=800&amp;amp;height=573&amp;amp;face=0_0_800_573,https://scrap.kakaocdn.net/dn/NbE44/hyYG43S7dw/BbQA4Hz1cOHr0vMkLYA85k/img.png?width=2209&amp;amp;height=1110&amp;amp;face=0_0_2209_1110&quot;&gt;&lt;a href=&quot;https://st-lab.tistory.com/267&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://st-lab.tistory.com/267&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eJ1f1/hyYHdmfP5d/G5HWz5XX3qCZS14mvLp7Z1/img.png?width=800&amp;amp;height=573&amp;amp;face=0_0_800_573,https://scrap.kakaocdn.net/dn/c3V7b4/hyYHdzKRBD/LchhyujkWlcgiDxO7INUWK/img.png?width=800&amp;amp;height=573&amp;amp;face=0_0_800_573,https://scrap.kakaocdn.net/dn/NbE44/hyYG43S7dw/BbQA4Hz1cOHr0vMkLYA85k/img.png?width=2209&amp;amp;height=1110&amp;amp;face=0_0_2209_1110');&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;[백준] 10816번 : 숫자 카드 2 - JAVA [자바]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://www.acmicpc.net/problem/10816 10816번: 숫자 카드 2 첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 &amp;le; N &amp;le; 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;st-lab.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;</description>
      <category>Algorithm/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/204</guid>
      <comments>https://jschoi96.tistory.com/204#entry204comment</comments>
      <pubDate>Fri, 18 Apr 2025 21:50:31 +0900</pubDate>
    </item>
    <item>
      <title>세 수의 합</title>
      <link>https://jschoi96.tistory.com/201</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2295&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2295&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;/h3&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;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;풀이방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int 배열에서 x + y + z = k가 존재할 때, k의 최대값을 찾는 문제다. (단, 인덱스는 중복 가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;배열을 이중 탐색하며 x + y합을 HashSet에 저장한다. 이 때 배열의 마지막 값은 저장하지 않아도 된다. (정렬이 된 경우에)&lt;/li&gt;
&lt;li&gt;x + y를 이제 알았으니 k - z를 배열을 순회하며 확인한다. 배열을 이중으로 순회하며 arr[i] - arr[j]를 하게되면 모든 k - z의 순서쌍을 구할 수 있다. 이 때, 해당 값이 set에 존재한다면 k의 최댓값을 갱신해준다. (arr[i]를 통해)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 탐색을 통해서도 값을 탐색할 수 있는데 HashSet이 더 로직을 구현하기 편했던것 같다.&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;h3 data-ke-size=&quot;size23&quot;&gt;코드&lt;/h3&gt;
&lt;pre id=&quot;code_1744721844225&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&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.Arrays;
import java.util.HashSet;
import java.util.Set;

public class boj2295 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int [] arr = new int[n];

        for (int i = 0; i &amp;lt; n; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }

        // A + B + C = K일 때 K의 최댓값을 구하는 문제

        // 1. 모든 A+B 경우의 수를 HashSet에 저장 (이 때 인덱스는 같아도 된다.

        Set&amp;lt;Integer&amp;gt; set = new HashSet&amp;lt;&amp;gt;();
        Arrays.sort(arr);

        for(int i = 0; i &amp;lt; n - 1; i++) { // 마지막 값까진 구할 필요 없음
            for(int j = 0; j &amp;lt; n - 1; j++) {
                set.add(arr[i] + arr[j]);
            }
        }

        // 2. A+B = K-C를 구해야 한다. 배열을 다시 순회하며 뺀 모든 경우의 수를 찾는다.

        int max = 0;
        for(int i = 0; i &amp;lt; n; i++) {
            for(int j = 0; j &amp;lt; n; j++) {
                int diff = arr[i] - arr[j];
                if (set.contains(diff)) { //
                    // 3. 이 때 값이 존재한다면 K값의 최댓값을 갱신해주면 됨
                    max = Math.max(max, arr[i]);
                }
            }
        }
        System.out.println(max);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/백준</category>
      <author>미네구스</author>
      <guid isPermaLink="true">https://jschoi96.tistory.com/201</guid>
      <comments>https://jschoi96.tistory.com/201#entry201comment</comments>
      <pubDate>Tue, 15 Apr 2025 21:58:22 +0900</pubDate>
    </item>
  </channel>
</rss>