<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>a-paka.log</title>
        <link>https://velog.io/</link>
        <description>iOS Engineer</description>
        <lastBuildDate>Tue, 22 Mar 2022 06:22:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. a-paka.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/a-paka" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[iOS] SOLID Principles]]></title>
            <link>https://velog.io/@a-paka/iOS-SOLID-Principles</link>
            <guid>https://velog.io/@a-paka/iOS-SOLID-Principles</guid>
            <pubDate>Tue, 22 Mar 2022 06:22:02 GMT</pubDate>
            <description><![CDATA[<p>각 원칙에 한 줄 설명과 예시는 다음과 같다.</p>
<hr>
<p>Single Responsibility
객체는 하나의 기능만 수행해야 한다.</p>
<ul>
<li>View 는 UI 관련 설정만, 네트워크 매니저는 HTTP 요청/응답만 관여해야 한다.</li>
</ul>
<hr>
<p>Open-Closed
소프트웨어 엔티티는 확장에 열려있고 변경에 닫혀있어야 한다.</p>
<ul>
<li>&lt;예시&gt;
데이터 타입이 계속 추가되는 경우 추상 클래스를 작성하면 좋다.</li>
</ul>
<hr>
<p>Liskov substitution</p>
<p>프로그램의 정상 동작을 유지하면서 클래스 S 를 따르는 객체를 클래스 S 의 서브클래스 T 를 따르는 객체로 치환할 수 있어야 한다.</p>
<ul>
<li>서브클래싱을 했을 때 상위 클래스의 동작과 엇나가면 안된다.</li>
</ul>
<hr>
<p>Interface segregation</p>
<p>사용하지 않는 UI 기능을 구현하지 않도록 주의하라</p>
<ul>
<li>&lt;예시&gt;
UI 관련 프로토콜에 구현이 필요 없는 메소드가 포함되는 경우 프로토콜을 분리하는 것이 좋다.</li>
</ul>
<hr>
<p>Dependency inversion</p>
<p>추상화한 것이 디테일에 의존하지 않도록 작성해야 한다.</p>
<ul>
<li>이것도 프로토콜 프로그래밍을 사용해야 하는 이유 중 하나이다.</li>
</ul>
<p>ref: <a href="https://www.raywenderlich.com/21503974-solid-principles-for-ios-apps">https://www.raywenderlich.com/21503974-solid-principles-for-ios-apps</a> 
ref: <a href="https://medium.com/@nishant.kumbhare4/solid-principles-in-swift-73b505d3c63f">https://medium.com/@nishant.kumbhare4/solid-principles-in-swift-73b505d3c63f</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[iOS] Delegate 와 Notification 의 차이]]></title>
            <link>https://velog.io/@a-paka/iOS-Delegate-%EC%99%80-Notification-%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@a-paka/iOS-Delegate-%EC%99%80-Notification-%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 22 Mar 2022 05:26:04 GMT</pubDate>
            <description><![CDATA[<p>Delegate 와 Notification 는 클래스 간에 커플링이나 디펜던시를 최대한 줄일 수 있게 도와주기 위해 고안되었다. Delegate (대리) 는 단어 뜻 그대로, 다른 객체에게 메세지를 보냈을 때 알아서 처리해달라고 요청하는 것이다.</p>
<p>TableView 가 스크롤을 했을 때, 추가적인 동작을 위해 Delegate 에게 메시지를 전달하는 것이 그 예시이다.</p>
<p>TableView 가 행을 선택하기 전, Delegate 에게 선택이 가능한지 물어볼 수도 있다.</p>
<p>Delegate 는 프로토콜 기반으로 동작하는데, 이는 클래스 간의 디펜던시를 최소화 할 수 있고, 프로토콜을 선언하는 입장에서 꼭 구현해야 하는 / 구현하지 않아도 되는 메소드를 분리할 수 있다.</p>
<p>ref: <a href="https://useyourloaf.com/blog/delegation-or-notification/">https://useyourloaf.com/blog/delegation-or-notification/</a></p>
<p>Notification 은 메시지를 브로드캐스팅한다. 앞의 예시에서 Delegate 는 sender 와 상호작용이 가능하다고 했는데, Notification 의 receiver 는 sender 에게 어떤 동작을 하도록 작용할 수 없다.</p>
<p>NotificationCenter 가 방송국 역할을 한다고 할 수 있다. 
(addObserver 로 옵저버 등록, post 로 메시지 전송)</p>
<hr>
<p>The concept of Delegate and Notification is devised in order to reduce couplings and dependencies (most of them are unnecessary.) between classes in application.</p>
<p>Delegate is, literally assigned to be delegated any actions to be done whenever sender sends certain messages.</p>
<p>For example, when scrolling table view, send a message to delegate to handle further actions.</p>
<p>Or before selecting a row, sender can ask its delegate whether to be allowed or not.</p>
<p>Delegate pattern is protocol based, it minimizes dependencies between classes, and separator must/optionally implemented methods easily.</p>
<p>In the meantime, Notification does broadcast messages. As in the previous example, Delegate can interact with its sender. But the receiver of Notification cannot force its sender to perform any action.</p>
<p>NotificationCenter plays a role as broadcast center, as receivers can add observers and senders post messages via NotificationCenter.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-k1qflqqd</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-k1qflqqd</guid>
            <pubDate>Tue, 01 Mar 2022 11:08:51 GMT</pubDate>
            <description><![CDATA[<p><strong>751. IP to CIDR</strong></p>
<p><img src="https://images.velog.io/images/a-paka/post/7dfbe89f-550d-46a9-9cab-36d98dc3cd57/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-03-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.03.35.png" alt=""></p>
<p>IP 주소가 주어지면, 이를 정수로 만든 다음 연속한 n개의 정수만을 커버하는 CIDR 의 최소 길이 배열을 찾으면 된다.</p>
<p>CIDR 이란, IP 주소 뒤에 비트 인덱스가 있어 이 비트 이후로는 어떤 숫자든 올 수 있기 때문에 여러 개의 IP 주소를 커버할 수 있다.</p>
<p>편의를 위해 아래 메소드를 생성했다.</p>
<pre><code class="language-swift">func ipToNum(_ ip: String) -&gt; Int {
    ip.split(separator: &quot;.&quot;).compactMap { Int($0) }.reduce(into: 0) { r, c in
        r = r * 256 + c
    }
}

func bit(_ x: Int) -&gt; Int {
    x &amp; -x
}

func log(_ x: Int) -&gt; Int {
    Int(log2(Double(x)))
}

func CIDR(_ num: Int, _ k: Int) -&gt; String {
    [num/(256*256*256) % 256,
     num/(256*256) % 256
     num/256 % 256,
     um%256].map { &quot;\($0)&quot; }.joined(separator: &quot;.&quot;) + &quot;/\(k)&quot;
}</code></pre>
<p>ipToNum : ip 주소를 정수로 변환
bit : least significant bit 의 크기
log : Log2 값
CIDR : 정수와 비트 인덱스에 해당하는 CIDR 문자열로 변환</p>
<p>풀이는 그리디 알고리즘을 사용하면 된다. LSB 만큼 더했을 때 n 이 남아있는 경우 CIDR 에 해당한다.</p>
<pre><code class="language-swift">func ipToCIDR(_ ip: String, _ n: Int) -&gt; [String] {
    var num = ipToNum(ip), n = n, res = [String]()

    while n &gt; 0 {
        var b = bit(num) &gt; 0 ? bit(num) : Int(pow(2.0, Double(log(n))))
        while b &gt; n {
            b = b / 2
        }
        res.append(CIDR(num, 32 - log(b)))
        num += b
        n -= b
    }

    return res
}</code></pre>
<p>0.0.0.0 이 주어진 경우 bit(0) = 0 이기 때문에 무한 루프를 돌게 되고,
이를 위해 Int(log2(num)) 만큼 강제 전진 해주는 과정이 필요하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-11994d1l</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-11994d1l</guid>
            <pubDate>Wed, 23 Feb 2022 10:27:22 GMT</pubDate>
            <description><![CDATA[<ol start="1066">
<li>Campus Bikes II</li>
</ol>
<p><img src="https://images.velog.io/images/a-paka/post/7fda2d35-2362-4fe5-baf7-af26a2f355ad/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-23%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.25.48.png" alt=""></p>
<p>worker - bike 쌍을 만들면서 맨하탄 거리 합의 최소를 찾아야 한다.</p>
<p>n, m &lt; 10 인 제한이라 그냥 노가다로 때려 박았다.</p>
<pre><code class="language-swift">var dic = [String: Int]()

func key(_ w: [[Int]], _ b: [[Int]]) -&gt; String {
    w.description + b.description
}

func d(_ w: [Int], _ b: [Int]) -&gt; Int {
    abs(w[0] - b[0]) + abs(w[1] - b[1])
}

func assignBikes(_ workers: [[Int]], _ bikes: [[Int]]) -&gt; Int {
    if bikes.isEmpty || workers.isEmpty {
        return 0
    }

    if let v = dic[key(workers, bikes)] {
        return v
    }

    let n = workers.count
    let m = bikes.count
    let res = (0..&lt;m).map { i -&gt; Int in
        let w = Array(workers[1..&lt;n])
        let b = Array(bikes[0..&lt;i]) + Array(bikes[(i+1)..&lt;m])
        return assignBikes(w, b) + d(workers[0], bikes[i])
    }.min()!

    dic[key(workers, bikes)] = res

    return res
}</code></pre>
<p>dp 문제로 Memoization 을 사용했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-ngwd4hml</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-ngwd4hml</guid>
            <pubDate>Tue, 22 Feb 2022 15:04:58 GMT</pubDate>
            <description><![CDATA[<ol start="1663">
<li>Smallest String With A Given Numeric Value</li>
</ol>
<p><img src="https://images.velog.io/images/a-paka/post/0c68fd34-5a22-4e26-80d1-b3bbdb2eb992/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.57.13.png" alt=""></p>
<p>이거 예전에 풀어본 적 있는 문제인데...</p>
<p>길이 n 인 String 이 도합 k 의 value 를 가지면서 사전순으로 가장 앞에 나와야 한다.</p>
<p>그리디 하게 풀고 뒤집으면 된다.</p>
<pre><code class="language-swift">func getSmallestString(_ n: Int, _ k: Int) -&gt; String {
    var res = [Character]()
    var k = k

    for i in 0..&lt;n {
        var r = k - (n - 1 - i) // 이거 가지고 만들어야 된다.
        if r &gt; 26 {
            res += [&quot;z&quot;]
            k -= 26
        } else {
            res += [Character(UnicodeScalar(97 + r - 1)!)]
            k -= r
        }
    }

    return String(Array(res.reversed()))
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-rc28kbey</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-rc28kbey</guid>
            <pubDate>Mon, 21 Feb 2022 09:47:52 GMT</pubDate>
            <description><![CDATA[<p>Pick one 버튼을 눌러 랜덤으로 문제를 하나 골랐다.</p>
<p><strong>906. Super Palindromes</strong></p>
<p><img src="https://images.velog.io/images/a-paka/post/9917de02-dc6e-4222-a936-120780d1133b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%206.43.11.png" alt=""></p>
<p>[left, right] 사이에 N 과 N*N 이 모두 팰린드롬인 수의 갯수를 구하는 문제인 듯 하다.</p>
<p>right &lt; 1e18 이므로 가능한 N &lt; 1e9 이다.</p>
<p>1e9 개의 팰린드롬을 미리 만들어 놓고 제곱수도 팰린드롬인지 확인하기로 한다.</p>
<p>자릿수가 n 이하인 팰린드롬 만드는 시간 복잡도는 양쪽에 숫자를 갖다 붙이는 방법으로 하면 O(10^(n/2)) 이다.</p>
<p>이 때 만들어진 팰린드롬 개수도 동일하고, 자릿수가 n 이하인 숫자가 팰린드롬인지 확인하는 시간 복잡도는 O(n) 이므로 시간은 충분하다.</p>
<pre><code class="language-swift">func superpalindromesInRange(_ left: String, _ right: String) -&gt; Int {
    var p = (1...9).map { &quot;\($0)&quot; }
    var res = 0

    for i in 1..&lt;Int(1e4) {
        let s = &quot;\(i)&quot;, r = String(s.reversed())
        for j in (0..&lt;10).map { &quot;\($0)&quot; } + [&quot;&quot;] {
            p.append(s + j + r)
        }
    }

    for n in p.map { Int($0)! * Int($0)! } {
        if Int(left)! &lt;= n, Int(right)! &gt;= n {
            var s = &quot;\(n)&quot;, r = String(s.reversed())
            res += s == r ? 1 : 0
        }
    }

    return res
}</code></pre>
<p><img src="https://images.velog.io/images/a-paka/post/6bb72502-2950-45af-a403-beea0fe71773/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%206.47.42.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-l6avq1kc</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-l6avq1kc</guid>
            <pubDate>Sun, 20 Feb 2022 09:45:20 GMT</pubDate>
            <description><![CDATA[<p>Pick One 을 눌러 랜덤 문제를 한 개 추출하였다.</p>
<p><strong>1751. Maximum Number of Events That Can Be Attended II</strong></p>
<p>예제를 먼저 살펴보았다.</p>
<p><img src="https://images.velog.io/images/a-paka/post/43710b51-17e9-4ee4-b43c-e19929c3b26b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.21.38.png" alt=""></p>
<p>k 개의 이벤트를 고를 수 있고, 이벤트는 겹치면 안 되는 모양이다. 이벤트의 cost 가 가장 큰 조합을 찾는 문제인 듯 하다.</p>
<p>DP 문제처럼 생겼다.</p>
<p>시작 날짜로 정렬해준 후 f(i, j) 를 i 번째 이후로 최대 j 개의 이벤트를 골랐을 때 최대값이라 하자.</p>
<p>f(i, j) = max (i 번째 이벤트를 고른 경우), (고르지 않은 경우)</p>
<p>라고 할 수 있다.</p>
<pre><code class="language-Swift">func maxValue(_ events: [[Int]], _ k: Int) -&gt; Int {
    let events = events.sorted { $0[0] &lt; $1[0] }
    let arr = Array(repeating: -1, count: k + 1)
    var dp = Array(repeating: arr, count: events.count)

    func f(_ i: Int, _ j: Int) -&gt; Int {
        if i &gt;= events.count || j &lt; 1 {
            return 0
        }

        if dp[i][j] != -1 {
            return dp[i][j]
        }

        let e = events[i]

        // let k = events.firstIndex { $0[0] &gt; e[1] } ?? Int.max
        var k = i + 1
        while k &lt; events.count, events[i][1] &gt;= events[k][0] {
            k += 1
        }

        dp[i][j] = max( f(i+1, j), f(k, j-1) + e[2] )

        return dp[i][j]
    }

    return f(0, k)
}</code></pre>
<p>메모이제이션이 없거나 firstIndex 를 사용하면 시간 제한에 걸린다...</p>
<p><img src="https://images.velog.io/images/a-paka/post/26dfbd3a-e6b5-46f4-94c3-4ce8f2a8f1ad/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.02.20.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4%EB%B3%B4%EC%95%98%EB%8B%A4-abxj5777</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4%EB%B3%B4%EC%95%98%EB%8B%A4-abxj5777</guid>
            <pubDate>Sun, 20 Feb 2022 07:44:39 GMT</pubDate>
            <description><![CDATA[<p>Pick one 버튼을 눌러 랜덤 문제를 하나 뽑았다.</p>
<p><strong>1281. Subtract the Product and Sum of Digits of an Integer</strong></p>
<p>설명이 한 줄이라 읽어보았다. 어떤 정수의 자릿수 전체의 곱과 합의 차를 구하는 문제이다.</p>
<p><img src="https://images.velog.io/images/a-paka/post/94835de8-d70e-4ecf-95bb-84d3022c20cc/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.37.32.png" alt=""></p>
<p>예제도 단순했다.</p>
<pre><code class="language-Swift">func subtractProductAndSum(_ n: Int) -&gt; Int {
    let arr = Array(&quot;\(n)&quot;).compactMap { Int(&quot;\($0)&quot;) }
    return arr.reduce(1, *) - arr.reduce(0, +)
}</code></pre>
<p>타입 변환은 귀찮다.. 파이썬이 그립다....</p>
<p><img src="https://images.velog.io/images/a-paka/post/5eefcf59-f606-4a40-bd45-21c3b99c4ecf/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.44.48.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4%EB%B3%B4%EC%95%98%EB%8B%A4</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4%EB%B3%B4%EC%95%98%EB%8B%A4</guid>
            <pubDate>Sun, 20 Feb 2022 07:35:28 GMT</pubDate>
            <description><![CDATA[<p>Pick One 버튼을 눌러 랜덤 문제를 하나 골랐다.</p>
<p><strong>1528. Shuffle String</strong></p>
<p>예제를 확인해 보았다.</p>
<p><img src="https://images.velog.io/images/a-paka/post/eed0ab60-36cd-469e-bb3e-dc9783aa9442/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.23.33.png" alt=""></p>
<p>보아하니 캐릭터의 실제 인덱스가 주어지고, 그에 맞게 정렬된 문자열을 반환하는 문제인 듯 하다.</p>
<p>O(n) 메모리 가지고는 쉽게 풀 수 있지만... 이 문제의 의도는 인메모리 정렬이니까... 한번 스캔하면서 제자리가 아닌 애들은 제자리를 찾을 때까지 스왑을 해주면 된다.</p>
<pre><code class="language-Swift">func restoreString(_ s: String, _ indices: [Int]) -&gt; String {
    var s = Array(s), indices = indices

    for i in 0..&lt;s.count {
        var j = indices[i]

        while i != j {
            s.swapAt(i, j)
            indices.swapAt(i, j)
            j = indices[i]
        }
    }

    return String(s)
}</code></pre>
<p><img src="https://images.velog.io/images/a-paka/post/7f37dcbe-0ce0-445b-b67f-63e8b5ed902c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.35.10.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-606lt1pc</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-606lt1pc</guid>
            <pubDate>Sun, 20 Feb 2022 07:20:03 GMT</pubDate>
            <description><![CDATA[<p>Pick one 버튼을 눌러 문제를 뽑았다.</p>
<p><strong>877. Stone Game</strong></p>
<p>예제 부터 확인했다.</p>
<p><img src="https://images.velog.io/images/a-paka/post/6374e1fd-27d8-4f3c-838e-a5494b3dfe40/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.16.54.png" alt=""></p>
<p>앨리스와 밥이 숫자를 하나씩 뽑는 문제인가 보다. 그리고 숫자의 합이 더 큰 사람이 이긴다. 최적의 플레이를 했을 때 앨리스가 이길 수 있는 지를 알아내면 된다.</p>
<p>그리디 알고리즘이 아닐까? 특히 첫 번째 무브에서 앨리스가 최대값을 뽑지 않으면 무조건 밥이 가져갈 것 같은데..</p>
<p>이렇게 생각하다 보니 답을 그냥 true 로 제출해봤다.</p>
<p><img src="https://images.velog.io/images/a-paka/post/f3b3d0b9-dbfb-4971-aad0-7447f821ba2c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.19.56.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를 풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-edidb3g2</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4-edidb3g2</guid>
            <pubDate>Sun, 20 Feb 2022 07:15:03 GMT</pubDate>
            <description><![CDATA[<p>Pick One 버튼을 눌러 문제를 하나 뽑아왔다.</p>
<p><strong>2088. Count Fertile Pyramids in a Land</strong></p>
<p>Description 은 읽기 귀찮아서 예시 입력을 먼저 보았다.</p>
<p><img src="https://images.velog.io/images/a-paka/post/08e33e85-21ac-49f7-be1b-ac5e7196db1e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.22.39.png" alt=""></p>
<p>피라미드와 인버스 피라미드 형태가 몇 개 있는지 세어 주는 문제인 듯 하다.</p>
<p>DP 문제가 아닐까? 행이 하나씩 추가되면 이전 결과값에 답을 더해가기 때문이다.</p>
<p>f(n) = f(n-1) + (새로 만든 피라미드) + (이어 붙인 피라미드)</p>
<ul>
<li>새로 만든 피라미드는 단순히 ㅗ 모양임을 확인하면 된다.</li>
<li>이어 붙인 피라미드는 밑변의 길이를 메모하고 있어야 해서, g 라는 배열 하나를 더 추가한다.</li>
<li>인버스 피라미드는 grid 를 뒤집으면 되기 때문에 피라미드 문제만 풀면 된다.</li>
</ul>
<p>그리드의 크기 제한을 확인했다.</p>
<pre><code>1 &lt;= m, n &lt;= 1000
1 &lt;= m * n &lt;= 1e5</code></pre><p>O(n^2) 인거 같으니 계속 하기로 한다...</p>
<pre><code class="language-Swift">func countPyramids(_ grid: [[Int]]) -&gt; Int {
    var n = grid.count
    var m = grid[0].count

    func count(_ grid: [[Int]]) -&gt; Int {

        var f = Array(repeating: 0, count: n)
        var g = Array(repeating: 0, count: m) // 현재 밑변의 길이가 2*g[k] - 1 인 피라미드의 중심이 여기에 있다.

        for i in 1..&lt;n {
            f[i] = f[i-1]

            // Existing pyramid

            for j in 0..&lt;m {
                if g[j] != 0 {
                    if j-g[j] &gt;= 0,
                       j+g[j] &lt; m,
                       Array(grid[i][(j-g[j])...(j+g[j])]) == Array(repeating: 1, count: 2*g[j] + 1) {
                        f[i] += 1
                        g[j] += 1
                    } else {
                        g[j] = 0
                    }
                }
            }

            // New pyramid

            for j in 1..&lt;(m-1) {
                if grid[i][(j-1)...(j+1)] == [1, 1, 1], grid[i-1][j] == 1 {
                    f[i] += 1
                    g[j] = max(g[j], 2)
                }
            }
        }

        return f[n-1]
    }

    print(count(grid), count(grid.reversed()))
    return count(grid) + count(grid.reversed())
}</code></pre>
<p>예제를 통과하지 못했다. 피라미드가 만들어지지 않는 조건을 추가했다.</p>
<pre><code>guard n &gt; 1, m &gt; 2 else {
    return 0
}</code></pre><p>그래도 통과가 안 된다. Existing pyramid 를 계산할 때 높이 4 짜리 피라미드가 높이 3짜리 피라미드를 동시에 포함하고 있음을 고려하지 못했다.</p>
<p>아래처럼 수정한다.</p>
<pre><code class="language-Swift">// Existing pyramid

for j in 0..&lt;m {
    while g[j] &gt;= 2 {
        if j-g[j] &gt;= 0,
           j+g[j] &lt; m,
           Array(grid[i][(j-g[j])...(j+g[j])]) == Array(repeating: 1, count: 2*g[j] + 1) {
            f[i] += g[j]-1
            g[j] += 1
            break
        } else {
            g[j] -= 1
        }
    }
}</code></pre>
<p><img src="https://images.velog.io/images/a-paka/post/8c98fc9e-1f7c-42f6-85e4-3279bbd182c9/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.10.02.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode 를  풀어 보았다.]]></title>
            <link>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4</link>
            <guid>https://velog.io/@a-paka/Leetcode-%EB%A5%BC-%ED%92%80%EC%96%B4-%EB%B3%B4%EC%95%98%EB%8B%A4</guid>
            <pubDate>Sun, 20 Feb 2022 06:21:03 GMT</pubDate>
            <description><![CDATA[<p>Pick One 버튼을 눌러 랜덤으로 한 문제를 뽑았다.</p>
<p><strong>1527. Patients With a Condition</strong></p>
<p>이런.. SQL 문제가 뽑혔다. 다시 돌렸다.</p>
<p><strong>223. Rectangle Area</strong></p>
<p>그림과 예시를 먼저 봤다.</p>
<p><img src="https://images.velog.io/images/a-paka/post/913cf47c-3944-43cb-8b2c-48a3f07deea5/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.02.25.png" alt=""></p>
<p>직사각형 2개를 주고 면적의 총 합을 구하는 문제였다.</p>
<p>겹치는 부분을 한 번 빼주면 될 거 같은데, 겹치는 좌표를 어떻게 구한담?</p>
<p>생각해보니 겹치는 좌표의 x, y 는 주어진 x, y 중 하나를 꼭 따라가게 되어있다.</p>
<p>코드 작성을 시작해 보았다. 우선 풀이를 쉽게 해주는 좌표 스트럭트와 좌표 2개로 면적을 리턴하는 메소드를 생성했다.</p>
<pre><code class="language-Swift">struct P {
    var x: Int
    var y: Int

    init(_ x: Int, _ y: Int) {
        self.x = x
        self.y = y
    }
}

func area(_ p: P, _ q: P) -&gt; Int {
    (q.x - p.x) * (q.y - p.y)
}</code></pre>
<p>잘 동작 하려나? p == q 인 경우에 0.. 머리 속으로 대충 돌려보니 맞는거 같다.</p>
<p>생각해보니 겹치는 좌표가 생기려면 변이 서로 겹쳐야 된다.</p>
<pre><code>var overlapped = 0
if max(ax1, bx1) &lt; min(ax2, bx2), max(ay1, by1) &lt; min(ay2, by2) {
    overlapped = area(P(max(ax1, bx1), max(ay1, by1)), P(min(ax2, bx2), min(ay2, by2)))
}</code></pre><p>그런데 area 함수에서 예외처리하면 if statement 를 없앨 수 있을 것 같다.</p>
<p>답:</p>
<pre><code class="language-Swift">class Solution {
    func computeArea(_ ax1: Int, _ ay1: Int, _ ax2: Int, _ ay2: Int, _ bx1: Int, _ by1: Int, _ bx2: Int, _ by2: Int) -&gt; Int {
        struct P {
            var x: Int
            var y: Int
            init(_ x: Int, _ y: Int) {
                self.x = x
                self.y = y
            }
        }

        func area(_ p: P, _ q: P) -&gt; Int {
            max(q.x - p.x, 0) * max(q.y - p.y, 0)
        }

        return
            area(P(ax1, ay1), P(ax2, ay2)) + 
            area(P(bx1, by1), P(bx2, by2)) - 
            area(P(max(ax1, bx1), max(ay1, by1)), P(min(ax2, bx2), min(ay2, by2)))
    }
}</code></pre>
<p><img src="https://images.velog.io/images/a-paka/post/01b10e5f-9ff6-4385-9f3f-0e7faf163329/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.20.49.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>