<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>삼월</title>
    <link>https://marchislike.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 00:32:34 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>삼월은마치</managingEditor>
    <image>
      <title>삼월</title>
      <url>https://tistory1.daumcdn.net/tistory/5304245/attach/241305504fa04e48bd74894ff12ba2eb</url>
      <link>https://marchislike.tistory.com</link>
    </image>
    <item>
      <title>포트번호 없이 ip 만으로 접속</title>
      <link>https://marchislike.tistory.com/264</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 ip주소에 포트번호 8080까지 붙여줘야만 접속이 가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 간단히 생략하고 ip주소만으로 접속하는 방법에 대해 알아왔다.&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;iptables 설정을 초기화 하고 원하는 포트번호(ex:8080)가 기본값인 80으로 redirection되게 해 주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1730699665225&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo iptables -F -t nat
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;892&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1p1zo/btsKwmwSqPA/5A2KJau9TCD9Hn3QxOVoa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1p1zo/btsKwmwSqPA/5A2KJau9TCD9Hn3QxOVoa0/img.png&quot; data-alt=&quot;중간엔 공백 오타다. 1. 2로 표시한 부분만 보자.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1p1zo/btsKwmwSqPA/5A2KJau9TCD9Hn3QxOVoa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1p1zo%2FbtsKwmwSqPA%2F5A2KJau9TCD9Hn3QxOVoa0%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;892&quot; height=&quot;180&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;892&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중간엔 공백 오타다. 1. 2로 표시한 부분만 보자.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접속이 잘 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLNTHj/btsKvqfOXv5/KZRQ6QwM8oLGND6MOTKN71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLNTHj/btsKvqfOXv5/KZRQ6QwM8oLGND6MOTKN71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLNTHj/btsKvqfOXv5/KZRQ6QwM8oLGND6MOTKN71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLNTHj%2FbtsKvqfOXv5%2FKZRQ6QwM8oLGND6MOTKN71%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;602&quot; height=&quot;318&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 nginx로 해야하는 줄 알고 삽질했던 때가 생각난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굉장히 간단했다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://eng-sohee.tistory.com/105&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://eng-sohee.tistory.com/105&lt;/a&gt;&lt;/p&gt;</description>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/264</guid>
      <comments>https://marchislike.tistory.com/264#entry264comment</comments>
      <pubDate>Mon, 4 Nov 2024 14:59:29 +0900</pubDate>
    </item>
    <item>
      <title>[Sorting] 56. Merge Intervals</title>
      <link>https://marchislike.tistory.com/254</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/merge-intervals/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/merge-intervals/description/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given an array&amp;nbsp;of&lt;span&gt;&amp;nbsp;&lt;/span&gt;intervals&amp;nbsp;where&lt;span&gt;&amp;nbsp;&lt;/span&gt;intervals[i] = [starti, endi], merge all overlapping intervals, and return&lt;span&gt;&amp;nbsp;&lt;/span&gt;an array of the non-overlapping intervals that cover all the intervals in the input.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlap, merge them into [1,6].
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;lt;= intervals.length &amp;lt;= 104&lt;/li&gt;
&lt;li&gt;intervals[i].length == 2&lt;/li&gt;
&lt;li&gt;0 &amp;lt;= starti &amp;lt;= endi &amp;lt;= 104&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729695494893&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def merge(self, intervals: List[List[int]]) -&amp;gt; List[List[int]]:
        
        intervals.sort(key=lambda x: x[0]) #정렬기준 key를 오름차순으로 정렬 시, start=x[0]을 기준으로 함

        result = []
        if intervals:
            cur = intervals[0] #초기값 설정 ex cur = [1,3]

            for next in intervals[1:]: #start = 1부터 순차적으로 탐색

                if next[0] &amp;lt;= cur[1]:
                    cur[1] = max(cur[1], next[1]) #병합
                else:
                    result.append(cur) #그냥 추가
                    cur = next #다음 [start, end]요소 받기
            result.append(cur) #순차적으로 next를 result에 추가
        
        return result&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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에 대해 x[0]=start를 기준으로 오름차순 정렬하겠다.&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;pre id=&quot;code_1729694986776&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;intervals.sort(key=lambda x: x[0])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내림차순&lt;/p&gt;
&lt;pre id=&quot;code_1729694977397&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;intervals.sort(key=lambda x: x[0], reverse=True)&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;x[1] 인 end를 기준으로 정렬할 시 다음과 같이 될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uL7as/btsKgNvzGvR/KKdbaXNbYL3U0c0oFYOzV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uL7as/btsKgNvzGvR/KKdbaXNbYL3U0c0oFYOzV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uL7as/btsKgNvzGvR/KKdbaXNbYL3U0c0oFYOzV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuL7as%2FbtsKgNvzGvR%2FKKdbaXNbYL3U0c0oFYOzV1%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;615&quot; height=&quot;253&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cur : list내에서 현재 가리키고 있는 [start, end] 요소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next : 다음 [start, end] 요소&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>SW 정글/운영체제</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/254</guid>
      <comments>https://marchislike.tistory.com/254#entry254comment</comments>
      <pubDate>Thu, 24 Oct 2024 00:13:27 +0900</pubDate>
    </item>
    <item>
      <title>[Two Pointer] 392. Is Subsequence</title>
      <link>https://marchislike.tistory.com/253</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/contest/leetcode-weekly-contest-3/problems/is-subsequence/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/contest/leetcode-weekly-contest-3/problems/is-subsequence/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given two strings&lt;span&gt;&amp;nbsp;&lt;/span&gt;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;t, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;true&lt;span&gt;&amp;nbsp;&lt;/span&gt;if&lt;span&gt;&amp;nbsp;&lt;/span&gt;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;subsequence&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;of&lt;span&gt;&amp;nbsp;&lt;/span&gt;t, or&lt;span&gt;&amp;nbsp;&lt;/span&gt;false&lt;span&gt;&amp;nbsp;&lt;/span&gt;otherwise.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;A&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;subsequence&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e.,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;ace&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a subsequence of&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;&lt;u&gt;a&lt;/u&gt;b&lt;u&gt;c&lt;/u&gt;d&lt;u&gt;e&lt;/u&gt;&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;while&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;aec&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is not).&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;groovy&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: start;&quot;&gt;&lt;code&gt;Input: s = &quot;abc&quot;, t = &quot;ahbgdc&quot;
Output: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;groovy&quot; style=&quot;background-color: #f5f5f5; color: #333333; text-align: start;&quot;&gt;&lt;code&gt;Input: s = &quot;axc&quot;, t = &quot;ahbgdc&quot;
Output: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0 &amp;lt;= s.length &amp;lt;= 100&lt;/li&gt;
&lt;li&gt;0 &amp;lt;= t.length &amp;lt;= 104&lt;/li&gt;
&lt;li&gt;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;t&lt;span&gt;&amp;nbsp;&lt;/span&gt;consist only of lowercase English letters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729689977279&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def isSubsequence(self, s: str, t: str) -&amp;gt; bool:
        #s를 split 후 t를 앞에서부터 순회하면서 찾다가 일치하면 다음 탐색 (대신 인덱스도 위치도 동일하게)
        
        i, j = 0, 0 #포인터 초기화
        
        while i &amp;lt; len(s) and j &amp;lt; len(t):
            if s[i] == t[j]:
                i += 1
            j += 1
                
        #true, false만 반환하므로 i가 전체 s의 길이와 동일할 때까지 증가하면 모두 찾았다는 의미
        return i == len(s) #True&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729689320207&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while i &amp;lt; len(s) and j &amp;lt; len(t):&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. s의 길이가 남아있는 동안만 t를 순회하도록 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;pre id=&quot;code_1729689384578&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;            if s[i] == t[j]:
                i += 1
            j += 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 일치할 경우 둘다 인덱스 +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;zwj; j 인덱스를 증가시키는 로직을 i의 증가 로직과 다른 들여쓰기 수준에서 진행하는 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. i 인덱스 관리&lt;/b&gt;: i 인덱스는 문자열 s의 문자가 문자열 t에서 일치할 때만 증가한다. 문자열 s의 다음 문자를 찾기 위해 t에서 계속 탐색을 진행해야 함을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. j 인덱스 관리&lt;/b&gt;: j는 문자열 t를 순회하는 인덱스로서, 문자열 t의 모든 문자를 확인하면서 s의 문자와 일치하는지 여부를 각 위치에서 검사하는데,&lt;u&gt; j 인덱스의 증가는 조건과 무관하게 항상 일어나야 한다. &lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 if 문의 외부에서 처리되어 t의 각 문자를 확인할 때마다 j가 무조건 1씩 증가해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SW 정글/알고리즘</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/253</guid>
      <comments>https://marchislike.tistory.com/253#entry253comment</comments>
      <pubDate>Wed, 23 Oct 2024 22:26:32 +0900</pubDate>
    </item>
    <item>
      <title>[stack] 20. Valid Parentheses</title>
      <link>https://marchislike.tistory.com/252</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/valid-parentheses/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/valid-parentheses/description/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given a string&lt;span&gt;&amp;nbsp;&lt;/span&gt;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;containing just the characters&lt;span&gt;&amp;nbsp;&lt;/span&gt;'(',&lt;span&gt;&amp;nbsp;&lt;/span&gt;')',&lt;span&gt;&amp;nbsp;&lt;/span&gt;'{',&lt;span&gt;&amp;nbsp;&lt;/span&gt;'}',&lt;span&gt;&amp;nbsp;&lt;/span&gt;'['&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;']', determine if the input string is valid.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;An input string is valid if:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Open brackets must be closed by the same type of brackets.&lt;/li&gt;
&lt;li&gt;Open brackets must be closed in the correct order.&lt;/li&gt;
&lt;li&gt;Every close bracket has a corresponding open bracket of the same type.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;s = &quot;()&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;s = &quot;()[]{}&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 3:&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;s = &quot;(]&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 4:&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;s = &quot;([])&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;lt;= s.length &amp;lt;= 104&lt;/li&gt;
&lt;li&gt;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;consists of parentheses only&lt;span&gt;&amp;nbsp;&lt;/span&gt;'()[]{}'.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유효한 괄호로 이루어져있는지 판별하는 문제&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1729668964647&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def isValid(self, s: str) -&amp;gt; bool:
        stack = []
        bracket_map = {')': '(', '}': '{', ']':'['}

        for brkt in s:
            if brkt in bracket_map.values(): # 열린 괄호(value)
                stack.append(brkt)

            elif brkt in bracket_map: #닫힌 괄호(key)
            # stack이 비어있거나
            #해당 닫힌 괄호를 key로 삼아 조회했을 때 기존 스택에 매칭되는 value(=열린괄호)가 없다면
                if not stack or stack.pop() != bracket_map[brkt]: 
                    return False
        
        return not stack #모든 괄호가 정상적으로 닫히면 스택이 비워지므로
        # not stack이 맞으면 True, 아니면 False&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 짝을 지어서 dictionary로 저장해 두면 편하다니&lt;/p&gt;
&lt;pre id=&quot;code_1729668181179&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  # 각 괄호의 짝을 딕셔너리로 표현
        bracket_map = {')': '(', '}': '{', ']': '['}&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;닫힌 괄호를 key로, 열린 괄호를 value로 사용하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열린 괄호는 생길 때마다 push되고, 닫힌 괄호를 만날 때 pop을 하는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pop을 하는 순간에 stack에 닫힌 괄호 key의 타입에 맞는 열린 괄호가 존재하지 않는 경우 False를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1729668565734&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;elif char in bracket_map:
                # 스택이 비어있거나 스택의 마지막 원소와 짝이 맞지 않는 경우
                if not stack or stack.pop() != bracket_map[char]:
                    return False&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력은 True, False로 받아야 하므로, not stack에 대해 맞다면 True, 스택이 비워지지 않아 not stack이 아니라면 False&lt;/p&gt;</description>
      <category>SW 정글/알고리즘</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/252</guid>
      <comments>https://marchislike.tistory.com/252#entry252comment</comments>
      <pubDate>Wed, 23 Oct 2024 16:46:05 +0900</pubDate>
    </item>
    <item>
      <title>[String] 14. Longest Common Prefix / startswith() 함수</title>
      <link>https://marchislike.tistory.com/251</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/longest-common-prefix/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/longest-common-prefix/description/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Write a function to find the longest common prefix string amongst an array of strings.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;If there is no common prefix, return an empty string&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;&quot;.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: strs = [&quot;flower&quot;,&quot;flow&quot;,&quot;flight&quot;]
Output: &quot;fl&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: strs = [&quot;dog&quot;,&quot;racecar&quot;,&quot;car&quot;]
Output: &quot;&quot;
Explanation: There is no common prefix among the input strings.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;lt;= strs.length &amp;lt;= 200&lt;/li&gt;
&lt;li&gt;0 &amp;lt;= strs[i].length &amp;lt;= 200&lt;/li&gt;
&lt;li&gt;strs[i]&lt;span&gt;&amp;nbsp;&lt;/span&gt;consists of only lowercase English letters.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;startswith()&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접두어, 접미어를 파악하기 위해 파이썬에서 제공되는 startwith(), endwith()를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 함수를 사용할 경우 접두(미)어를 쉽게 찾을 수 있으며 dictionary 타입에서도 사용 가능&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_1729662508982&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sentence = &quot;girl's generation&quot;

result = sentence.startswith('girl')
print(result)

# 출력결과: True&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;endswith()&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729662668925&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;idol = [
    &quot;girl's generation&quot;,
    &quot;black pink&quot;,
    &quot;A-pink&quot;,
    &quot;aespa&quot;
]

for i in idol:
    # 문자열을 소문자로 변환한 후, 'pink'로 끝나는지 확인
    if i.lower().endswith('pink'):
        print(i)  # 문자열 출력
    else:
        print(&quot;&quot;)  # 빈 문자열 출력
        
#출력결과
#black pink
#A-pink&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729665003772&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def longestCommonPrefix(self, strs: List[str]) -&amp;gt; str:
        if not strs:
            return &quot;&quot; #빈 리스트 입력 시 빈 문자열 반환
        
        short_str = min(strs, key=len) # 사전순이 아닌 문자열 길이로 최소값 찾기
        for i in range(len(short_str)): # 가장 짧은 문자열 기준으로
            for s in strs: # 기존 strs 리스트 내 요소들과 비교
                if s[i] != short_str[i]: # 더이상 일치하는 문자가 없으면
                    return short_str[:i] # i-1번째까지 문자열 출력
        
        return short_str #모든 문자열이 공통 접두어일 경우&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for문으로 문자열을 하나하나 돌면서 비교하거나 &quot;가장 짧은 문자열&quot;로 비교하면 효율적이다.&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;+) 빈 문자열이 입력으로 주어진 경우에도 &quot;&quot;로 처리해야 한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 공통 접두사어가 없으면 &quot;&quot;로 반환하는 것만 생각했었기에 처음엔 떠오르지 않았다.&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;가장 짧은 문자열을 기준으로 비교하므로, strs 리스트 내의 요소 s도 인덱스를 i까지만 돌면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서부터 i-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;*슬라이스 범위&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;start&lt;/b&gt;: 슬라이스의 &lt;b&gt;시작 인덱스&lt;/b&gt; (포함).
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생략하면 &lt;b&gt;0&lt;/b&gt;으로 간주&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;end&lt;/b&gt;: 슬라이스의 &lt;b&gt;종료 인덱스&lt;/b&gt; (미포함).
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인덱스 end에 해당하는 문자는 포함되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;step&lt;/b&gt;: 문자열을 몇 칸씩 건너뛸지를 지정합니다. 기본값은 1&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729664935405&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def longestCommonPrefix(self, strs: List[str]) -&amp;gt; str:
        if not strs:
            return &quot;&quot; #빈 리스트 입력 시 빈 문자열 반환
        
        short_str = min(strs, key=len) # 사전순이 아닌 문자열 길이로 최소값 찾기
        for i in range(len(short_str)): # 가장 짧은 문자열 기준으로
            for s in strs: # 기존 strs 리스트 내 요소들과 비교
                if s[i] != short_str[i]: # 더이상 일치하는 문자가 없으면
                    return short_str[:i] # i-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;여기까지만 구현했을 경우, 가장 짧은 문자열이 다른 문자열들과 비교했을 때 전체가 공통 접두어가 될 경우에 대한 결과가 빠져있으므로 short_str 자체를 리턴하는 부분도 넣어야 한다.&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;zwj;  &lt;span style=&quot;color: #262626; text-align: start;&quot;&gt;&lt;b&gt;[&quot;dog&quot;,&quot;racecar&quot;,&quot;car&quot;] 처럼 공통접두어가 존재하지 않는 경우&lt;/b&gt;에 대한 처리는 어디서?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729665219991&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for i in range(len(short_str)): # 가장 짧은 문자열 기준으로
            for s in strs: # 기존 strs 리스트 내 요소들과 비교
                if s[i] != short_str[i]: # 더이상 일치하는 문자가 없으면
                    return short_str[:i] # i-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;해당 for문 안에서 슬라이싱 문법으로 i-1번째까지 출력이므로, 공통 접두어가 없을 경우 자연스럽게 끝나고 &quot;&quot; 빈 문자열을 반환하게 된다.&lt;/p&gt;</description>
      <category>SW 정글/알고리즘</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/251</guid>
      <comments>https://marchislike.tistory.com/251#entry251comment</comments>
      <pubDate>Wed, 23 Oct 2024 15:34:48 +0900</pubDate>
    </item>
    <item>
      <title>[String] 412. Fizz Buzz</title>
      <link>https://marchislike.tistory.com/250</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/fizz-buzz/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/fizz-buzz/description/&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given an integer&lt;span&gt;&amp;nbsp;&lt;/span&gt;n, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;a string array&lt;span&gt;&amp;nbsp;&lt;/span&gt;answer&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;b&gt;1-indexed&lt;/b&gt;) where:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;answer[i] == &quot;FizzBuzz&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;if&lt;span&gt;&amp;nbsp;&lt;/span&gt;i&lt;span&gt;&amp;nbsp;&lt;/span&gt;is divisible by&lt;span&gt;&amp;nbsp;&lt;/span&gt;3&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;5.&lt;/li&gt;
&lt;li&gt;answer[i] == &quot;Fizz&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;if&lt;span&gt;&amp;nbsp;&lt;/span&gt;i&lt;span&gt;&amp;nbsp;&lt;/span&gt;is divisible by&lt;span&gt;&amp;nbsp;&lt;/span&gt;3.&lt;/li&gt;
&lt;li&gt;answer[i] == &quot;Buzz&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;if&lt;span&gt;&amp;nbsp;&lt;/span&gt;i&lt;span&gt;&amp;nbsp;&lt;/span&gt;is divisible by&lt;span&gt;&amp;nbsp;&lt;/span&gt;5.&lt;/li&gt;
&lt;li&gt;answer[i] == i&lt;span&gt;&amp;nbsp;&lt;/span&gt;(as a string) if none of the above conditions are true.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;1부터 n까지의 숫자를 순서대로 출력합니다.&lt;/li&gt;
&lt;li&gt;각 숫자에 대해 다음 규칙을 따릅니다:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;숫자가 3의 배수&lt;/b&gt;일 경우: &quot;Fizz&quot; 출력&lt;/li&gt;
&lt;li&gt;&lt;b&gt;숫자가 5의 배수&lt;/b&gt;일 경우: &quot;Buzz&quot; 출력&lt;/li&gt;
&lt;li&gt;&lt;b&gt;숫자가 3과 5의 공배수&lt;/b&gt;(15의 배수)일 경우: &quot;FizzBuzz&quot; 출력&lt;/li&gt;
&lt;li&gt;&lt;b&gt;위 조건에 해당하지 않는 숫자&lt;/b&gt;일 경우: 숫자 그대로 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3,6,9게임이 떠오르는 문제&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;수가 3, 6, 9가 들어가면 박수를 치고 33이면 박수를 두 번 쳐야 하니까&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1729660423248&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def fizzBuzz(self, n: int) -&amp;gt; List[str]:
        result = []
        for i in range(1, n+1):
            if i % 15 == 0:
                result.append(&quot;FizzBuzz&quot;)
            elif i % 5 == 0:
                result.append(&quot;Buzz&quot;)
            elif i % 3 == 0:
                result.append(&quot;Fizz&quot;)
            else:
                result.append(str(i)) # int -&amp;gt; str
        
        return result&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;빈 리스트 result [] 를 만들고 for문을 돌면서 하나하나 추가해 주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E1cFW/btsKfqgBgli/dd0B5WoCBzJUoOn8DDdg20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E1cFW/btsKfqgBgli/dd0B5WoCBzJUoOn8DDdg20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E1cFW/btsKfqgBgli/dd0B5WoCBzJUoOn8DDdg20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE1cFW%2FbtsKfqgBgli%2Fdd0B5WoCBzJUoOn8DDdg20%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;623&quot; height=&quot;442&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>SW 정글/알고리즘</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/250</guid>
      <comments>https://marchislike.tistory.com/250#entry250comment</comments>
      <pubDate>Wed, 23 Oct 2024 14:14:43 +0900</pubDate>
    </item>
    <item>
      <title>[math] 7. Reverse Integer</title>
      <link>https://marchislike.tistory.com/249</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/reverse-integer/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/reverse-integer/description/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given a signed 32-bit integer&lt;span&gt;&amp;nbsp;&lt;/span&gt;x, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;x&lt;span&gt;&amp;nbsp;&lt;/span&gt;with its digits reversed. If reversing&lt;span&gt;&amp;nbsp;&lt;/span&gt;x&lt;span&gt;&amp;nbsp;&lt;/span&gt;causes the value to go outside the signed 32-bit integer range&lt;span&gt;&amp;nbsp;&lt;/span&gt;[-231, 231 - 1], then return&lt;span&gt;&amp;nbsp;&lt;/span&gt;0.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Assume the environment does not allow you to store 64-bit integers (signed or unsigned).&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: x = 123
Output: 321
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: x = -123
Output: -321
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 3:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: x = 120
Output: 21
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-231 &amp;lt;= x &amp;lt;= 231 - 1&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729658620496&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def reverse(self, x: int) -&amp;gt; int:
        
        sign = -1 if x &amp;lt; 0 else 1
        
        reverse_num = str(abs(x))[::-1]
        
        result = sign * int(reverse_num)

        if result &amp;lt; -2**31 or 2**31 &amp;lt; result:
            return 0

        return result&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;a href=&quot;https://marchislike.tistory.com/248&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://marchislike.tistory.com/248&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⬆️앞서 적용했던 슬라이싱 방법을 사용하면 간단할 것 같은데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 example3을 보았을 때, 변환한 뒤 앞자리에 0이 존재한다면 0을 제거해야 하는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 찾아보니 파이썬에서 문자열을 int형으로 변환하면 자동으로 0이 제거된다고 한다..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 처음에 무지성으로 이렇게 구현을 해서 돌렸다가..&lt;/p&gt;
&lt;pre id=&quot;code_1729656490521&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def reverse(self, x: int) -&amp;gt; int:
        return int(str(x)[::-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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-123을 입력하면 321- 가 아니라 -321이 나와야 한다.&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;그래서 reverse num을 저장한 후 해당 reverse num에 대해 다시 부호를 처리해 줘야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1729658265083&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sign = -1 if x &amp;lt; 0 else 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x가 음수라면 sign = -1 을 넣어줘서 나중에 reverse_num에 곱해서 음수로 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값은 절대값으로 받아야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int x에 대해 절대값 abs()으로 받은 후 str으로 형변환하여 슬라이싱을 사용할 수 있도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1729658526377&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;reverse_num = str(abs(x))[::-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;&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;최종 값에 대해 다시 int형으로 변환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1729658578133&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;result = sign * int(reverse_num)&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;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; &lt;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;If reversing&lt;/span&gt;&lt;span style=&quot;color: #262626; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color: #262626; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;causes the value to go outside the signed 32-bit integer range&lt;/span&gt;&lt;span style=&quot;color: #262626; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;[-231, 231 - 1], then return&lt;/span&gt;&lt;span style=&quot;color: #262626; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;0.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729658954164&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if result &amp;lt; -2**31 or 2**31 &amp;lt; result:
	return 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SW 정글/알고리즘</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/249</guid>
      <comments>https://marchislike.tistory.com/249#entry249comment</comments>
      <pubDate>Wed, 23 Oct 2024 13:53:08 +0900</pubDate>
    </item>
    <item>
      <title>[math] 9. Palindrome-number</title>
      <link>https://marchislike.tistory.com/248</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/palindrome-number/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/palindrome-number/description/&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;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;Given an integer&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;x&lt;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;true&lt;span&gt;&amp;nbsp;&lt;/span&gt;if&lt;span&gt;&amp;nbsp;&lt;/span&gt;x&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a&lt;span&gt; &lt;/span&gt;&lt;b&gt;palindrome&lt;/b&gt;&lt;span style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot; data-keyword=&quot;palindrome-integer&quot;&gt;&lt;/span&gt;, and&lt;span&gt;&amp;nbsp;&lt;/span&gt;false&lt;span&gt;&amp;nbsp;&lt;/span&gt;otherwise&lt;span style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vim&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: x = 121
Output: true
Explanation: 121 reads as 121 from left to right and from right to left.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: x = -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 3:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: x = 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-231&amp;nbsp;&amp;lt;= x &amp;lt;= 231&amp;nbsp;- 1&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Solution&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729654843274&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def isPalindrome(self, x: int) -&amp;gt; bool:
        return False if x &amp;lt; 0 else x == int(str(x)[::-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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 한 자리수일 때는 true, 두 자리면 같아야만 true, 이후 mid를 기준으로 left/right 자르는 방법을 생각했는데&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;슬라이싱[::]을 사용해서 기존 x 값과 reverse값이 같은지 비교하면 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이싱은 [start:end:step] 순서로, step에 -1을 넣으면 역순으로 str을 변환하니 유용하다.&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;&quot;순서가 존재하는 연속된 시퀀스형만&quot;&lt;/b&gt; 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;문자열 (str)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리스트 (list)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;튜플 (tuple)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;범위 (range)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 int형으로 주어진 x에 대해 str으로 적용한 다음 다시 int 형변환이 필요하다.&lt;/p&gt;
&lt;pre id=&quot;code_1729655261624&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int(str(x)[::-1])&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dejYFb/btsKf9Y5doR/c78tJYOzf0tOkLiAVriWPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dejYFb/btsKf9Y5doR/c78tJYOzf0tOkLiAVriWPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dejYFb/btsKf9Y5doR/c78tJYOzf0tOkLiAVriWPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdejYFb%2FbtsKf9Y5doR%2Fc78tJYOzf0tOkLiAVriWPk%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;454&quot; height=&quot;377&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;752&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;reference&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;a href=&quot;https://oneteveryday.tistory.com/224&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://oneteveryday.tistory.com/224&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SW 정글/알고리즘</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/248</guid>
      <comments>https://marchislike.tistory.com/248#entry248comment</comments>
      <pubDate>Wed, 23 Oct 2024 12:49:38 +0900</pubDate>
    </item>
    <item>
      <title>[hash] 1. two-sum</title>
      <link>https://marchislike.tistory.com/247</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/two-sum/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/two-sum/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given an array of integers&lt;span&gt;&amp;nbsp;&lt;/span&gt;nums&amp;nbsp;and an integer&lt;span&gt;&amp;nbsp;&lt;/span&gt;target, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;indices of the two numbers such that they add up to&lt;span&gt;&amp;nbsp;&lt;/span&gt;target.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;You may assume that each input would have&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;exactly&lt;span&gt;&amp;nbsp;&lt;/span&gt;one solution&lt;/b&gt;, and you may not use the&lt;span&gt;&amp;nbsp;&lt;/span&gt;same&lt;span&gt;&amp;nbsp;&lt;/span&gt;element twice.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;You can return the answer in any order.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: nums = [3,2,4], target = 6
Output: [1,2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 3:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: nums = [3,3], target = 6
Output: [0,1]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1729610159614&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution:
    def twoSum(self, nums, target):
        num_dict = {}  # 해시 테이블 초기화

        for i, num in enumerate(nums):  # 인덱스와 값을 동시에 얻음
            comp = target - num  # 보수 계산 (complement)
            
            if comp in num_dict:  # 보수가 해시 테이블에 있는지 확인
                return [num_dict[comp], i]  # 보수와 현재 숫자의 인덱스를 반환
            
            num_dict[num] = i  # 현재 숫자와 인덱스를 해시 테이블에 저장

        return []  # 해결할 수 없는 경우 빈 리스트 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;zwj;  return [num_dict[comp], i]&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;보수 comp가 해시테이블 num_dict 안에 존재한다면, 리스트[]를 리턴하는데, 두 가지를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;num_dict[comp]와 i 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;num_dict[comp]는 target에서 i번째 인덱스의 값에 해당하는 요소를 뺀 값을 지닌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹여 해당하는 수 조합이 없다면 마지막 return은 [] 빈 리스트로 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729610064780&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if comp in num_dict:
    return [num_dict[comp], i]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;**comp(보수)**가 &lt;b&gt;해시 테이블(num_dict)에 존재하는지&lt;/b&gt; 확인. &lt;b&gt;있다면&lt;/b&gt;, 해당 보수의 인덱스와 현재 인덱스 i를 리스트로 반환&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, 7, 11, 15]이고 target이 9일 때:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;첫 번째 숫자 2에서 &lt;b&gt;보수&lt;/b&gt;는 9 - 2 = 7 이다.&lt;/li&gt;
&lt;li&gt;두 번째 숫자 7을 만났을 때, comp(보수)인 2가 &lt;b&gt;이미 해시 테이블에 존재&lt;/b&gt;한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때 해시 테이블에 저장된 2의 인덱스는 0이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;따라서 [0, 1]을 반환한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729609759855&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nums = [2, 7, 11, 15]
target = 9
numMap = {2: 0, 7: 1}  # 딕셔너리 상태

complement = 2  # target - nums[i] = 9 - 7 = 2
print(numMap[complement])  # 출력: 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729609990447&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;numMap[complement] = 0  # 보수의 인덱스
i = 1  # 현재 숫자의 인덱스

print([numMap[complement], i])  # 출력: [0, 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;&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;nums = &lt;span style=&quot;color: #262626; text-align: start;&quot;&gt;[2,7,11,15] / target = 9&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729609921096&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Index: 0, Value: 2
Index: 1, Value: 7
Index: 2, Value: 11
Index: 3, Value: 15&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_1729611112840&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;num_dict[2] = 0  # 숫자 2의 인덱스는 0
print(num_dict[2])  # 출력: 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SW 정글/알고리즘</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/247</guid>
      <comments>https://marchislike.tistory.com/247#entry247comment</comments>
      <pubDate>Wed, 23 Oct 2024 11:13:36 +0900</pubDate>
    </item>
    <item>
      <title>[PintOS] WIL (4) 난 이해를 한 걸까..?</title>
      <link>https://marchislike.tistory.com/245</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 swap disk와 copy on write에 대해 무지성으로 작성되었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Copy On Write&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;현재까지는 fork할 때 메모리가 할당된 page에 대해서 부모에서 자식으로 복사할 때 같은 내용의 물리메모리를 자식에게도 할당 해주었다. 같은 메모리가 두 번 복사되기에 메모리 낭비로 볼 수도 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;cow는 fork시에는 부모와 자식이 동일한 물리 메모리를 가리키게 하고&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;해당 페이지에 write 요청이 발생해야 새로운 물리메모리를 할당해 주도록 수정한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;fork 시 물리메모리를 모두 복사하지 않고 부모와 같은 물리메모리를 공유하다가 write작업 시 해당 페이지의 물리메모리를 새로 맵핑한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;부모와 자식 프로세스는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;쓰기 작업 이후에&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;서로 다른 메모리 프레임을 가지게 되어, 쓰기 작업이 서로에게 영향을 주지 않&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;** 페이지를 만들 때부터 쓰려고 하면 page fault가 나도록 해야 함&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기부터는 수정이 있었던 파일 일부에 대해 간략히 메모하고 지나가겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. thread.h 수정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729522711889&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#ifdef VM
    /* Table for whole virtual memory owned by thread. */
    struct supplemental_page_table spt;
    void *rsp;
    void* stack_bottom;
#endif&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 스레드마다 보조 페이지 테이블(supplemental_page_table)을 추가하여 가상 메모리를 관리&lt;/li&gt;
&lt;li&gt;rsp는 현재 스레드의 스택 포인터를 저장하며, 커널 모드와 유저 모드 전환 시 사용&lt;/li&gt;
&lt;li&gt;stack_bottom은 현재 스레드의 스택의 바닥 주소를 나타내며, 스택 확장 시 사용&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;&lt;b&gt;2. anon.h&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729522753245&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#ifndef VM_ANON_H
#define VM_ANON_H
#include &quot;vm/vm.h&quot;

#define SECTOR_SIZE 512 // 추가된 부분

struct page;
enum vm_type;

struct anon_page {
    int bit_idx; // 추가된 부분: 스왑 공간에서의 비트맵 인덱스를 저장
};

void vm_anon_init (void);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;SECTOR_SIZE를 정의하여 디스크 섹터의 크기를 지정&lt;/li&gt;
&lt;li&gt;anon_page 구조체에 bit_idx를 추가하여 페이지가 스왑 디스크의 어느 위치에 저장되었는지 추적&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. file.h&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729522814214&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum vm_type;

struct file_page {
    struct file *file;
    off_t ofs;
    void *file_start_page;
    void *file_end_page;
    size_t page_read_bytes;
    size_t page_zero_bytes;
};

void vm_file_init (void);&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;file_page 구조체를 정의하여 파일 기반 페이지에 필요한 정보를 저장&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;file: 해당 페이지가 속한 파일을 가리킨다.&lt;/li&gt;
&lt;li&gt;ofs: 파일 내에서의 오프셋&lt;/li&gt;
&lt;li&gt;file_start_page, file_end_page: 메모리 매핑된 파일의 시작과 끝 페이지 주소&lt;/li&gt;
&lt;li&gt;page_read_bytes: 페이지에서 읽어야 할 바이트 수&lt;/li&gt;
&lt;li&gt;page_zero_bytes: 페이지에서 0으로 채워야 할 바이트 수&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;&lt;b&gt;4. vm.h (1)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729522848960&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct frame {
    void *kva;
    struct page *page;
    struct list_elem frame_elem; // 추가된 부분: 프레임 테이블 관리를 위한 리스트 요소
};

struct page {
    struct frame *frame;   /* Back reference for frame */

    /* Your implementation */
    struct hash_elem page_elem; /* 해시 테이블 요소 */
    bool is_writable;
    int bit_idx; // 스왑 비트맵 인덱스

    union {
        struct uninit_page uninit;
        struct anon_page anon;
        struct file_page file;
    #ifdef EFILESYS
        struct page_cache page_cache;
    #endif
    };
};&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;frame 구조체에 frame_elem을 추가하여 프레임 테이블을 리스트로 관리&lt;/li&gt;
&lt;li&gt;page 구조체에 page_elem을 추가하여 보조 페이지 테이블에서 페이지를 해시 테이블로 관리&lt;/li&gt;
&lt;li&gt;is_writable: 페이지의 쓰기 가능 여부를 나타냄&lt;/li&gt;
&lt;li&gt;bit_idx: 스왑 공간에서의 인덱스를 저장하여 스왑 인/아웃 시 사용&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;&lt;b&gt;5. vm.h(2)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729522902749&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// for aux
struct load_info{
    struct file *file;
    size_t page_read_bytes;
    size_t page_zero_bytes;
    off_t ofs;
    bool writable;
    size_t file_start_page;
    size_t file_end_page;
};&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;load_info 구조체를 정의하여 지연 로딩(lazy loading) 시 필요한 정보를 저장&lt;/li&gt;
&lt;li&gt;aux로 전달되어 페이지를 초기화할 때 사용&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. process.c (1)&lt;/p&gt;
&lt;pre id=&quot;code_1729522969082&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int process_wait(tid_t child_tid UNUSED)
{
    struct thread *child = get_child_process(child_tid);
    if (child == NULL)
        return -1;

    sema_down(&amp;amp;child-&amp;gt;wait_sema);
    list_remove(&amp;amp;child-&amp;gt;child_elem);
    int result = child-&amp;gt;exit_status;
    sema_up(&amp;amp;child-&amp;gt;exit_sema);

    return result; // 변경된 부분: result를 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;process_wait 함수에서 child-&amp;gt;exit_status 대신 result 변수를 반환하도록 수정&lt;/li&gt;
&lt;li&gt;이는 child-&amp;gt;exit_status가 sema_up 이후에 변경될 수 있으므로, 미리 값을 저장해 두기 위함&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. process.c (2)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729522934174&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void process_exit(void)
{
    struct thread *cur = thread_current();

    // FDT의 모든 파일을 닫는다.
    for (int i = 2; i &amp;lt; FDT_COUNT_LIMIT; i++) {
        process_close_file(i);
    }
    palloc_free_multiple(cur-&amp;gt;fdt, FDT_PAGES);

    // 현재 실행 중인 파일도 닫는다.
    file_close(cur-&amp;gt;running); 
    process_cleanup();

    // 부모에게 종료를 알린다.
    sema_up(&amp;amp;cur-&amp;gt;wait_sema);

    // 부모의 signal을 기다린다.
    sema_down(&amp;amp;cur-&amp;gt;exit_sema);

    // 추가된 부분: 보조 페이지 테이블 해시 제거
    hash_destroy(&amp;amp;cur-&amp;gt;spt.pages, page_dealloc);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;/li&gt;
&lt;li&gt;hash_destroy와 page_dealloc을 사용하여 페이지를 해제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8. lazy_load_segment에서 file seek 추가 및 aux 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729523003866&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct load_info *info = (struct load_info *)aux;
uint8_t *kpage = page-&amp;gt;frame-&amp;gt;kva;

file_seek(info-&amp;gt;file, info-&amp;gt;ofs);
if (file_read(info-&amp;gt;file, kpage, info-&amp;gt;page_read_bytes) != (int)info-&amp;gt;page_read_bytes){
    palloc_free_page(kpage);
    free(aux);
    return false;
}
memset(kpage + info-&amp;gt;page_read_bytes, 0, info-&amp;gt;page_zero_bytes);

free(aux);

return true;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lazy_load_segment 함수에서 file_seek을 사용하여 파일의 정확한 위치에서 읽음&lt;/li&gt;
&lt;li&gt;aux로 전달된 load_info 구조체를 사용하여 필요한 정보를 가져옴&lt;/li&gt;
&lt;li&gt;페이지를 메모리에 로드한 후 aux를 해제&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;&lt;b&gt;9. load_segment 함수 수정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729523042150&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool load_segment(struct file *file, off_t ofs, uint8_t *upage,
                 uint32_t read_bytes, uint32_t zero_bytes, bool writable)
{
    ASSERT((read_bytes + zero_bytes) % PGSIZE == 0);
    ASSERT(pg_ofs(upage) == 0);
    ASSERT(ofs % PGSIZE == 0);

    file_seek (file, ofs);
    while (read_bytes &amp;gt; 0 || zero_bytes &amp;gt; 0)
    {
        size_t page_read_bytes = read_bytes &amp;lt; PGSIZE ? read_bytes : PGSIZE;
        size_t page_zero_bytes = PGSIZE - page_read_bytes;

        struct load_info *aux = (struct load_info  *)malloc(sizeof(struct load_info));
        if(aux == NULL)	
            return false;
        memset(aux, 0, sizeof(struct load_info));
        aux-&amp;gt;file = file;
        aux-&amp;gt;page_read_bytes = page_read_bytes;
        aux-&amp;gt;page_zero_bytes = page_zero_bytes;
        aux-&amp;gt;writable = writable;
        aux-&amp;gt;ofs = ofs;

        if (!vm_alloc_page_with_initializer(VM_ANON, upage, writable, lazy_load_segment, aux))
            return false;

        read_bytes -= page_read_bytes;
        zero_bytes -= page_zero_bytes;
        upage += PGSIZE;
        ofs += page_read_bytes;
    }
    return true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;aux로 load_info 구조체를 만들어 지연 로딩에 필요한 정보를 전달&lt;/li&gt;
&lt;li&gt;file_seek을 통해 파일의 오프셋을 설정&lt;/li&gt;
&lt;li&gt;vm_alloc_page_with_initializer를 사용하여 페이지를 할당하고 초기화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;10. setup_stack 함수 수정 &lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729523135179&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static bool setup_stack(struct intr_frame *if_)
{
    bool success = false;
    void *stack_bottom = (void *)(((uint8_t *)USER_STACK) - PGSIZE);

    if(vm_alloc_page(VM_ANON | VM_MARKER_0, stack_bottom, 1)){
        success = vm_claim_page(stack_bottom);
        if(success){
            if_-&amp;gt;rsp = USER_STACK;
            thread_current()-&amp;gt;stack_bottom = stack_bottom;
        }
    }
    return success;
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스택을 초기화할 때 페이지를 할당하고 즉시 클레임(claim)&lt;/li&gt;
&lt;li&gt;stack_bottom을 thread_current()에 저장하여 이후 스택 확장 시 사용&lt;/li&gt;
&lt;li&gt;유저 스택의 최상단 주소를 if_-&amp;gt;rsp에 설정&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;&lt;b&gt;11. anon.c에서 swap in/out 구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729523162714&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static bool anon_swap_in (struct page *page, void *kva) {
    struct anon_page *anon_page = &amp;amp;page-&amp;gt;anon;
    
    int idx = anon_page-&amp;gt;bit_idx;
    if(idx &amp;lt; 0) {
        return false;
    }
    
    for (int i = 0; i &amp;lt; 8; i++) {
        disk_sector_t sec_no = (disk_sector_t) idx*8 + i;
        disk_read(swap_disk, sec_no, kva + SECTOR_SIZE * i);
    }

    anon_page-&amp;gt;bit_idx = -1;
    bitmap_flip(swap_table.swap_used_map, idx);

    return true;
}

static bool anon_swap_out (struct page *page) {
    struct anon_page *anon_page = &amp;amp;page-&amp;gt;anon;
    struct frame *victim_frame = page-&amp;gt;frame;
    int idx = bitmap_scan(swap_table.swap_used_map, 0, 1, false);
    if (idx == BITMAP_ERROR) {
        return false;
    }

    for (int i = 0; i &amp;lt; 8; i++) {
        disk_sector_t sec_no = (disk_sector_t) idx*8 + i;
        disk_write(swap_disk, sec_no, (victim_frame-&amp;gt;kva) + SECTOR_SIZE * i);
    }

    anon_page-&amp;gt;bit_idx = idx;
    pml4_clear_page(thread_current()-&amp;gt;pml4, page-&amp;gt;va);
    bitmap_flip(swap_table.swap_used_map, idx);

    return true;
}

static void anon_destroy (struct page *page) {
    struct anon_page *anon_page = &amp;amp;page-&amp;gt;anon;
    struct thread *cur = thread_current();
    hash_delete(&amp;amp;cur-&amp;gt;spt.pages, &amp;amp;page-&amp;gt;page_elem);
    if (page-&amp;gt;frame){
        pml4_clear_page(cur-&amp;gt;pml4, page-&amp;gt;va);
        palloc_free_page(page-&amp;gt;frame-&amp;gt;kva); 
        list_remove(&amp;amp;page-&amp;gt;frame-&amp;gt;frame_elem);
        free(page-&amp;gt;frame);
        page-&amp;gt;frame = NULL;
    }
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;anon_swap_in&lt;/b&gt;: 스왑 디스크에서 페이지를 메모리로 읽어오기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스왑 공간에서 bit_idx를 사용하여 위치를 찾기&lt;/li&gt;
&lt;li&gt;8개의 섹터를 읽어와 페이지 크기(4KB)를 채우기&lt;/li&gt;
&lt;li&gt;스왑 비트맵을 업데이트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;anon_swap_out&lt;/b&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;8개의 섹터에 페이지를 기록&lt;/li&gt;
&lt;li&gt;페이지 테이블 엔트리를 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;anon_destroy&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12. file.c에서 파일 기반 페이지의 swap in/out 구현&lt;/p&gt;
&lt;pre id=&quot;code_1729523225564&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool file_backed_initializer (struct page *page, enum vm_type type, void *kva) {
    page-&amp;gt;operations = &amp;amp;file_ops;
    struct file_page *file_page = &amp;amp;page-&amp;gt;file;
    return true;
}

static bool file_backed_swap_in (struct page *page, void *kva) {
    struct file_page *file_page = &amp;amp;page-&amp;gt;file;
    struct file *file = file_page-&amp;gt;file;
    file_seek(file, file_page-&amp;gt;ofs);
    file_read_at(file, kva, file_page-&amp;gt;page_read_bytes, file_page-&amp;gt;ofs);
    return true;
}

static bool file_backed_swap_out (struct page *page) {
    uint64_t *pml4 = thread_current()-&amp;gt;pml4;
    struct file_page *file_page = &amp;amp;page-&amp;gt;file;

    if(pml4_is_dirty(pml4, page-&amp;gt;va)){
        struct file *file = file_page-&amp;gt;file;
        file_seek(file, file_page-&amp;gt;ofs);
        file_write_at(file, page-&amp;gt;frame-&amp;gt;kva, file_page-&amp;gt;page_read_bytes, file_page-&amp;gt;ofs);
        pml4_set_dirty(pml4, page-&amp;gt;va, false);
    }

    pml4_clear_page(pml4, page-&amp;gt;va);

    return true;
}

static void file_backed_destroy (struct page *page) {
    struct file_page *file_page = &amp;amp;page-&amp;gt;file;
    uint64_t *pml4 = thread_current()-&amp;gt;pml4;
    struct supplemental_page_table *spt = &amp;amp;thread_current()-&amp;gt;spt;

    hash_delete(&amp;amp;spt-&amp;gt;pages, &amp;amp;page-&amp;gt;page_elem);

    if(page-&amp;gt;frame != NULL){
        if(pml4_is_dirty(pml4, page-&amp;gt;va))
            file_write_at(file_page-&amp;gt;file, page-&amp;gt;va, file_page-&amp;gt;page_read_bytes, file_page-&amp;gt;ofs);
        
        pml4_clear_page(pml4, page-&amp;gt;va);
        palloc_free_page(page-&amp;gt;frame-&amp;gt;kva);

        list_remove(&amp;amp;page-&amp;gt;frame-&amp;gt;frame_elem);
        free(page-&amp;gt;frame);
        page-&amp;gt;frame = NULL;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;file_backed_swap_in&lt;/b&gt;: 파일에서 페이지를 읽어와 메모리에 로드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;file_backed_swap_out&lt;/b&gt;: 페이지가 수정되었는지 확인하고, 수정되었으면 파일에 내용을 기록&lt;/li&gt;
&lt;li&gt;&lt;b&gt;file_backed_destroy&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vm.c 코드 (전체코드)&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1729520577068&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* vm.c: Generic interface for virtual memory objects. */

#include &quot;threads/malloc.h&quot;
#include &quot;vm/vm.h&quot;
#include &quot;vm/inspect.h&quot;
#include &quot;threads/mmu.h&quot;
#include &quot;userprog/process.h&quot;
#include &quot;userprog/syscall.h&quot;
#include &amp;lt;string.h&amp;gt;

static unsigned
page_hash (const struct hash_elem *p_, void *aux UNUSED);
static bool
page_less (const struct hash_elem *a_,
           const struct hash_elem *b_, void *aux UNUSED);

static struct page *page_lookup (struct supplemental_page_table *spt, const void *address);

struct list frame_table;

struct lock frame_table_lock;

/* Initializes the virtual memory subsystem by invoking each subsystem's
 * intialize codes. */
void
vm_init (void) {
	vm_anon_init ();
	vm_file_init ();
	list_init(&amp;amp;frame_table);

	lock_init(&amp;amp;frame_table_lock);
#ifdef EFILESYS  /* For project 4 */
	pagecache_init ();
#endif
	register_inspect_intr ();
	/* DO NOT MODIFY UPPER LINES. */
	/* TODO: Your code goes here. */
}

/* Get the type of the page. This function is useful if you want to know the
 * type of the page after it will be initialized.
 * This function is fully implemented now. */
enum vm_type
page_get_type (struct page *page) {
	int ty = VM_TYPE (page-&amp;gt;operations-&amp;gt;type);
	switch (ty) {
		case VM_UNINIT:
			return VM_TYPE (page-&amp;gt;uninit.type);
		default:
			return ty;
	}
}

/* Helpers */
static struct frame *vm_get_victim (void);
static bool vm_do_claim_page (struct page *page);
static struct frame *vm_evict_frame (void);

/* Create the pending page object with initializer. If you want to create a
 * page, do not create it directly and make it through this function or
 * `vm_alloc_page`. */
bool
vm_alloc_page_with_initializer (enum vm_type type, void *upage, bool writable,
		vm_initializer *init, void *aux) {
	ASSERT (VM_TYPE(type) != VM_UNINIT)

	struct supplemental_page_table *spt = &amp;amp;thread_current ()-&amp;gt;spt;

	struct page* page = spt_find_page (spt, upage);

	/* Check wheter the upage is already occupied or not. */
	if (page == NULL) {
		/* TODO: Create the page, fetch the initialier according to the VM type,
		 * TODO: and then create &quot;uninit&quot; page struct by calling uninit_new. You
		 * TODO: should modify the field after calling the uninit_new. */
		page = malloc(sizeof(struct page));
		if (page == NULL)
			goto err;
		bool (*initializer)(struct page *, enum vm_type, void *);
		switch (VM_TYPE(type)){
		case VM_ANON:
			initializer = anon_initializer;
			break;
		case VM_FILE:
			initializer = file_backed_initializer;
			break;
		default:
			goto err;
		}

		uninit_new(page, upage, init, type, aux, initializer);
		page-&amp;gt;is_writable = writable;
		
		/* TODO: Insert the page into the spt. */
		return spt_insert_page(spt, page);
	}
err:
	return false;
}

/* Find VA from spt and return page. On error, return NULL. */
struct page *
spt_find_page (struct supplemental_page_table *spt UNUSED, void *va UNUSED) {
	struct page *page = NULL;
	/* TODO: Fill this function. */
	return page_lookup(spt, va);
}

/* Insert PAGE into spt with validation. */
bool
spt_insert_page (struct supplemental_page_table *spt UNUSED,
		struct page *page UNUSED) {
	int succ = false;
	/* TODO: Fill this function. */
	struct hash_elem * result = hash_insert(&amp;amp;spt-&amp;gt;pages, &amp;amp;page-&amp;gt;page_elem);
	if(result == NULL)
		succ = true;
	return succ;
}

void
spt_remove_page (struct supplemental_page_table *spt, struct page *page) {
	vm_dealloc_page (page);
	return true;
}

/* Get the struct frame, that will be evicted. */
static struct frame *
vm_get_victim (void) {
	 /* TODO: The policy for eviction is up to you. */
	struct list_elem *e = list_pop_front(&amp;amp;frame_table);
	struct frame *victim = list_entry(e, struct frame, frame_elem);

	return victim;
}

/* Evict one page and return the corresponding frame.
 * Return NULL on error.*/
static struct frame *
vm_evict_frame (void) {
	struct frame *victim = vm_get_victim ();
	/* TODO: swap out the victim and return the evicted frame. */
	struct page *victim_page = victim-&amp;gt;page;
	
	if(swap_out(victim_page)) {

		victim_page-&amp;gt;frame = NULL;
		victim-&amp;gt;page = NULL;
		memset(victim-&amp;gt;kva, 0, PGSIZE);

		return victim;
	}

	return NULL;
}

/* palloc() and get frame. If there is no available page, evict the page
 * and return it. This always return valid address. That is, if the user pool
 * memory is full, this function evicts the frame to get the available memory
 * space.*/
static struct frame *
vm_get_frame (void) {
	struct frame *frame = (struct frame*)malloc(sizeof(struct frame));
	ASSERT (frame != NULL);
	/* TODO: Fill this function. */
	frame-&amp;gt;kva = palloc_get_page(PAL_USER);
	frame-&amp;gt;page = NULL;
	if(frame-&amp;gt;kva == NULL) {
		free(frame);
		frame = vm_evict_frame();
	}
	
	ASSERT (frame-&amp;gt;page == NULL);
	
	lock_acquire(&amp;amp;frame_table_lock);
	list_push_back(&amp;amp;frame_table, &amp;amp;frame-&amp;gt;frame_elem);
	lock_release(&amp;amp;frame_table_lock);

	return frame;
}

/* Growing the stack. */
static void
vm_stack_growth (void *addr UNUSED) {
    if(vm_alloc_page(VM_ANON | VM_MARKER_0, pg_round_down(addr), 1))
		thread_current()-&amp;gt;stack_bottom -= PGSIZE;
	
}

/* Handle the fault on write_protected page */
static bool
vm_handle_wp (struct page *page UNUSED) {
}

/* Return true on success */
bool
vm_try_handle_fault (struct intr_frame *f, void *addr,
		bool user, bool write, bool not_present) {
	struct supplemental_page_table *spt = &amp;amp;thread_current ()-&amp;gt;spt;
	/* TODO: Validate the fault */
	if(addr == NULL || is_kernel_vaddr(addr)){
		return false;
	}
	
	if (!not_present){
		return false;
	}

	void *rsp = f-&amp;gt;rsp; // user access인 경우 rsp는 유저 stack을 가리킨다.
    if (!user) // kernel access인 경우 thread에서 rsp를 가져와야 한다.
		rsp = thread_current()-&amp;gt;rsp;

	// 스택 확장으로 처리할 수 있는 폴트인 경우, vm_stack_growth를 호출한다.
    if (rsp-8 &amp;lt;= addr  &amp;amp;&amp;amp; USER_STACK - 0x100000 &amp;lt;= addr &amp;amp;&amp;amp; addr &amp;lt;= USER_STACK)
		vm_stack_growth(pg_round_down(addr));
	
	struct page *page = spt_find_page(spt, addr);
	if (page == NULL){
		return false;
	}
	if (write &amp;amp;&amp;amp; !page-&amp;gt;is_writable){
		return false;
	}
	
	/* TODO: Your code goes here */
	bool success = vm_do_claim_page (page);
	return success;
}

/* Free the page.
 * DO NOT MODIFY THIS FUNCTION. */
void
vm_dealloc_page (struct page *page) {
	destroy (page);
	free (page);
}

/* Claim the page that allocate on VA. */
bool
vm_claim_page (void *va UNUSED) {
	struct thread *cur = thread_current();
	struct page *page = spt_find_page(&amp;amp;cur-&amp;gt;spt, va);
	/* TODO: Fill this function */
	if (page == NULL){
		return false;
	}
	return vm_do_claim_page (page);
}

/* Claim the PAGE and set up the mmu. */
static bool
vm_do_claim_page (struct page *page) {
	struct frame *frame = vm_get_frame ();

	/* Set links */
	frame-&amp;gt;page = page;
	page-&amp;gt;frame = frame;

	/* TODO: Insert page table entry to map page's VA to frame's PA. */

	struct thread *cur = thread_current();
	pml4_set_page(cur-&amp;gt;pml4, page-&amp;gt;va, frame-&amp;gt;kva, page-&amp;gt;is_writable);
	return swap_in(page, frame-&amp;gt;kva);
}

/* Initialize new supplemental page table */
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
	hash_init (&amp;amp;spt-&amp;gt;pages, page_hash, page_less, NULL);
}

/* Returns a hash value for page p. */
unsigned
page_hash (const struct hash_elem *p_, void *aux UNUSED) {
  const struct page *p = hash_entry (p_, struct page, page_elem);
  return hash_bytes (&amp;amp;p-&amp;gt;va, sizeof p-&amp;gt;va);
}

/* Returns true if page a precedes page b. */
bool
page_less (const struct hash_elem *a_,
           const struct hash_elem *b_, void *aux UNUSED) {
  const struct page *a = hash_entry (a_, struct page, page_elem);
  const struct page *b = hash_entry (b_, struct page, page_elem);

  return a-&amp;gt;va &amp;lt; b-&amp;gt;va;
}

/* Returns the page containing the given virtual address, or a null pointer if no such page exists. */
struct page *
page_lookup (struct supplemental_page_table *spt, const void *va) {
	struct page p;
	struct hash_elem *e;
	
	p.va = pg_round_down(va);
	e = hash_find (&amp;amp;spt-&amp;gt;pages, &amp;amp;p.page_elem);
	return e != NULL ? hash_entry (e, struct page, page_elem) : NULL;
}

/* Copy supplemental page table from src to dst */
bool
supplemental_page_table_copy (struct supplemental_page_table *dst,
		struct supplemental_page_table *src) {
	struct hash_iterator i;
	struct hash_elem *elem;
	hash_first(&amp;amp;i, &amp;amp;src-&amp;gt;pages);
	while ((elem = hash_next(&amp;amp;i))){
		struct page *p = hash_entry(elem, struct page, page_elem);
		enum vm_type type = page_get_type(p);

		if (VM_TYPE(p-&amp;gt;operations-&amp;gt;type) == VM_UNINIT){
			//if(!vm_alloc_page_with_initializer(VM_ANON, p-&amp;gt;va, p-&amp;gt;is_writable, p-&amp;gt;uninit.init, p-&amp;gt;uninit.aux)) // 왜 ANON?
			struct load_info *copy_aux = (struct load_info *)malloc(sizeof(struct load_info));
			memcpy(copy_aux, p-&amp;gt;uninit.aux, sizeof(struct load_info));
			if(!vm_alloc_page_with_initializer(type, p-&amp;gt;va, p-&amp;gt;is_writable, p-&amp;gt;uninit.init, copy_aux))
				return false;
		}else{
			if(vm_alloc_page(type, p-&amp;gt;va, p-&amp;gt;is_writable)
			&amp;amp;&amp;amp; vm_claim_page(p-&amp;gt;va)){
				struct page* copy = spt_find_page(dst, p-&amp;gt;va);
				memcpy(copy-&amp;gt;frame-&amp;gt;kva, p-&amp;gt;frame-&amp;gt;kva, PGSIZE);
				copy-&amp;gt;frame-&amp;gt;page = copy;
			}else
				return false;
		}
		
	}
	return true;
	
}

/* Free the resource hold by the supplemental page table */
void
supplemental_page_table_kill (struct supplemental_page_table *spt UNUSED) {
	/* TODO: Destroy all the supplemental_page_table hold by thread and
	* TODO: writeback all the modified contents to the storage. */
	// hash_destroy(&amp;amp;spt-&amp;gt;pages, page_dealloc);
	hash_clear(&amp;amp;spt-&amp;gt;pages, page_dealloc);
}

void page_dealloc(struct hash_elem *e, void *aux UNUSED) {
	struct page *target = hash_entry (e, struct page, page_elem);
	destroy(target);
    free(target);
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div data-message-model-slug=&quot;gpt-4&quot; data-message-id=&quot;f862dccc-c648-486c-a447-4d8f0a969662&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핀토스의 vm.c 파일은 가상 메모리 객체에 대한 일반적인 인터페이스를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 주로 가상 메모리의 초기화, 페이지 할당, 페이지 타입 확인, 페이지 테이블 관리, 페이지 폴트 처리, 스왑 인/아웃, 스택 확장 등의 기능을 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.초기화 함수 (vm_init):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가상 메모리 서브시스템 초기화를 담당한다.&lt;/li&gt;
&lt;li&gt;vm_anon_init(), vm_file_init() 등 서브시스템 초기화를 호출하고, 프레임 테이블을 초기화하며, 락을 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520628404&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void
vm_init (void) {
	vm_anon_init ();
	vm_file_init ();
	list_init(&amp;amp;frame_table);

	lock_init(&amp;amp;frame_table_lock);
#ifdef EFILESYS  /* For project 4 */
	pagecache_init ();
#endif
	register_inspect_intr ();
	/* DO NOT MODIFY UPPER LINES. */
	/* TODO: Your code goes here. */
}&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;b&gt;2. 페이지 타입 가져오기 (page_get_type):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지의 타입을 확인하는 함수로, 페이지가 어떤 타입(익명 페이지, 파일 백업 페이지 등)인지 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520642176&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum vm_type
page_get_type (struct page *page) {
	int ty = VM_TYPE (page-&amp;gt;operations-&amp;gt;type);
	switch (ty) {
		case VM_UNINIT:
			return VM_TYPE (page-&amp;gt;uninit.type);
		default:
			return ty;
	}
}&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;b&gt;3. 페이지 할당 (vm_alloc_page_with_initializer):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새 페이지 객체를 생성하고 초기화 함수를 설정한다.&lt;/li&gt;
&lt;li&gt;이미 존재하는 주소에 대한 페이지 요청이 들어오면, 해당 주소가 이미 사용 중인지 확인 후 새 페이지를 할당하거나 에러 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520676263&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool
vm_alloc_page_with_initializer (enum vm_type type, void *upage, bool writable,
		vm_initializer *init, void *aux) {
	ASSERT (VM_TYPE(type) != VM_UNINIT)

	struct supplemental_page_table *spt = &amp;amp;thread_current ()-&amp;gt;spt;

	struct page* page = spt_find_page (spt, upage);

	/* Check wheter the upage is already occupied or not. */
	if (page == NULL) {
		/* TODO: Create the page, fetch the initialier according to the VM type,
		 * TODO: and then create &quot;uninit&quot; page struct by calling uninit_new. You
		 * TODO: should modify the field after calling the uninit_new. */
		page = malloc(sizeof(struct page));
		if (page == NULL)
			goto err;
		bool (*initializer)(struct page *, enum vm_type, void *);
		switch (VM_TYPE(type)){
		case VM_ANON:
			initializer = anon_initializer;
			break;
		case VM_FILE:
			initializer = file_backed_initializer;
			break;
		default:
			goto err;
		}

		uninit_new(page, upage, init, type, aux, initializer);
		page-&amp;gt;is_writable = writable;
		
		/* TODO: Insert the page into the spt. */
		return spt_insert_page(spt, page);
	}
err:
	return false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 페이지 찾기 및 삽입 (spt_find_page, spt_insert_page):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주소를 사용하여 보조 페이지 테이블에서 해당 페이지를 찾거나, 새 페이지를 삽입한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520693005&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct page *
spt_find_page (struct supplemental_page_table *spt UNUSED, void *va UNUSED) {
	struct page *page = NULL;
	/* TODO: Fill this function. */
	return page_lookup(spt, va);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729520724850&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool
spt_insert_page (struct supplemental_page_table *spt UNUSED,
		struct page *page UNUSED) {
	int succ = false;
	/* TODO: Fill this function. */
	struct hash_elem * result = hash_insert(&amp;amp;spt-&amp;gt;pages, &amp;amp;page-&amp;gt;page_elem);
	if(result == NULL)
		succ = true;
	return succ;
}&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;b&gt;5. 페이지 제거 (spt_remove_page):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 페이지를 보조 페이지 테이블에서 제거하고 메모리에서 할당 해제한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520747822&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void
spt_remove_page (struct supplemental_page_table *spt, struct page *page) {
	vm_dealloc_page (page);
	return true;
}&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;b&gt;6. 페이지 스왑 아웃 및 프레임 희생자 선택 (vm_evict_frame, vm_get_victim):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리에서 프레임을 제거(스왑 아웃)하고, 스왑 아웃할 프레임의 희생자를 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520769968&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static struct frame *
vm_get_victim (void) {
	 /* TODO: The policy for eviction is up to you. */
	struct list_elem *e = list_pop_front(&amp;amp;frame_table);
	struct frame *victim = list_entry(e, struct frame, frame_elem);

	return victim;
}

/* Evict one page and return the corresponding frame.
 * Return NULL on error.*/
static struct frame *
vm_evict_frame (void) {
	struct frame *victim = vm_get_victim ();
	/* TODO: swap out the victim and return the evicted frame. */
	struct page *victim_page = victim-&amp;gt;page;
	
	if(swap_out(victim_page)) {

		victim_page-&amp;gt;frame = NULL;
		victim-&amp;gt;page = NULL;
		memset(victim-&amp;gt;kva, 0, PGSIZE);

		return victim;
	}

	return NULL;
}&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;b&gt;7. 스택 확장 (vm_stack_growth):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주소가 주어지면 스택을 확장하는 기능을 제공한다. 주소가 스택 확장 가능 범위 내에 있는지 확인 후 확장을 수행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520819958&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static void
vm_stack_growth (void *addr UNUSED) {
    if(vm_alloc_page(VM_ANON | VM_MARKER_0, pg_round_down(addr), 1))
		thread_current()-&amp;gt;stack_bottom -= PGSIZE;
	
}&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;b&gt;8. 페이지 폴트 처리 (vm_try_handle_fault):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페이지 폴트가 발생했을 때, 해당 주소에 대한 페이지를 찾고, 필요에 따라 페이지를 로드하거나 스택을 확장하는 로직을 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520840108&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool
vm_try_handle_fault (struct intr_frame *f, void *addr,
		bool user, bool write, bool not_present) {
	struct supplemental_page_table *spt = &amp;amp;thread_current ()-&amp;gt;spt;
	/* TODO: Validate the fault */
	if(addr == NULL || is_kernel_vaddr(addr)){
		return false;
	}
	
	if (!not_present){
		return false;
	}

	void *rsp = f-&amp;gt;rsp; // user access인 경우 rsp는 유저 stack을 가리킨다.
    if (!user) // kernel access인 경우 thread에서 rsp를 가져와야 한다.
		rsp = thread_current()-&amp;gt;rsp;

	// 스택 확장으로 처리할 수 있는 폴트인 경우, vm_stack_growth를 호출한다.
    if (rsp-8 &amp;lt;= addr  &amp;amp;&amp;amp; USER_STACK - 0x100000 &amp;lt;= addr &amp;amp;&amp;amp; addr &amp;lt;= USER_STACK)
		vm_stack_growth(pg_round_down(addr));
	
	struct page *page = spt_find_page(spt, addr);
	if (page == NULL){
		return false;
	}
	if (write &amp;amp;&amp;amp; !page-&amp;gt;is_writable){
		return false;
	}
	
	/* TODO: Your code goes here */
	bool success = vm_do_claim_page (page);
	return success;
}&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;b&gt;9. 페이지 및 프레임 클레임 (vm_claim_page, vm_do_claim_page):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주소에 해당하는 페이지를 클레임하고, 물리 메모리에 매핑한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520858057&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool
vm_claim_page (void *va UNUSED) {
	struct thread *cur = thread_current();
	struct page *page = spt_find_page(&amp;amp;cur-&amp;gt;spt, va);
	/* TODO: Fill this function */
	if (page == NULL){
		return false;
	}
	return vm_do_claim_page (page);
}

/* Claim the PAGE and set up the mmu. */
static bool
vm_do_claim_page (struct page *page) {
	struct frame *frame = vm_get_frame ();

	/* Set links */
	frame-&amp;gt;page = page;
	page-&amp;gt;frame = frame;

	/* TODO: Insert page table entry to map page's VA to frame's PA. */

	struct thread *cur = thread_current();
	pml4_set_page(cur-&amp;gt;pml4, page-&amp;gt;va, frame-&amp;gt;kva, page-&amp;gt;is_writable);
	return swap_in(page, frame-&amp;gt;kva);
}&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;b&gt;10. 보조 페이지 테이블 관련 함수 (supplemental_page_table_init, supplemental_page_table_copy, supplemental_page_table_kill):&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보조 페이지 테이블을 초기화하거나, 복사하거나, 종료 처리를 담당한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1729520879868&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
	hash_init (&amp;amp;spt-&amp;gt;pages, page_hash, page_less, NULL);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729520892614&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool
supplemental_page_table_copy (struct supplemental_page_table *dst,
		struct supplemental_page_table *src) {
	struct hash_iterator i;
	struct hash_elem *elem;
	hash_first(&amp;amp;i, &amp;amp;src-&amp;gt;pages);
	while ((elem = hash_next(&amp;amp;i))){
		struct page *p = hash_entry(elem, struct page, page_elem);
		enum vm_type type = page_get_type(p);

		if (VM_TYPE(p-&amp;gt;operations-&amp;gt;type) == VM_UNINIT){
			//if(!vm_alloc_page_with_initializer(VM_ANON, p-&amp;gt;va, p-&amp;gt;is_writable, p-&amp;gt;uninit.init, p-&amp;gt;uninit.aux)) // 왜 ANON?
			struct load_info *copy_aux = (struct load_info *)malloc(sizeof(struct load_info));
			memcpy(copy_aux, p-&amp;gt;uninit.aux, sizeof(struct load_info));
			if(!vm_alloc_page_with_initializer(type, p-&amp;gt;va, p-&amp;gt;is_writable, p-&amp;gt;uninit.init, copy_aux))
				return false;
		}else{
			if(vm_alloc_page(type, p-&amp;gt;va, p-&amp;gt;is_writable)
			&amp;amp;&amp;amp; vm_claim_page(p-&amp;gt;va)){
				struct page* copy = spt_find_page(dst, p-&amp;gt;va);
				memcpy(copy-&amp;gt;frame-&amp;gt;kva, p-&amp;gt;frame-&amp;gt;kva, PGSIZE);
				copy-&amp;gt;frame-&amp;gt;page = copy;
			}else
				return false;
		}
		
	}
	return true;
	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729520903680&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void
supplemental_page_table_kill (struct supplemental_page_table *spt UNUSED) {
	/* TODO: Destroy all the supplemental_page_table hold by thread and
	* TODO: writeback all the modified contents to the storage. */
	// hash_destroy(&amp;amp;spt-&amp;gt;pages, page_dealloc);
	hash_clear(&amp;amp;spt-&amp;gt;pages, page_dealloc);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SW 정글/운영체제</category>
      <author>삼월은마치</author>
      <guid isPermaLink="true">https://marchislike.tistory.com/245</guid>
      <comments>https://marchislike.tistory.com/245#entry245comment</comments>
      <pubDate>Tue, 22 Oct 2024 00:09:25 +0900</pubDate>
    </item>
  </channel>
</rss>