<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Duna.log</title>
        <link>https://velog.io/</link>
        <description>더 멋진 iOS 개발자를 향해</description>
        <lastBuildDate>Sun, 22 Aug 2021 15:04:47 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Duna.log</title>
            <url>https://images.velog.io/images/yoonah-dev/profile/be008975-4902-44da-95bf-f3d182f1f9bd/KuqexMR1_400x400.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Duna.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yoonah-dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Leetcode) Group Anagrams]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Group-Anagrams</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Group-Anagrams</guid>
            <pubDate>Sun, 22 Aug 2021 15:04:47 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions</strong>
<strong>Medium Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-medium/103/array-and-strings/778/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌕 🌑 🌑 (중)</strong></p>
<hr>
<p><code>Anagrams</code>, 단어나 문장을 구성하고 있는 문자의 순서를 바꾸어 다른 단어나 문장을 만드는 놀이 라고 합니다.
이름 그대로 Character의 순서만 바뀌면 같은 단어가 되는 element들끼리 묶는 문제였어요.</p>
<p>저는 어떻게 접근해야할지도 모르겠고, 도저히 감이 잡히지 않아서 Solution에 또 손을 댔습니다...🥲 
정말로 모르겠더라구요...🥲</p>
<p>또 새로운 방법을 얻어갑니다.</p>
<h3 id="solution">Solution</h3>
<p>제 생각보다 너무너무너무너무 x 100 간단했던 방식이었습니다.</p>
<p>정말 짧지 않나요?
제가 머릿속으로 그리고 처음에 짰던 코드가 미완성인 상태라도 저것보다 길었는데... 자괴감이 드네요.</p>
<pre><code class="language-swift">func groupAnagrams(_ strs: [String]) -&gt; [[String]] {
    guard strs.count &gt; 1 else { return [strs] }

    var map = [String: [String]]()

    for str in strs {
        let key = String(str.sorted())
        map[key, default: []].append(str)
    }

    return Array(map.values)
}</code></pre>
<p>이 코드는 <code>Dictionary</code>를 특이하게 사용했습니다. 
<code>[String: [String]]</code> : key를 String으로 value를 String 배열로 잡았어요.</p>
<p>요 부분만 보고는 저도 어떻게 할 생각인가 싶었는데, 밑에 for문을 보게 되면 str를 하나씩 가져오면서 key값을 sorted로 일정하게 만듭니다.
한 마디로 <code>eat</code>와 <code>ate</code> 모두 sorted된 상태가 <code>aet</code>이기 때문에 두 개 모두 key값을 <code>aet</code>로 가지게 되는거죠. 그렇기 때문에 anagrams로 인식이 되어서 같은 value로 들어갑니다.</p>
<p>제가 생각한 것보다 훨씬 쉽게 풀리던거였습니다...🥲
하지만 저렇게 <code>Dictionary</code>를 쓸 수 있다는 것, <code>Dictionary</code>에서의 default사용을 할 수 있다는 것, 이런걸 처음 알았네요.. 다음부터는 풀이에 사용해봐야겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) First Unique Character in a String]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-First-Unique-Character-in-a-String</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-First-Unique-Character-in-a-String</guid>
            <pubDate>Sun, 22 Aug 2021 11:08:27 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions</strong>
<strong>Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/127/strings/881/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection String의 세번째 문제인 <code>First Unique Character in a String</code>를 풀어봤습니다.</p>
<p>이번 문제는 String 속에서 한 번만 나타나는 Character를 찾고 해당 Character의 index를 return하는 문제였습니다.</p>
<p>저는 문제를 보자마자 <strong><code>Stack</code>를 사용하면 되겠다!</strong> 했는데, 중복이라는 게 2개만 있는 게 아닌데 2개라고 안일하게 생각해버린거였습니다..
3개도 나올 수 있고 4,5.. 무한정으로 등장할 수 있기 때문에 <code>Stack</code>은 절대 알맞지 않더라구요.</p>
<p>대신 다른 방법들을 찾아봤습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>첫 번째 방법은 <code>Dictionary</code>를 사용했습니다. </p>
<p>두 개의 <code>Dictionary</code>를 만들었는데요, 첫 번째는 Character가 나오는 Count를 세는 용, 두 번째는 Character의 index를 저장하는 용으로 만들었어요.
두 개로 나눈 이유는 <code>Dictionary</code>에는 순서가 없어서, 하나씩 찬찬히 넣어줘도 뒤죽박죽이 되어 버립니다...😂</p>
<p>일단 첫 번째 for문을 통해서 s에 포함되어 있는 character가 lists에 key값으로 포함되어 있는지 보고, </p>
<p><code>없으면</code> 
해당 key값을 넣고 value로 0를 넣어줍니다. 그리고 indexs에는 해당 값이 들어온 적이 없다면 index값을 value로 넣어줍니다.
<code>있으면</code>
해당 char를 가지고 있는 value값을 +1 해줍니다.</p>
<p>그리고 두 번째 for문에서는 indexs도 마찬가지로 뒤죽박죽이기 때문에 value를 중심으로 sort를 먼저해주고 그에 맞춰서 key값과 index값을 꺼냅니다.
꺼낸 key값이 list에서 0를 출력한다면 그 index를 return해줍시다.</p>
<p>두 번째 for문에서 return되지 못했다면 모든 character가 중복이라는 뜻이기 때문에 -1를 return하면 됩니다.</p>
<pre><code class="language-swift">func firstUniqChar(_ s: String) -&gt; Int {
    var lists: [Character: Int] = [:]
    var indexs: [Character: Int] = [:]

    for (index, char) in s.enumerated() {
        if lists.keys.contains(char) {
            if let num = lists[char] {
                lists.updateValue(num+1, forKey: char)
            }
        } else {
            lists[char] = 0
            if !indexs.keys.contains(char) {
                indexs[char] = index
            }
        }
    }

    for (key, index) in indexs.sorted(by: { $0.1 &lt; $1.1 }) {
        if lists[key] == 0 {
            return index
        }
    }

    return -1
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/c3af4ea4-db10-4f90-a943-81fcfc337e6c/%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%202021-08-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.12.29.png" alt=""></p>
<p>Runtime은 보시는대로 <code>276ms</code>가 걸렸습니다. 전체에서 중간정도의 Runtime이 걸렸습니다.
시간을 줄이고 싶어서 다른 분들이 짠 코드를 봤는데, 너무 신선한 방식들이라서 가져와 봤습니다.</p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>이 방식이 현재 Runtime이 가장 빠르다라고 되어 있어서 봤는데, 너무 신선했습니다.
방식이 엄청 어려운 것은 아닌데, 이렇게도 풀 수 있었는데 싶었던 방식이었습니다.</p>
<p>제가 처음에 c언어를 배울 때 많이 사용하던 방식이었는데요. 
바로 <strong>유니코드</strong>를 사용하는 방식입니다.</p>
<p>일단 <code>Array</code>를 만들고 26칸을 생성해줍니다. 소문자 알파벳의 갯수라고 생각하시면 됩니다.
그리고 각 칸에는 0으로 초기화를 해줘요.</p>
<p>우리는 <code>&#39;a&#39;의 유니코드</code>를 기본으로 해서 그에 맞춰서 각 character에 index를 부여할 겁니다.
예를 들어서 &#39;c&#39;가 들어온다면, &#39;c&#39;는 유니코드로 99에 해당하기 때문에 &#39;c&#39; - &#39;a&#39;를 하게 되면 2가 나오게 됩니다. counter[2]는 c가 들어가는 칸이 되고 우리가 생각했던 index에 맞춰 들어가는 걸 알 수 있죠?</p>
<p>각 character가 index에 맞춰서 들어가면 해당 index에 들어있는 숫자가 +1씩 증가하게 됩니다. 
즉, 0이면 아무것도 안들어옴. 1이면 1개, 2면 2개가 들어온거죠.</p>
<p>그리고 두 번째 for문에서 counter의 값이 1이면 해당 <code>index(i)</code>를 return 합니다.</p>
<p>첫 번째와는 다르게 배열을 사용했기 때문에 이미 들어오는대로 정렬이 잘 되어 있어서 따로 sorted를 안해도 되고 Array를 이미 26개의 자리에 맞춰서 만들어둬서 훨씬 편합니다.</p>
<pre><code class="language-swift">extension UnicodeScalar {
    var intValue: Int {
        return Int(value)
    }
}

func firstUniqChar(_ s: String) -&gt; Int {
    var counter = Array(repeating: 0, count: 26)
    let a_unicode = UnicodeScalar(&quot;a&quot;).intValue

    for c in s.unicodeScalars {
        counter[c.intValue - a_unicode] += 1
    }

    var i = 0
    for c in s.unicodeScalars {
        if counter[c.intValue - a_unicode] == 1 {
            return i
        }

        i += 1
    }

    return -1
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/d2b7aa45-8fb6-4817-b5d3-eb6317e36fd8/%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%202021-08-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.21.11.png" alt=""></p>
<p>Runtime이 쏙 내려간 걸 알 수 있습니다.</p>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p>가장 Runtime이 빨랐어요.! 분명 이중 for문을 썼는데 제일 빨라서 놀랐습니다.</p>
<p>이번에는 Array와 Set를 사용했습니다.</p>
<p>이번 문제는 chars에 있는 문자를 하나씩 빼내서 자신의 index 뒤에 있는 모든 문자들과 하나씩 대조해보면서 푸는 문제였습니다. </p>
<p>만약에 같은 문자가 뒤에 있다면 그 문자는 skipChars라는 Set에다가 넣어두고 다음에 그 문자 차례가 왔을 때 where조건에 걸려서 그 문자는 다시 for문을 돌지 못하게 했습니다.</p>
<p>그리고 뒤에 자신과 같은 문자가 없다면 isUnique라는 Boolean타입을 true로 만들어서 해당 index를 return하게 해줬습니다.</p>
<pre><code class="language-swift">func firstUniqChar(_ s: String) -&gt; Int {
    let chars: [Character] = [Character](s)
    var skipChars: Set&lt;Character&gt; = []

    for i in 0 ..&lt; chars.count where !skipChars.contains(chars[i]) {
        var isUnique: Bool = true

        for j in i + 1 ..&lt; chars.count {
            guard isUnique else { break }
            if chars[i] == chars[j] {
                isUnique = false
                skipChars.insert(chars[i])
                break
            }
        }

        if isUnique { return i }
    }

    return -1
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/64edd666-1fc5-4269-b6f0-8aff8f8c8601/%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%202021-08-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.21.57.png" alt=""></p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/dcec8b57-9f33-4b54-9e11-ccdc408b5bef/%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%202021-08-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.22.30.png" alt=""></p>
<p>보시다시피 시간이 굉장히 빨랐습니다. 이중 for문인데도 불구하고 Runtime이 가장 빠르게 나왔어요!!</p>
<p>아마도 contains되는 애들을 바로바로 제외시키기도 했고, 또 for문을 돌려서 return하는 게 아니라 지금 상태에서 Unique하다면 바로 그 index를 return시키는 방식으로 해서 그런지 빠른게 아닌가 싶습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Set Matrix Zeroes]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Set-Matrix-Zeroes</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Set-Matrix-Zeroes</guid>
            <pubDate>Sat, 21 Aug 2021 13:35:16 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions</strong>
<strong>Medium Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-medium/103/array-and-strings/777/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌕 🌑 🌑 (중)</strong></p>
<hr>
<p><code>Medium</code>으로 넘어온 뒤에 풀어본 2번째 문제였습니다.</p>
<p>이 문제는 제목 그대로, Matrix를 0으로 설정하는 문제였습니다. Matrix속에 0이 있다면 그 0이 있는 자리와 같은 행, 열에 있는 수들을 모두 0으로 변경시키는 문제였습니다.</p>
<p>이번에 문제를 풀 때 노력해본 것이 있다면, 문제를 보고 코드로 바로 치기보다는 생각 먼저 해보기였습니다. 말은 쉽지만 문제를 보면 코드로 먼저 치기 마련이거든요. 
이번엔 공책에 문제를 좀 정리하고 풀도록 했습니다.</p>
<p>꾸준히 습관으로 만들 생각입니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>처음 든 생각이 <strong>&quot;한 번 for문을 돌면서 어느 지점에 0이 있는지 찾아내자&quot;</strong> 였습니다.</p>
<p>일단 <code>enumerated()</code>를 써서 row에 있는 배열 뿐만 아니라 각 배열의 index, 그리고 배열 안에 있는 원소들의 column index를 빼왔어요. 그리고 해당 위치에 있는 숫자가 0이라면 그 row, column에 해당하는 index를 전에 만들어둔 Set에다가 넣어줬습니다.</p>
<p>Set를 사용한 이유는 Set이 중복을 제거해주기 때문입니다.
0이 같은 행,열에 있을 경우 계속해서 같은 숫자가 들어오게 되는데 이럴 경우에는 이미 0으로 만들어진 행,열을 또 0으로 만드는 의미없는 일들이 계속 일어날 거 같아서 Set으로 만들어 중복을 완전히 제거해줬습니다.</p>
<p>그리고 위의 for문에서 설정한 <code>rows</code> <code>colunms</code>에 따라서 for문을 돌리면서 행과 열에 0를 집어 넣어줬습니다.</p>
<pre><code class="language-swift">func setZeroes(_ matrix: inout [[Int]]) {
    var rows = Set&lt;Int&gt;()
    var colunms = Set&lt;Int&gt;()

    for (index, row) in matrix.enumerated() {
        for (col, num) in row.enumerated() {
            if num == 0 {
                rows.insert(index)
                colunms.insert(col)
            }
        }
    }

    for i in rows {
        for j in 0..&lt;matrix[0].count {
            matrix[i][j] = 0
        }
    }

    for i in colunms {
        for j in 0..&lt;matrix.count {
            matrix[j][i] = 0
        }
    }
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/72f536a8-4e48-45b6-8b30-b8a25c3931ff/%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%202021-08-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.54.32.png" alt=""></p>
<p>Runtime은 너무 나쁘지도 좋지도 않은 정도로 나왔습니다. </p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>두 번째 방식도 첫번째와 크게 다르지 않습니다.
하나 다른 게 있다면, 위처럼 행과 열을 적용해주는 코드를 2번에 나눠서 쓰지 않고 한 번에 썼어요.</p>
<p><code>insert</code>해주는 코드는 거의 동일하고, insert에 맞춰서 새로운 0를 넣어주는 부분이 조금 달랐습니다.</p>
<p>이번에는 <code>contains</code>를 사용해서 이중 for문을 돌렸습니다.
해당 부분의 숫자가 0이 아니고, rows 또는 cols에 들어있는 행, 열이라면 그 부분을 0으로 만들어줬습니다.</p>
<p>이중 for문이 2번으로 줄었기 때문에 시간이 훨씬 줄었을거라고 생각했는데요.</p>
<pre><code class="language-swift">func setZeroes(_ matrix: inout [[Int]]) {
    if matrix.count == 0 { return }

    var rows: Set&lt;Int&gt; = []
    var cols: Set&lt;Int&gt; = []

    for i in 0..&lt;matrix.count {
        for j in 0..&lt;matrix[i].count {
            if matrix[i][j] == 0 {
                rows.insert(i)
                cols.insert(j)
            }
        }
    }

    for i in 0..&lt;matrix.count {
        for j in 0..&lt;matrix[i].count {
            if matrix[i][j] != 0 &amp;&amp; (rows.contains(i) || cols.contains(j)) {
                matrix[i][j] = 0
            }
        }
    }
 }</code></pre>
<p> <img src="https://images.velog.io/images/yoonah-dev/post/5b0b0c26-cc0a-42da-8f26-110f2442a9af/%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%202021-08-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.56.17.png" alt=""></p>
<p>처음엔 오히려 늘었습니다..😂 역시 Leetcode의 Runtime은 오락가락이네요..
그래도 두번째 돌렸을 때는 많이 떨어졌어요.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/c9afaee6-7836-4e3f-be50-21b7d23c97c3/%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%202021-08-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.56.49.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Reverse Integer]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Reverse-Integer</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Reverse-Integer</guid>
            <pubDate>Sat, 21 Aug 2021 10:10:05 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions</strong>
<strong>Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/127/strings/880/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection String의 두번째 문제인 <code>Reverse Integer</code>를 풀어봤습니다.</p>
<p><code>Reverse Interger</code>문제도 저번 <code>Reverse String</code>만큼 쉬웠습니다. 말 그대로 Integer를 <code>Reverse</code>시키는 겁니다.</p>
<p>조금 걸리는 부분이 있었다면, </p>
<ol>
<li>음수도 들어올 수 있기때문에 reverse할 때 - 부호를 처리하는 점</li>
<li>2의 31제곱 이상, -2의 31제곱 이하 그리고 0은 꼭 0를 return해야 한다는 점
이었습니다.</li>
</ol>
<p>이 부분들만 고려하면서 코드를 짜면 쉽게 짤 수 있었습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>저는 위에 있는 부분들을 처리하기 위해서 if문을 통해 두 가지 조건으로 나눴습니다.
첫 번째는 0보다 큰 수가 들어오는 부분, 두 번째는 0보다 작은 수가 들어오는 부분으로 했어요.
0은 처음에 들어왔을 때, <code>guard</code>를 통해서 처리했습니다.</p>
<p><code>x가 0보다 클 땐</code>
일단 수를 reverse하고 Int로 변환합니다. 그리고 변환된 수가 2의 31제곱 이상이면 0를 return해주고 아니면 해당 수를 return 합니다.</p>
<p><code>x가 0보다 작을 땐</code>
수에서 -를 제외하고 reverse를 시킨 후 Int로 변환합니다. 그리고 변환된 수에 -를 붙인 값이 -2의 31제곱 이하면 0를 return하고 아니면 해당 수를 return합니다.</p>
<pre><code class="language-swift">func reverse(_ x: Int) -&gt; Int {
    guard x != 0  else { return 0 }

    if x &gt; 0 {
        let reverse = String(&quot;\(x)&quot;.reversed())

        if let reverse = Int(reverse) {
            guard reverse &lt; Int(pow(2.0, 31)) else { return 0 }
            return reverse
        }
        return 0
    } else {
        let reverse = String(&quot;\(-x)&quot;.reversed())

        if let reverse = Int(reverse) {
            guard -reverse &gt; Int(pow(-2.0, 31)) else { return 0 }
            return -reverse
        }
        return 0
    }
}</code></pre>
<p>Runtime은 <code>4ms</code>정도 걸렸습니다.</p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>2번째 방법도 1번째 방법과 비슷한 형태로 짜여져 있습니다. 
다른점이 있다면 첫번째는 if문을 사용해서 음수, 양수를 나눴다면 2번째 방법은 isNegative라는 Boolean값을 만들어서 음수일 때의 처리를 따로 했습니다.</p>
<p>그리고 reversed()라는 함수를 사용하지 않고 for문을 돌려서 character를 하나씩 받아서 처리를 해줬습니다.</p>
<pre><code class="language-swift">func reverse(_ x: Int) -&gt; Int {
        var stringNum = String(x)
        var newStr = &quot;&quot;
        var isNegative = false

        for char in stringNum {
            if char == &quot;-&quot; {
                isNegative = true
                continue
            }
            newStr = &quot;\(char)&quot; + newStr
        }

        if isNegative {
            newStr = &quot;-&quot; + newStr
        }

        guard let numToReturn = Int(newStr) else { return 0}
        if (numToReturn &gt; 2147483647) || (numToReturn &lt; -2147483648) { return 0}
        return numToReturn
}</code></pre>
<p> <img src="https://images.velog.io/images/yoonah-dev/post/02898bfd-64eb-4b02-96e7-cb66ab4578ba/%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%202021-08-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.08.19.png" alt=""></p>
<p> 요정도의 시간이 나오긴 하는데, 1번째 방법도 그렇고 Runtime이 계속 바뀌더라구요.
 <code>0~8ms</code>를 왔다갔다 하는 거 같습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) 3Sum]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-3Sum</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-3Sum</guid>
            <pubDate>Tue, 17 Aug 2021 05:38:05 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions</strong>
<strong>Medium Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-medium/103/array-and-strings/776/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌕 🌑 🌑 (중)</strong></p>
<hr>
<p><code>Array</code>에서 Easy Collection은 끝났기 때문에 Medium Collection으로 넘어왔습니다.!</p>
<p>역시나 어려웠고, 쉽게 풀리지 않았습니다.🥲
첫 문제부터 저는 1시간만에 Solution를 찾아 봤네요.. 열심히 해야겠습니다.</p>
<p><code>3Sum</code>은 배열안에 있는 숫자들 중에 3개 숫자의 합이 0이 되는 조합을 찾아서 배열 형태로 배열에 넣는 문제였습니다.</p>
<p>처음에 문제를 풀었을 때, 되겠다 싶었는데. 나타날 다양한 케이스를 고려하지 않아서 각 케이스에서 <strong>Wrong</strong>이 뜰 때마다 보수공사를 했습니다.. 결론적으로 이 코드는 못 쓰겠다 싶어서 다른 방식들을 찾아봤고 결과적으로 좋은 코드를 찾을 수 있었습니다.</p>
<p>정렬하는 방식들을 정말 많이 공부해야겠어요...🥲</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p><strong>해당 방식은 Wrong Answer만 나왔습니다.</strong></p>
<p>문제를 보자마자 정렬을 시킨 다음, 앞 숫자부터 2개씩 묶어서 뒤에 숫자와 합이 0이 되는지 봐야지. 라고 생각했지만. 너무 많은 케이스를 고려 안했습니다..🥲</p>
<p>당연히 nums안에 있는 케이스가 3개 미만이라면 3개의 sum를 찾을 수 없기 때문에 빈 배열을 return했고, nums를 sorted한 값들이 들어있는 <code>sortedNums</code>의 가장 첫 번째값이 0보다 크다면 아무리 세 값을 더해도 0이 나올 일이 없다는 뜻이기에 빈 배열을 return해줬습니다.</p>
<p>그리고 아래 코드에서 볼 수 있듯이 두 값을 묶은 다음(0 이하인 두 값), 0 이상인 한 값과 더 해서 sum이 나오면 <code>answers</code>에다가 넣어줬습니다.</p>
<p>하지만 문제가 많더라구요.. 
먼저 중복이 생기는 문제가 나와서 return할 때 Set으로 감싸주는 일을 했어요.
그 다음으로 생긴 문제가 양의 정수 두 개가 음의 정수 한 개와 더해졌을 때 0이 되는 케이스가 있다는 겁니다.
이 케이스를 다루려면 완전히 코드를 새로 짜는 게 낫다는 결론이 나서 다른 코드를 찾아봤습니다.</p>
<pre><code class="language-swift">func threeSum(_ nums: [Int]) -&gt; [[Int]] {
    guard nums.count &gt;= 3 else { return [] }

    let sortedNums = nums.sorted()
    guard sortedNums[0] &lt;= 0 else { return [] }

    var answers: [[Int]] = []
    for i in 1..&lt;sortedNums.count where sortedNums[i-1] &lt;= 0 {
        let sum = sortedNums[i] + sortedNums[i-1]

        if sum &gt; 0 { continue }

        if i+1 &gt; sortedNums.count-1 { break }

        for j in (i+1...sortedNums.count-1).reversed() where sortedNums[j] &gt;= 0 {
            if sum + sortedNums[j] == 0 {
                answers.append([sortedNums[i-1], sortedNums[i], sortedNums[j]])
                break
            }
        }
    }

    return Array(Set(answers))
}</code></pre>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>결론적으로 답이 된 코드입니다.</p>
<p>일단 세팅하는 코드는 비슷합니다. 다른 점은 풀어가는 방식이죠!
왜 이 생각을 못했지 싶었습니다..</p>
<p><code>first</code> <code>current</code> <code>last</code> 이 세가지 숫자를 둘 겁니다.
<code>first(i)</code>는 맨 앞에서부터 오는 값,
<code>last(k)</code>는 맨 뒤에서부터 오는 값,
<code>current(j)</code>는 <code>first</code>와 <code>last</code> 사이 값을 찾을 겁니다.</p>
<p><code>first</code>는 for문을 통해서 차례대로 받아올 것이고, 
<code>current</code>는 항상 <code>first+1</code>한 값에서 시작할 겁니다.
<code>last</code>는 맨 뒤(<code>count - 1</code>)에서 시작하면 되겠죠?</p>
<p>중간 중간 <code>sorted[i] == sorted[i-1]</code>, <code>sorted[j] == sorted[j-1]</code>인 경우를 넘겨서 중복이 생길 경우들도 없애줄 거예요.</p>
<p>그리고 <code>current</code>가 <code>last</code>보다 작을 때에만 <code>first + current + last</code>의 값을 구하고 그 값이 0이 맞다면 result에 넣을 겁니다. 
만약에 sum보다 작다면, <code>current(j)</code>값을 위로 올려서 sum값을 올리겠죠.
반대로 sum보다 크다면, <code>last(k)</code>의 값을 내려서 sum값을 내릴겁니다.</p>
<p>해당 코드는 이러한 과정을 통해서 진행됩니다.</p>
<pre><code class="language-swift">func threeSum(_ nums: [Int]) -&gt; [[Int]] {
    guard nums.count &gt;= 3 else { return [] }

    let sorted = nums.sorted()
    var result: [[Int]] = []
    for i in 0..&lt;sorted.count {
        if i != 0, sorted[i] == sorted[i-1] { continue }

        var j = i + 1
        var k = sorted.count-1

        while j &lt; k {
            let sum = sorted[i] + sorted[j] + sorted[k]
            if sum == 0 {
                result.append([sorted[i], sorted[j], sorted[k]])
                j += 1
                while j &lt; k, sorted[j] == sorted[j-1] {
                    j += 1
                }
            } else if sum &lt; 0 {
                j += 1
            } else {
                k -= 1
            }
        }
    }

    return result
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/4233291c-0cea-4824-b2a0-0e811c88cff7/%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%202021-08-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.47.22.png" alt=""></p>
<p>세 값을 나눠서 진행하기 때문에 위에 코드처럼 2개씩 묶기 때문에 나타나는 문제도 해결되고, 심지어 중복도 나타날 일이 없습니다. 
<code>first</code>, <code>last</code>, <code>current</code>를 따로 나눠서 배열 문제를 해결해본 적이 처음이라서 바로 생각하지 못한 거 같습니다. 이제 알게됐으니 열심히 사용해보려구요. 너무 좋네요👍</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Reverse String]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Reverse-String</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Reverse-String</guid>
            <pubDate>Tue, 17 Aug 2021 03:52:13 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions</strong>
<strong>Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/127/strings/879/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌑 🌑 🌑 🌑 (최하)</strong></p>
<hr>
<p>Easy Collection String의 첫번째 문제인 <code>Reverse String</code>를 풀어봤습니다.
벌써 <code>Array</code>가 끝났네요. </p>
<p><code>Reverse String</code>문제는 매우 쉬웠습니다. 말 그대로 String를 <code>Reverse</code>시키는 겁니다.</p>
<p>제가 첫번째로 풀었던 코드는 고작 한 줄 밖에 되지않아요..</p>
<p>그럼 <code>Reverse String</code>를 코드와 함께 풀어보겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>아마 알고리즘을 해보신 분들이라면 제목을 보자마자 &quot;이걸 써야겠다&quot; 싶을 거예요.
제목 그대로 <code>Reverse</code>를 쓰는 겁니다.</p>
<pre><code class="language-swift">func reverseString(_ s: inout [Character]) {
    s.reverse()
}</code></pre>
<p>끝났습니다. 이게 다입니다.
<code>reverse()</code>라는 함수는 주어진 배열을 완전 반대로 알아서 뒤집어 줍니다.</p>
<p>Runtime은 적당히 나온 거 같아요.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/bacd52a5-e6ad-42f3-881e-3e187a035c1c/%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%202021-08-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.32.15.png" alt=""></p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>2번째 방식은 가장 Runtime이 빨랐던 코드를 가져왔습니다.</p>
<p>배열의 대칭되는 부분에 있는 숫자들을 바꿔주는 코드였어요.
어차피 대칭되는 위치에 있는 숫자들을 사용할 생각이어서 <code>middle</code>를 놓았습니다. for문으로 전체 숫자를 보지 않아도 되기 때문에 <code>middle</code>를 두는 편이 더 효과적입니다.</p>
<p>그리고 temp를 둬서 두 숫자의 위치를 바꿔줬습니다.
전형적인 swap 로직이었어요.</p>
<pre><code class="language-swift">func reverseString(_ s: inout [Character]) {
    let middle = Int(s.count / 2)
    for index in 0..&lt;middle {
        let temp = s[index]
        s[index] = s[s.count - index - 1]
        s[s.count - index - 1] = temp
    }
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/64e561e4-1482-4ab0-a403-69c0cd2dbe62/%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%202021-08-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.35.56.png" alt=""></p>
<p>분명히 더 빠른 코드였는데, 제가 돌리니깐 1번 방식보다 느리게 나왔습니다. 
Leetcode가 돌리면서 계속 차이가 있는 거 같아요..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Rotate image]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Rotate-image</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Rotate-image</guid>
            <pubDate>Mon, 16 Aug 2021 05:57:04 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/770/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection의 열한번째 문제이자 Array 마지막 문제인 Rotate image를 풀어봤습니다.</p>
<p>Rotate image는 주어진 이차원배열 형식의 값들을 90도 회전시키는 문제였습니다.</p>
<p>문제 자체에 대한 접근은 쉬웠는데, 문제에서 조건으로 내걸었던 <strong>&quot;다른 배열로 옮기지 말고 현재 배열에서 변경해라&quot;</strong> 라는 말이 문제를 어떻게 풀어야 할 지 생각을 하게 만들었습니다.</p>
<p>같이 코드를 보면서 설명 진행해볼게요.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>일단 문제가 한 번에 풀렸습니다. 저번 스토쿠 문제가 저한테는 어려웠기 때문에 이번 문제도 당연 어려울 거라는 생각때문인지 고민을 많이 했습니다.
하지만 간단하게 이중 for문으로 풀이를 완료했어요. 다행입니다..🥲</p>
<p>문제 자체에서는 다른 배열로 옮기지 말라고 했지만, 저는 다른 배열로 옮기는 수 밖에는 생각이 안들어서 일단 배열 하나를 만들고 <code>matrix</code>에 있는 값들을 옮겨줬어요.</p>
<p>그리고 해당 배열에서 <code>row</code>를 하나씩 빼내오면서 <code>row</code>안의 값을 <code>enumerated()</code>를 사용해서 <code>index</code>와 함께 하나씩 빼줬습니다.
그러고나서 <code>matrix</code>의 맨 뒤 <code>column</code>부터 하나씩 채워갔어요.</p>
<p>어떤 방식을 사용했냐면 <code>matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]</code>라고 했을 때, 
90도로 돌린다면 <code>matrix = [[7, 4, 1], [8, 5, 2], [9, 6, 3]]</code>이 들어옵니다.
잘 생각해보면 각 배열의 맨 첫 번째 숫자들이 첫 번째 배열에 모이고, 두 번째 숫자들은 두 번째 배열, 세 번째 숫자들은 세 번째 배열에 모이는 걸 볼 수 있습니다.
그리고 순서는 뒤부터 들어오는 걸 볼 수 있어요. </p>
<p>해당 방식을 이용해서 첫 번째 배열 숫자들은 맨 마지막 열에 순서대로 배치하고, 중간 배열 숫자들은 중간 열에 순서대로 배치, 마지막 배열 숫자들은 첫 번째 열에 순서대로 배치했습니다.</p>
<pre><code class="language-swift">func rotate(_ matrix: inout [[Int]]) {
    guard matrix.count != 1 else { return }
    let temp = matrix
    var column = matrix.count - 1

    for row in temp {
        for (index, i) in row.enumerated() {
            matrix[index][column] = i
        }
        column -= 1
    }
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/74cd10f0-3bbe-41ae-b6d4-e99214ba3f5f/%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%202021-08-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.10.31.png" alt=""></p>
<p>Runtime은 <code>8ms</code>로 괜찮게 나왔습니다!! 하지만 8ms보다 빠른 Runtime을 가진 코드가 있더라구요.</p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>이번 코드는 다른 배열을 추가하지 않고 해당 배열 안에서만 숫자 변경을 진행했습니다.
처음에 이런 방식을 생각하긴 했지만 어떻게 내가 원하는 숫자들끼리 변경하지 싶어서 시도해보지 않은 방식이었는데, 이렇게 하면 될 걸 싶었습니다.</p>
<p>일단 해당 코드는 두번의 이중 for문을 거쳐요. 그럼에도 빠른 이유는 <code>matrix</code>가 제일 커도 n이 20이라는 점과 배열을 하나만 사용하기 때문이 아닐까 싶습니다.</p>
<p>첫 번째 이중 for문은 각각 자기 자리와 상반되는 위치에 있는 숫자를 서로 바꿔줍니다.
처음에 이 코드를 보고 굳이 이렇게 왜 바꾸지 싶었습니다. 이해하고 보니, 해당 코드를 거치고 난 후에 우리가 원하는 숫자들끼리 한 배열에 묶여있게 된다는 걸 알게 됐습니다..! </p>
<p>두 번째 이중 for문은 이제 같은 배열에 있는 숫자들끼리 자리를 바꿔줍니다.
아마 위에 for문을 거치고 난 배열은 우리가 원하는 배열과는 완전히 반대로 생겼을 거예요. <code>reversed()</code>를 해주고 싶게 생겼습니다.
그 반대로 뒤집는 걸 두 번째 이중 for문이 해줄겁니다.</p>
<pre><code class="language-swift">func rotate(_ matrix: inout [[Int]]) {
    let n = matrix.count

    for i in 0..&lt;n {
        for j in i..&lt;n {
            let temp  = matrix[i][j]
            matrix[i][j] = matrix[j][i]
            matrix[j][i] = temp
        }
    }

    for i in 0..&lt;n {
        for j in 0..&lt;n/2 {
            let temp  = matrix[i][j]
            matrix[i][j] = matrix[i][n - 1 - j]
            matrix[i][n - 1 - j] = temp
        }
    }
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/80c93ebb-6b34-4953-86d5-467f6c4e9223/%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%202021-08-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.20.46.png" alt=""></p>
<p>분명, 첫 번째 문제 풀 때 해당 코드보다 빠르다고 되어 있었는데 제가 돌려보니 더 느리게 나왔습니다. 
<code>8ms</code>나 <code>12ms</code>나 큰 차이는 아니니깐요.!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Valid Sudoku]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Valid-Sudoku</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Valid-Sudoku</guid>
            <pubDate>Thu, 12 Aug 2021 06:15:17 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/769/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌕 🌑 🌑 (중)</strong></p>
<hr>
<p>Easy Collection의 열번째 문제인 Valid Sudoku를 풀어봤습니다.</p>
<p>Valid Sudoku는 주어진 이차원 배열 속 스도쿠 숫자들을 통해 해당 스도쿠가 문제가 없는지 확인하는 문제였습니다.</p>
<p>기본적인 스도쿠 규칙대로 같은 행, 열에 같은 숫자가 있으면 안되고, 같은 3*3 칸 속에도 같은 숫자가 있으면 안됩니다. 주어진 이차원 배열이 해당 규칙을 따르는지 확인하면 됩니다.</p>
<p>저는 행, 열을 확인하는 로직은 바로 생각이 났지만 3*3 규칙에 해당하는 로직이 바로 떠오르지 않아서 고민 끝에 Solution 찬스를 썼습니다.</p>
<p>전에 C++로 알고리즘을 짰을 때, 썼던 dfs 방식이 생각나긴 했는데 그 비슷한 방식으로 하던거 같아요!</p>
<p>Solution 코드들을 같이 봅시다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>첫번째 방식은 row, colum, box(3*3짜리 칸)를 확인하는 Set를 따로 세 개씩두고 확인하는 방식이었습니다.</p>
<p>해당 방식은 저번에 했던 Two Sum때와 동일하게 <code>enumerated()</code>를 사용했는데요.</p>
<p>첫 for문에서는 characterRow 자체를 빼오고 두번째 for문에서는 그 row안에 있는 character들을 하나씩 빼오는 방식이었습니다. 그리고 <code>enumerated()</code>를 사용해서 해당 character의 index를 함께 가져와서 Set으로 만들어져있는 row, columns, boxes에 넣어줬습니다.</p>
<p>만약, 해당 character가 <code>contains = true</code>에 해당한다면 조건에 부합하지 않기 때문에 결론적으로 false를 return하고 아니면 true를 return하도록 해줬습니다.</p>
<p>row, column, box별로 index를 둬서 character가 있는 자리를 표시하도록 했습니다. <code>/3</code>를 해준 이유는 각 칸별로 index를 잡기 위함이에요. 행, 열 총 3*3칸이 한 box를 이루고 있기 때문이죠.</p>
<pre><code class="language-swift">func isValidSudoku(_ board: [[Character]]) -&gt; Bool {
    let size = board.count
    var columns = (0..&lt;size).map { _ in Set&lt;Character&gt;(minimumCapacity: size) }
    var boxes = (0..&lt;size).map { _ in Set&lt;Character&gt;(minimumCapacity: size) }

    for (rowIndex, characterRow) in board.enumerated() {
        var row = Set&lt;Character&gt;()
        for (columnIndex, character) in characterRow.enumerated() {

            if character == &quot;.&quot; {
                continue
            }

            let rowBoxIndex = Int(rowIndex / 3)
            let columnBoxIndex = Int(columnIndex / 3)
            let boxIndex = columnBoxIndex + (rowBoxIndex * (size/3))

            if row.contains(character) {
                return false
            }
            row.insert(character)

            let column = columns[columnIndex]
            if column.contains(character) {
                return false
            }
            columns[columnIndex].insert(character)

            let box = boxes[boxIndex]
            if box.contains(character) {
                return false
            }
            boxes[boxIndex].insert(character)
        }
    }
    return true
}</code></pre>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>두 번째 방법도 첫 번째 방법과 비슷합니다. 조금 다른 부분은 String으로 넣어줬고, row, column, grid에 각각 직접 정한 String값을 넣었어요.</p>
<p>하지만 전체적인 방식은 아주 비슷합니다. <code>contains</code>되어있는지 확인하고 아니라면 <code>insert</code> 맞다면 false를 return합니다.</p>
<p>위에서는 <code>enumerated()</code>를 사용한 것과는 다르게 0부터 9까지 이중 for문을 돌렸어요. 어차피 스도쿠 판은 9*9 크기로 한정되어 있기 때문에 그렇습니다.</p>
<p>위에 보다 좀 더 이해하기 쉽고 생각하기도 쉬웠던 로직 같습니다.</p>
<pre><code class="language-swift">func isValidSudoku(_ board: [[Character]]) -&gt; Bool {
    var setSudoku = Set&lt;String&gt;()

    for i in 0..&lt;9 {
        for j in 0..&lt;9 {
            if board[i][j] != &quot;.&quot; {
                let value = board[i][j]
                let row = &quot;row:\(i):\(value)&quot;
                let column = &quot;column:\(j):\(value)&quot;
                let grid = &quot;row:\(i / 3):\(j / 3):\(value)&quot;

                if setSudoku.contains(row) || setSudoku.contains(column) || setSudoku.contains(grid) {
                    return false
                } else {
                    setSudoku.insert(row)
                    setSudoku.insert(column)
                    setSudoku.insert(grid)
                }
            }
        }
    }
    return true
}</code></pre>
<p>저는 당연히 있는 숫자들끼리 비교하려고 했는데, 다른 Set를 만들 생각을 왜 못했는지 모르겠네요 🥲
더 노력해야겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Two Sum]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Two-Sum</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Two-Sum</guid>
            <pubDate>Sat, 07 Aug 2021 02:26:53 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/546/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection의 아홉번째 문제인 Two Sum를 풀어봤습니다.</p>
<p>Two Sum 문제는 배열 안에 있는 두 원소의 합이 들어오는 Target과 같다면 그 두 값의 index를 배열로 return해주는 문제였습니다.</p>
<p>처음 생각한 방식이 시간 초과가 날 것 같아서 걱정이었는데, 생각할 수 있는 가장 기본적인 로직임에도 불구하고 시간 초과는 발생하지 않았습니다!</p>
<p>해당 코드말고도 생각하지 못했던 방식으로 풀어낸 방법들이 있어서 해당 코드들도 들고와봤습니다.</p>
<p>코드를 보면서 설명드릴게요.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>제일 기본적이고 바로 생각할 수 있는 방식이었습니다.</p>
<p>첫번째 원소부터 시작해서 마지막 원소까지 맞는 짝을 샅샅히 뒤지는 방식입니다.
찾아내기 위해서 이중 for문을 사용했구요. <code>target</code>값과 <code>index</code>에 해당하는 값의 차가 <code>j</code>에 해당하는 값과 같다면 두 수의 합이 <code>target</code>이라는 것이기에 <code>[index, j]</code>를 return해줬습니다.</p>
<p>기본적이기도 하고 이중for문을 사용했기 때문에 당연히 시간 초과 에러가 날 줄 알았는데, 나지 않았어요!!</p>
<pre><code class="language-swift">func twoSum(_ nums: [Int], _ target: Int) -&gt; [Int] {
    for index in nums.indices {
        for j in index+1..&lt;nums.count {
            if target - nums[index] == nums[j] {
                return [index, j]
            }
        }
    }

    return []
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/0ea049d9-c131-4ad8-a94b-acc496a9375e/%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%202021-08-07%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.52.54.png" alt=""></p>
<p>하지만 예상했던대로 Runtime이 아주 길었습니다..</p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>문제를 맞추자마자 가장 빠른 Runtime를 가진 답변을 찾아봤더니, 이거였습니다.</p>
<p>전체적으로 빠른 Runtime를 가진 답변들이 다 <code>Dictionary</code>를 사용했더라구요. 또 <code>Dictionary</code>를 응용하지 못해서 아쉬웠습니다.😫</p>
<p>해당 방식의 풀이는 이러합니다.</p>
<p>일단 <code>nums</code>에 있는 숫자들을 불러와서 해당 숫자가 <code>target-num</code> index에 해당하는 값이 있다면 그 index와 현재 index를 return하는 방식입니다.
만약에 해당하는 숫자가 없다면 <code>Dictionary</code>에 index와 함께 넣어주는거죠.</p>
<p>예를 들어, <code>nums = [2, 7, 11, 15]</code>이고 <code>target = 9</code>라면
첫번째 턴에 <code>numDictionary[9-2]</code>값을 찾아보겠죠? 하지만 아무것도 없기 때문에 <code>numDictionary[2] = 0</code>를 넣어줄겁니다.
두번째 턴에 <code>numDictionary[9-7]</code>값을 찾아보겠죠? 아까 넣어준 2 인덱스 값이 0이기 때문에 <code>match = 0</code>일 거고, 결론적으로 <code>[0, 1]</code>를 return할 겁니다.</p>
<pre><code class="language-swift">func twoSum(_ nums: [Int], _ target: Int) -&gt; [Int] {
    var numDictionary = [Int: Int]()
    var index = 0
    for num in nums {
        if let match = numDictionary[target - num] {
            return [match, index]
        } else {
            numDictionary[num] = index
        }
        index += 1
    }
    return []
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/21e29aa0-fc83-452e-a404-cf2f361bac60/%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%202021-08-07%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.04.54.png" alt=""></p>
<p>Runtime 속도도 굉장히 빠릅니다.👍</p>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p>3번째 방법은 2번째 방법과 비슷하면서도 조금 다릅니다.</p>
<p>동일하게 <code>Dictionary</code>를 쓰는 건 맞지만 for문을 돌리는 방식이 달라요.
해당 방식은 <code>nums.enumerated()</code>를 사용했습니다. 저 방식을 사용하면 <code>(index, num)</code>에 해당하는 두 값이 나와요. 
예를 들어서 &quot;Swift&quot;라는 문자열을 <code>.enumerated()</code>하게 된다면 <code>[ 1: &quot;S&quot;, 2: &quot;w&quot;, 3: &quot;i&quot;, 4: &quot;f&quot;, 5: &quot;t&quot; ]</code> 요렇게 된다는거죠.</p>
<p>저러한 방식을 사용해서 <code>nums = [2, 7, 11, 15]</code>에서 <code>index</code>와 <code>num</code>값을 한 번에 가져오는 겁니다.</p>
<p>안에서 비교하는 방식은 위와 같은데 조금 다른건 처음 비교할 때 target에서 num를 뺀 값이 아닌 그 값 자체의 index를 찾는 방식입니다. 그리고 값이 없을 때 <code>Dictionary</code>에 저장하는 방식도 <code>target - num</code>한 값에 값으로 현재의 <code>index</code>를 넣습니다.</p>
<p>위에 코드를 이해한다면 3번째 방식도 쉽게 이해할 수 있을 것이라고 생각이 듭니다.</p>
<pre><code class="language-swift">func twoSum(_ nums: [Int], _ target: Int) -&gt; [Int] {
    var complement = [Int: Int]()
    for (index, num) in nums.enumerated() {
        if let prevIndex = complement[num] {
            return [prevIndex, index]
        } else {
            complement[target - num] = index
        }
    }
    return []
}</code></pre>
<p>항상 방식이 다양하게 사용할 수 있지만, 계속 배열을 쓰게 되는 거 같아요. 
<code>Dictionary</code>나 요런 다양한 자료구조들이 조금 익숙해지면 자주 사용하게 되겠죠?😂</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Move Zeroes]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Move-Zeroes</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Move-Zeroes</guid>
            <pubDate>Thu, 05 Aug 2021 06:23:49 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/567/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection의 여덟번째 문제인 Move Zeroes를 풀어봤습니다.</p>
<p>문제 제목 그대로, 0인 값들을 뒤쪽으로 옮기는 문제였습니다.</p>
<p>이번 문제에서는 들어오는 nums의 값이 inout으로 표시가 되어서 직접 사용할 수 있었는데요, 항상 inout으로 되어 있는 문제는 새로운 배열을 만드는 것보다 그 자체에서 값을 바꿨을 때 효율이 컸어서 이번에도 그렇게 해보려고 노력했습니다.</p>
<p>코드를 보면서 설명드리겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>이번에는 1번째 방식으로 한 번에 문제를 풀었습니다.</p>
<p>저는 일단 위에서 말한 것처럼 지금 주어진 배열에서 문제를 바로 풀기 위해서 nums에서 0을 찾으면 해당 0를 지우고 맨 뒤로 0를 넣는 방식으로 코드를 짰습니다.</p>
<p>그렇게 되면 index가 0에서 바로 1로 계속해서 +1되는 방식이 아닌 해당 수가 0이 아니라면 +1되는 방식으로 진행되어야 합니다. 그러다보니 index를 조건문에 넣게 되면 1개라도 0이 있을 경우 조건을 영영 못 맞출 수도 있습니다.</p>
<p>그래서 따로 cnt라는 값을 둬서 한 턴마다 +1되도록 했습니다. 이렇게 했을 경우 원소의 개수에 맞게 조건문을 돌릴 수 있어서 좋았습니다.</p>
<pre><code class="language-swift">func moveZeroes(_ nums: inout [Int]) {
    guard nums.count &gt; 1 else { return }

    var index = 0
    var cnt = 0

    while cnt &lt; nums.count {
        if nums[index] == 0 {
            nums.remove(at: index)
            nums.append(0)
        } else {
            index += 1
        }
        cnt += 1
    }
}</code></pre>
<p>Runtime은 32ms정도로 좋았습니다.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/ebc656df-d757-4dd7-a4ca-c4b568688023/%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%202021-08-05%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.00.35.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Plus One]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Plus-One</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Plus-One</guid>
            <pubDate>Thu, 05 Aug 2021 04:51:09 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/559/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection의 일곱번째 문제인 Plus One를 풀어봤습니다.</p>
<p>처음에 문제를 잘못 파악했을 때 쉬운 문제인 줄 알았는데, 생각보다 머리를 써야하는 문제였습니다.</p>
<p>Array의 맨 마지막 숫자에 +1를 했을 때 값을 Array로 출력하는 문제였는데요.
문제는 +1했을 때 해당값이 10이 되면 해당 부분을 0으로 바꿔주고 앞 부분들에 해당 carry가 +1되어야 하는 문제였어서 그런 부분들이 조금 까다로웠습니다.</p>
<p>코드를 보면서 설명드리겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p><strong>잘못 이해한 방식입니다.</strong></p>
<p>문제를 보자마자 &quot;뭐야, 맨 마지막 배열 원소에 +1 하면 되잖아?&quot; 라고 생각해서 푼 방식입니다.
실제로 맨 뒤 숫자가 9 미만이라면 carry가 생길 일이 없기 때문에 해당 방식이 맞지만, 9라면 해당 방식이 완전히 잘못 됐기 때문에 2번 방식부터는 9를 생각하면서 풀었습니다.</p>
<pre><code class="language-swift">func plusOne(_ digits: [Int]) -&gt; [Int] {
        var num = digits

        num[digits.count-1] += 1

        return num
}</code></pre>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p><strong>실패한 방식입니다.</strong></p>
<p>+1를 어떻게 해주면 좋을까 하다가. 배열에 있는 원소들을 자리에 맞게 10의 거듭제곱을 곱해서 숫자로 만든 다음, 1를 더한 값을 다시 배열에 넣으면 되겠다! 싶었습니다.</p>
<p>그렇게 하면 따로 1를 더하는 로직을 짜지 않아도 숫자니깐 자연스럽게 더해지겠죠?</p>
<pre><code class="language-swift">func plusOne(_ digits: [Int]) -&gt; [Int] {
    var num: [Int] = []
    var sum = 0

    for i in 0..&lt;digits.count {
        sum += digits[i] * Int(pow(10, Double(digits.count - (i + 1))))
    }

    sum += 1

    for n in &quot;\(sum)&quot; {
        num.append(Int(String(n))!)
    }

    return num
}</code></pre>
<p>하지만 문제가 생겼습니다. 가장 긴 배열의 길이가 100이기 때문에 100의 100 거듭제곱까지 나타나게 되는데, 해당 길이가 Int가 충족시킬 수 있는 길이를 넘어서 Fatal Error가 발생합니다.</p>
<p>혹시나 싶어서 UInt로도 진행해봤는데요. 똑같은 Fatal Error가 발생했습니다..🥲
<img src="https://images.velog.io/images/yoonah-dev/post/866add1a-33ec-4227-a5a2-1c36191620bb/%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%202021-08-05%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.17.26.png" alt=""></p>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p>그렇다면 어떻게 +1를 해줄까 싶었습니다.</p>
<p>문득 1번째 방법에서 말했듯 9가 아니라면 다 carry를 생각해줄 필요가 없는데, 제가 그냥 배열에서 +1 해도 되는 걸 숫자로 푼 다음에 다시 배열로 만드는 헛수고를 하고 있다는 걸 깨달았습니다.</p>
<p>그럼 일단, +1를 하고서 맨 뒤가 10이라면 carry 문제를 해결하자 라는 결론이 나왔습니다.</p>
<p>맨 뒤 숫자부터 보면서 해당 숫자가 9보다 크다면 10으로 나눈 나머지 값을 값으로 가지고 해당 수의 앞에 있는 수에 +1를 더해줬습니다.</p>
<p>하지만 해당 수가 맨 앞에 있는 숫자라면 어떡하지? 라는 생각이 들더라구요.
<strong>그럼 그 앞에 1를 넣어주자</strong> 라는 결론이 나왔습니다.
<code>insert</code>를 사용해서 원하는 위치에 1를 넣도록 코드를 짰습니다.</p>
<pre><code class="language-swift">func plusOne(_ digits: [Int]) -&gt; [Int] {
    var num = digits

    num[digits.count - 1] += 1

    for i in num.indices.reversed() {
        if num[i] &gt; 9 {
            num[i] = num[i] % 10

            if i == 0 {
                num.insert(1, at: 0)
            } else {
                num[i - 1] += 1
            }
        }
    }

    return num
}</code></pre>
<p>Runtime도 4ms밖에 안걸렸습니다.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/812c3174-7c0d-4bc5-a264-81037d444604/%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%202021-08-05%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.29.28.png" alt=""></p>
<p>매일 코드를 짜면 감이 좀 잡힐 것 같았는데, 아직은 Swift에서 사용할 수 있는 자료구조를 많이 몰라서 그런지 쉽게 앞으로 나아가지질 않네요🥲
더 갈고 닦아야겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Intersection of Two Arrays II ]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Intersection-of-Two-Arrays-II</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Intersection-of-Two-Arrays-II</guid>
            <pubDate>Tue, 03 Aug 2021 04:52:28 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/674/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection의 여섯번째 문제인 Intersection of Two Arrays II를 풀어봤습니다.</p>
<p>이번 문제는 제목과 동일하게 두개의 배열에 있는 원소들의 교집합을 찾는 문제였습니다.</p>
<p>두 Array에 있는 공통적인 원소들을 찾는 것이라서 간단해보일 수 있지만 들어오는 Array에 따라 다양한 조건을 충족시켜줘야 했기 때문에 조금 복잡한 감이 있었습니다.</p>
<p>이번 코드들은 다양한 시도 끝에 답이 나왔기 때문에 답을 보고 싶으신 분들은 4️⃣ 번째 방법부터 보시면 되겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p><strong>실패한 방식입니다.</strong></p>
<p>처음에 교집합이라는 단어를 보자마자 <code>Set</code>를 써야겠구나. 생각했습니다.
<code>Set</code>에는 <code>intersection</code>이라는 직접 교집합을 찾아주는 함수가 있습니다. </p>
<p>이걸 이용해서 교집합을 찾으면 되겠구나. 라고 생각했는데, 아니었습니다.</p>
<p>예를 들어, <code>nums1 = [1, 2, 2, 1]</code> <code>num2 = [1, 1]</code> 이라고 한다면 답은 <code>[1, 1]</code>이 나와야 합니다.
하지만<code>Set</code>은 자체적으로 중복을 제거해버리기 때문에 답으로 나오는 값은 <code>[1]</code>뿐인거죠.</p>
<pre><code class="language-swift">func intersect(_ nums1: [Int], _ nums2: [Int]) -&gt; [Int] {
    var setNums1 = Set&lt;Int&gt;()

    for i in nums1 {
        setNums1.insert(i)
    }

    setNums1 = setNums1.intersection(nums2)

    return Array(setNums1)
}</code></pre>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p><strong>또 다른 실패 방식</strong></p>
<p>그럼 중복이 생길 수 있게 해야겠다. 생각했습니다.</p>
<p>일단 두 배열 중 더 짧은 코드로 for문을 돌리면서 긴 배열에 있는 숫자가 <code>contain</code>되어 있으면 result라는 배열에 넣는거죠. 
하지만 해당 코드도 문제가 있습니다. 반대로 중복이 생겨버렸어요.</p>
<p>예를 들어, <code>nums1 = [1, 2, 3]</code> <code>nums2 = [1, 1]</code> 라고 했을 때 답으로 <code>[1]</code>이 나와야 합니다.
하지만 답으로 <code>[1, 1]</code>이 나와요. 
왜냐면 짧은 배열을 기준으로 하기 때문에 1이 nums1에 있는지 2번 확인하기 때문이죠. 그렇다고 해서 긴 배열로 for문을 돌리면 해결되는 문제도 아닙니다. </p>
<pre><code class="language-swift">func intersect(_ nums1: [Int], _ nums2: [Int]) -&gt; [Int] {
    var result: [Int] = []

    if nums1.count &gt; nums2.count {
        for num in nums2 {
            if nums1.contains(num) {
                result.append(num)
            }
        }
    } else {
        for num in nums1 {
            if nums2.contains(num) {
                result.append(num)
            }
        }
    }

    return result
}</code></pre>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p><strong>또또 다른 실패 방식</strong></p>
<p>그래서 이번에는 중복을 확인한 숫자는 사라지도록 <code>remove</code>함수를 사용했습니다.
전에 있던 코드에서 <code>remove</code>만 추가했는데, 위에 있는 예시가 해결되었습니다.</p>
<p>하지만, <code>submit</code>를 했더니 또 다른 문제가 생겼습니다.
32번째 case에서 <code>Wrong</code>이 떴더라구요.. 분명 중복을 제거한다고 했는데 제대로 안되는지 문제가 계속 생겼습니다..😂</p>
<pre><code class="language-swift">func intersect(_ nums1: [Int], _ nums2: [Int]) -&gt; [Int] {
    var result: [Int] = []
    var arr: [Int] = []

    if nums1.count &gt; nums2.count {
        arr = nums1
        for num in nums2 {
            if arr.contains(num) {
                result.append(num)
                arr.remove(at: arr.firstIndex(of: num) ?? 0)
            }
        }
    } else {
        arr = nums2
        for num in nums1 {
            if nums2.contains(num) {
                result.append(num)
                arr.remove(at: arr.firstIndex(of: num) ?? 0)
            }
        }
    }

    return result
}</code></pre>
<h3 id="4️⃣-번째-방법">4️⃣ 번째 방법</h3>
<p>드디어 성공했습니다.</p>
<p>하지만 위에 실패한 코드들과 약간 다릅니다. 위에 있는 코드에서는 num1, num2의 count별로 case를 나눴다면 해당 코드는 case를 나누지 않고 진행했어요.
case 나눈 거 때문에 위 코드에 문제가 생긴거라면 너무 맘이 아프네요🥲</p>
<p>해당 코드도 위와 동일하게 <code>contains</code>된 부분들을 삭제해줬어요.</p>
<pre><code class="language-swift">func intersect(_ nums1: [Int], _ nums2: [Int]) -&gt; [Int] {
    var result: [Int] = []
    var arr: [Int] = []

    arr = nums1
    for num in nums2 {
        if arr.contains(num) {
            result.append(num)
            arr.remove(at: arr.firstIndex(of: num)!)
        }
    }

    return result
}</code></pre>
<p>하지만, Runtime이 많이 걸리더라구요. 544ms나 걸렸습니다..
그래서 Runtime를 짧게 만들기 위한 방식을 찾아봤습니다.
<img src="https://images.velog.io/images/yoonah-dev/post/74b0cf27-5a4e-40e2-872b-8929cf9aab2c/%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%202021-08-03%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.36.17.png" alt=""></p>
<h3 id="5️⃣-번째-방법">5️⃣ 번째 방법</h3>
<p><code>Runtime</code>이 Best인 방식이었습니다.
그리고 <code>Dictionary</code>를 사용한 점이 굉장히 인상깊었던 방식입니다.</p>
<p>코드를 설명하자면, 
먼저 <code>Dictionary</code>인 <code>dic</code>를 하나 만들어주고 해당 <code>Dictionary</code>에 key값과 value값을 모두 Int로 받는다고 명시해줍니다.</p>
<p>그리고 먼저 <code>num1</code>에 있는 값들을 하나씩 세줍니다.
<code>dic[num, default: 0] += 1</code> 이 부분이 뭔가 싶을 수도 있는데요.
예를 들자면, <code>num1 = [1, 2, 3, 1, 2]</code>라고 할 때에 저 for문을 돌린다고 하면, 
<code>dic</code>안의 값은 <code>[ 1 : 2, 2 : 2, 3 : 1 ]</code>이 됩니다.
for문에서 들어온 num값이 key값으로 들어가는데 그 전에 들어왔던 적이 없으면 default: 0이 아니라면 전 value에서 +1된 값이 value로 들어옵니다.</p>
<p>완성된 <code>Dictionary</code>를 기준으로해서 <code>nums2</code>에 있는 값들과 비교해줍니다. 안에 <code>nums2</code>에 있는 숫자가 있으면 result에 넣어주고 value값을 -1 해줍니다.</p>
<pre><code class="language-swift">func intersect(_ nums1: [Int], _ nums2: [Int]) -&gt; [Int] {
    var dic: [Int: Int] = [:]

    for num in nums1 {
        dic[num, default: 0] += 1
    }

    var result = [Int]()

    for num in nums2 {
        if let freq = dic[num], freq &gt; 0 {
            result.append(num)
            dic[num] = freq - 1
        }
    }

    return result
}</code></pre>
<p><code>Dictionary</code>를 이런식으로 쓸 수 있다는게 참신했습니다.
당연히 num들을 직접 비교하는 방식을 생각했는데, num가 몇개 있는지 센 후에 진행하는 방식은 처음이었습니다. </p>
<p>아직까지 Swift에서 제공해주는 자료구조들을 다 알진 못해서 문제를 풀 때마다 새로운 자료구조를 배워가는 기분입니다. </p>
<p>Swift 알고리즘 얼른 정복할 겁니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Single Number]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Single-Number</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Single-Number</guid>
            <pubDate>Sun, 01 Aug 2021 04:51:06 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/549/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection의 다섯번째 문제인 Single Number를 풀어봤습니다.</p>
<p>이번 문제는 중복없이 혼자만 존재하는 숫자를 찾는 문제였습니다. </p>
<p>앞에 문제들이 중복 제거나 중복 확인을 하는게 대부분이여서 다른 문제들의 방식을 사용할 수도 있었어요. 하지만 되게 특이한 방식도 있더라구요, 소개해드리고 싶어서 가져왔습니다.</p>
<p>먼저 기본적인 방법부터 코드를 보여드리면서 설명하겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>전에 중복이 있는지 찾아내는 로직을 조금 수정했습니다.</p>
<p><strong><code>nums</code>에 있는 숫자가 1개라면 바로 그 숫자를 return하고,
그 이상이라면 먼저 <code>sorted</code>를 한 후에 양 옆의 숫자들이 같은 수인지 확인하는 방식으로 로직을 짰습니다.</strong></p>
<p>해당 index의 수와 index+1의 수가 같다면 <code>index+2</code>해주는 식으로 해서 이미 확인한 수를 다시 확인하지 않도록 했습니다. 그리고 양 옆에 숫자가 같지 않다면 그 수가 바로 혼자 존재하는 수이기 때문에 해당 숫자를 return하도록 했습니다.</p>
<p>하지만 <code>nums</code> 맨 끝에 있는 수가 혼자 존재하는 수이고, <code>nums</code>에 들어있는 수가 홀수라면 while조건에 따라서 맨 끝에 있는 수를 확인하지 못하게 됩니다. 하지만 그 수가 혼자 존재한다는 건 명백하기 때문에 while문을 원만하게 통과했다면 return를 <code>num</code>에 있는 마지막 숫자로 했습니다.</p>
<pre><code class="language-swift">func singleNumber(_ nums: [Int]) -&gt; Int {
    guard nums.count &gt; 1 else { return nums[0] }

    let num = nums.sorted()
    var index = 0

    while index &lt; nums.count-1  {
        if num[index] == num[index+1]{
            index += 2
        } else {
            return num[index]
        }
    }

    return num[nums.count-1]
}</code></pre>
<p>해당 방식이 runtime은 느렸지만 memory측면에서는 좋았습니다.
<img src="https://images.velog.io/images/yoonah-dev/post/f0a657f1-1426-4731-b3ed-69336a39db3e/%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%202021-08-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.02.57.png" alt=""></p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>해당 방식은 memory측면에서는 좋지 않지만 중복을 문제에 자주 등장하는 Set를 이용한 문제였습니다.</p>
<p>일단 Set를 하나 만들어두고 <code>nums</code>에 있는 숫자를 Set이 가지고 있다면 remove하고 가지고 있지 않다면 insert하는 방식으로 로직을 구현했습니다.</p>
<p>전 코드보다 이해하기도 쉽고 runtime도 전보다 빠르게 나왔습니다.</p>
<p><code>contains</code>된 것만 지우기 때문에 결국 혼자있는 숫자는 나갈 수가 없는 형태인거죠. 그 점을 이용해서 for문을 돌리고 배열에 있는 첫번째 원소를 return 했습니다.</p>
<pre><code class="language-swift">func singleNumber(_ nums: [Int]) -&gt; Int {
    var tempNums = Set&lt;Int&gt;()
    for value in nums {
        if tempNums.contains(value) {
            tempNums.remove(value)
        } else {
            tempNums.insert(value)
        }
    }
    return tempNums.first!
}</code></pre>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p>runtime이 가장 좋은 방법이며, 생각지도 못한 방법이었습니다.
<img src="https://images.velog.io/images/yoonah-dev/post/71429b14-a4de-4a64-8e14-3700602327f5/%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%202021-08-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.25.35.png" alt=""></p>
<p>일단 코드부터 보여드리겠습니다.</p>
<pre><code class="language-swift">func singleNumber(_ nums: [Int]) -&gt; Int {
    var result = 0
    for num in nums {
        result ^= num
    }
    return result
}</code></pre>
<p>코드가 매우 짧고, 간결합니다.
하지만 저는 처음부터 이해하진 못했습니다. <code>^=</code> 이 친구가 무슨 뜻인지 도통 몰랐거든요.</p>
<h4 id="-는-뭘까">^= 는 뭘까?</h4>
<p><code>XOR(^)</code>를 아시나요? 
우리가 아는 <code>OR(||)</code>은 비교하는 두 개의 값 중 하나만 True여도 True를 return합니다. 
<code>XOR</code>은 <code>OR</code>과는 다르게 두 개의 값이 다른 값을 가지고 있어야 True를 return합니다.</p>
<p>한마디로 <code>1(true) ^ 0(false) = 1(true)</code> 인거죠.</p>
<p><code>^=</code>은 <code>result = result ^ num</code>를 뜻합니다.
두 값의 <code>XOR</code>값이 result로 들어올 겁니다.</p>
<h4 id="를-써서-어떻게-문제를-푼다는거죠">^=를 써서 어떻게 문제를 푼다는거죠?</h4>
<p>저도 처음에 ^=와 중복이 무슨 상관이라고 저 방식을 사용한다는 거지. 우연히 해보니깐 된건가? 
이렇게 생각했습니다.</p>
<p>하지만 <code>XOR</code>의 의미를 이해한다면 충분히 저 방식으로 풀어낼 수 있더라구요.</p>
<p>예시를 들어보겠습니다.
<code>nums = [1, 2, 3, 2, 3]</code> 이라고 하겠습니다.</p>
<p>처음에 1이 들어오면 <code>0 ^ 1 =&gt; 0000 ^ 0001 = 0001(1)</code> 이 됩니다.
2가 들어오면 <code>1 ^ 2 =&gt; 0001 ^ 0010 = 0011(3)</code> 이 됩니다.
3이 들어오면 <code>3 ^ 3 =&gt; 0011 ^ 0011 = 0000(0)</code> 이 됩니다.
2가 들어오면 <code>0 ^ 2 =&gt; 0000 ^ 0010 = 0010(2)</code> 이 됩니다.
3이 들어오면 <code>2 ^ 3 =&gt; 0010 ^ 0011 = 0001(1)</code> 이 됩니다.</p>
<p>결국 정답인 1이 나옵니다.</p>
<p><code>XOR</code>은 같은 자리에 중복으로 나오는 값을 0으로 만들고 서로 다른 값을 1로 만듭니다.
그렇기 때문에 두 개의 숫자가 중복으로 나오면 <code>0010(2) ^ 0010(2) = 0000(0)</code> 이렇게 0이 될 수 밖에 없는거죠.
결국 중복으로 나타나 자신의 숫자를 지울 값이 없는 숫자만이 살아남게 됩니다.</p>
<p>그 원리를 사용해서 문제를 푼 거구요.</p>
<p><code>XOR</code>, <code>NOR</code>, <code>XAND</code> 등등 이런걸로 한 번도 뭘 해보겠다는 생각이 없었는데, 이렇게 간단하게 풀기에 좋다니.. 너무 신기하더라구요. 정말 공부해야할 게 많고 가야할 길이 멀다는 걸 또 느낍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Contains Duplicate]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Contains-Duplicate</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Contains-Duplicate</guid>
            <pubDate>Mon, 26 Jul 2021 06:34:42 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/578/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌑 🌑 🌑 🌑 (최하)</strong></p>
<hr>
<p>Easy Collection의 네번째 문제인 Contains Duplicate를 풀어봤습니다.</p>
<p>첫번째 문제에서는 중복을 제거했다면 이번 문제는 중복이 있는지 확인하는 문제였습니다.</p>
<p>전에 한 번 중복을 찾아내는 문제를 풀었기 때문에 그와 비슷한 방식으로 문제를 풀어나갔습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p><strong>첫번째 방법은 시간 초과가 난 로직입니다.</strong></p>
<p>저번에도 시간 초과가 났었는데, 이번 문제에서도 시간 초과가 발생했습니다.</p>
<p>가장 기본적인 이중 for문으로 짰었기에, 짤 때부터 이건 시간 초과가 발생하겠구나 싶은 로직이었습니다.</p>
<p><span style="color:Blue"><strong>문제가 생긴 이유</strong></span>
1&lt;= element 갯수 &lt;= 10^5 만큼의 배열크기가 들어올 수 있다고 했기 때문에 숫자가 커짐에 따라 시간 초과 문제가 발생한 것 같습니다. 이미 문제를 풀면서도 예상했던 부분이었습니다.</p>
<pre><code class="language-swift">func containsDuplicate(_ nums: [Int]) -&gt; Bool {
    guard nums.count &gt; 1 else { return false }

    for i in 0..&lt;nums.count-1 {
        for j in i+1..&lt;nums.count {
            if nums[i] == nums[j]{
                return true
            }
        }
    }
    return false
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/e8d15b27-6afd-4bf4-8e1b-153aa08b92cd/%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%202021-07-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.39.26.png" alt=""></p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>서로 멀리 떨어진 숫자들을 어떻게 대조해서 중복이 있는 걸 찾을까 고민을 하다가,
멀리 떨어져있다면 붙이면 되겠다 라는 생각이 들었습니다.</p>
<p>일단 정렬을 하고 나서 양 옆에 같은 숫자가 있는지 확인하는거죠.</p>
<pre><code class="language-swift">func containsDuplicate(_ nums: [Int]) -&gt; Bool {
    guard nums.count &gt; 1 else { return false }

    let num = nums.sorted()

    for index in 1..&lt;nums.count {
        if num[index] == num[index-1]{
            return true
        }
    }
    return false
}</code></pre>
<p><code>nums</code>가 전 문제들처럼 inout으로 써진게 아니여서 따로 num이라는 배열을 사용했습니다.</p>
<p>그리고 num에 있는 element들 양옆에 같은 숫자가 있으면 true를 바로 return하도록 로직을 짰습니다.</p>
<p>2번째 방식의 Runtime은 중간정도의 속도가 나오더군요.
<img src="https://images.velog.io/images/yoonah-dev/post/78c250e6-afbb-45ec-9a5e-b42de1385e13/%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%202021-07-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.45.11.png" alt=""></p>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p>3번째 방법은 보자마자 왜 나는 이런 생각을 못했을까 싶었던 방식이었습니다.</p>
<p>바로 중복을 싫어하는 Set를 써서 Set에 들어간 nums의 갯수와 그냥 nums의 갯수를 비교하는거죠.
만약 중복이 있다면 Set에 들어간 것과 그냥 nums에 있는 원소의 갯수가 차이날 것입니다.</p>
<pre><code class="language-swift">func containsDuplicate(_ nums: [Int]) -&gt; Bool {
    nums.count != Set(nums).count
}</code></pre>
<p>고작 한 줄 입니다. 왜 이 생각을 못했을까요?
항상 중복이 나오면 Set를 쓰자라고 생각을 했는데, 이번 문제에서는 왜 그러지 못했는지..🥲</p>
<p>알고리즘 더 열심히 해야겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Rotate Array]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Rotate-Array</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Rotate-Array</guid>
            <pubDate>Sun, 25 Jul 2021 12:37:33 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/646/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌕 🌑 🌑 🌑 (하)</strong></p>
<hr>
<p>Easy Collection의 세번째 문제인 Rotate Array를 풀어봤습니다.</p>
<p>제목 그대로 배열을 Rotate하는 로직 짜기가 문제였습니다.</p>
<p>전 문제들처럼 쉽게 풀 거라고 예상했지만 <strong>시간 초과</strong>가 났고, 시간복잡도가 O(n)의 효율을 낼 수 있는 코드를 생각하다보니 자연스레 코드 자체가 좀 복잡해졌습니다.</p>
<p>코드를 보여드리면서 설명하겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p><strong>첫번째 방법은 시간 초과가 난 로직입니다.</strong></p>
<p>그렇기 때문에 바로 정답을 보고 싶으시다면 2번째 방법부터 보시는 걸 추천드립니다.</p>
<p>시간 초과가 난 이유를 저도 정확히 알 것 같습니다. </p>
<p><span style="color:Blue"><strong>문제가 생긴 이유</strong></span>
일단 머릿속으로 정리했을 때, 맨 뒤에 있는 element가 앞으로 오고 앞에 있는 것들이 차례대로 뒷줄로 밀려나야한다고 생각이 들어서 이중 for문을 사용했습니다. 
해당 문제는 전제로 1&lt;= element 갯수 &lt;= 10^5 만큼의 배열크기가 들어올 수 있다고 했기 때문에 숫자가 커짐에 따라 시간 초과 문제가 발생한 것 같습니다.</p>
<pre><code class="language-swift">func rotate(_ nums: inout [Int], _ k: Int) {
    if nums.count &gt; 1 {
        for _ in 0..&lt;k {
            let num = nums[nums.count-1]

            for j in (0...nums.count-2).reversed() {
                nums[j+1] = nums[j]
            }
            nums[0] = num
        }
    }
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/12a4f323-5c48-4c3f-b73d-ac4901e69998/%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%202021-07-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.26.38.png" alt=""></p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>이중 for문이 안된다면 O(n)의 효율이 나도록 단일 for문만 돌려야 된다는 생각이 들었습니다.</p>
<p>하지만 단일 for문을 사용해서 어떻게 이중 for문과 같은 효율을 내지 싶더라구요. 
그래서 공간 복잡도를 늘리는 대신, 배열을 하나 더 만들기로 했습니다.</p>
<p>해당 배열에 nums에 있는 숫자들을 k부터 차곡차곡 넣다가 다시 0~k-1까지 넣는 방식으로 구현했습니다.</p>
<p>nums = [1, 2, 3, 4, 5, 6, 7]
k = 3
라고 한다면
sub = [#, #, #, 1, 2, 3, 4] 를 먼저 넣고 
sub = [5, 6, 7, 1, 2, 3, 4] 를 다음에 넣어주는거죠.</p>
<pre><code class="language-swift">func rotate(_ nums: inout [Int], _ k: Int) {
    var sub = [Int](repeating: 0, count: nums.count)
    for i in 0..&lt;nums.count {
        sub[(i + k) % nums.count] = nums[i]
    }

    for i in 0..&lt;nums.count {
        nums[i] = sub[i]
    }
}</code></pre>
<p>일단, sub라는 배열은 배열의 크기를 초기화해줘야 합니다. 
알고리즘하면서 <code>[Int](repeatint:0, count: nums.count)</code> 이렇게 처음 써봅니다..
그냥 <code>var sub: [Int] = [ ]</code> 이렇게 사용하면 <strong>out of range</strong> 오류가 뜨더라구요. 빈 배열이기 때문에 그렇겠죠.</p>
<p>그리고 안에서 <code>(i + k) % nums.count</code>를 사용해서 위의 방식을 구현해줬습니다.
해당 식으로 계산하게 되면 k = 3일 때는 3부터 sub라는 배열에 숫자가 차게되고 이후에 <code>(i + k)</code>값이 nums.count값 이상으로 가게되어 0부터 다시 숫자가 시작되기 때문에 해당 방식을 구현할 수 있게 됩니다.</p>
<p>2번째 방식은 Runtime이 아주 빨랐습니다.👍
<img src="https://images.velog.io/images/yoonah-dev/post/243e9073-08a0-4e73-8226-a5e736f03c26/%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%202021-07-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.28.01.png" alt="">
<img src="https://images.velog.io/images/yoonah-dev/post/0b025ff7-ad1b-4db7-b3be-7c6756d1754c/%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%202021-07-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.28.12.png" alt=""></p>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p>3번째 방법은 대표 답안으로 작성되어 있던 걸 Swift로 구현한 방식입니다.</p>
<p>대표 답안 자체가 Leetcode에서는 Java, 아니면 Python으로 되어 있기 때문에 방식이 다소 Java 코드 같을 수 있습니다.</p>
<p>하지만 효율은 2번째 방식보다 5ms정도 더 좋았습니다.</p>
<pre><code class="language-swift">func rotate(_ nums: inout [Int], _ k: Int) {
    let l = k % nums.count
    var count = 0

    for start in 0..&lt;nums.count where count &lt; nums.count {
        var current = start
        var prev = nums[start]

        repeat {
            let next = (current + l) % nums.count
            let temp = nums[next]
            nums[next] = prev
            prev = temp
            current = next
            count += 1
        } while (start != current)
    }
}</code></pre>
<p>해당 방식은 코드로 보기에도 이해하기가 복잡합니다.</p>
<p>간단하게 설명하자면
<img src="https://images.velog.io/images/yoonah-dev/post/c39c8539-8077-4389-aa6a-2105760f52ce/%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%202021-07-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.21.35.png" alt=""></p>
<p>이런 방식입니다. 
저는 2번째 방식이 훨씬 짜기 쉽다고 생각이 들어서 3번째 방식은 참고해서 짜는걸로 만족했습니다.</p>
<h4 id="요건-뭐지">요건 뭐지?</h4>
<p>저는 알고리즘으로 처음 배우는 문법이 많았습니다. 너무 뷰 짜는데만 Swift를 쓴 거 같다는 생각이 들더라구요..
그 문법 중 하나가 repeat-while이었습니다.</p>
<p>repeat-while은 do-while과 동일한 기능을 하는 친구입니다.</p>
<p>do-while과 사용 방식은 동일하기 때문에 설명은 더 안하겠습니다.!</p>
<p><a href="https://0urtrees.tistory.com/131">repeat-while를 더 알고 싶다면</a></p>
<h3 id="4️⃣-번째-방법">4️⃣ 번째 방법</h3>
<p>제가 생각하기에 가장 간단하고 편한 방식인 거 같습니다.</p>
<pre><code class="language-swift">func rotate(_ nums: inout [Int], _ k: Int) {
    if k &lt; 1 || nums.isEmpty {
        return
    }
    let k = k % nums.count
    nums = Array(nums[nums.count - k..&lt;nums.count] + nums[0..&lt;nums.count-k])
}</code></pre>
<p>Runtime도 가장 좋고 코드도 쉽습니다.
Swift의 Array는 Subscript를 사용해서 배열의 값을 범위만큼 가져올 수 있습니다.
이 점을 이용해서 코드를 짰습니다.</p>
<p>앞부분엔 k+1 인덱스부터 끝까지 가져온 elements를 넣고 뒷부분엔 앞부터 k까지의 elements들을 넣어서 앞에서 귀찮게 <code>for문</code>돌렸던 걸 쉽게 해결했습니다.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/813df336-e495-43e1-8ca7-9b708053fa68/%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%202021-07-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.30.39.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Best Time to Buy and Sell Stock II]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Best-Time-to-Buy-and-Sell-Stock-II</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Best-Time-to-Buy-and-Sell-Stock-II</guid>
            <pubDate>Fri, 23 Jul 2021 15:20:52 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions
Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/564/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌑 🌑 🌑 🌑 (최하)</strong></p>
<hr>
<p>Easy Collection의 두번째 문제인 Best Time to Buy and Sell Stock II를 풀어봤습니다.</p>
<p>저번에 첫 문제를 한 번 풀어봐서 그런지, 비슷한 방식으로 풀어가면 되는거라서 크게 어려움은 없었습니다. </p>
<p>또한 첫 시도에서 좋은 Runtime를 얻고 best example과도 크게 차이가 없어서 저번보다 시도 횟수가 많이 줄었습니다.</p>
<p>일단 제가 썼던 코드를 한 번 보여드리겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>이번 문제는 전에 산 물건이 후에 팔았을 때 가장 큰 이득을 얻었다고 할 때, 얼마의 이득을 얻는가에 대한 문제였습니다.</p>
<p>즉, 후에 이득이 나지 않는다면 팔지 않아도 된다는 겁니다.</p>
<p>그래서 저는 현재(index)가 전(index-1)보다 더 큰 수를 가지고 있는 경우에 profit에다가 값을 더 해줬습니다.</p>
<pre><code class="language-swift">func maxProfit(_ prices: [Int]) -&gt; Int {
    var profit = 0

    for index in 1..&lt;prices.count {
        if prices[index-1] &lt; prices[index] {
            profit += prices[index] - prices[index-1]
        }
    }

    return profit
}
</code></pre>
<p>이렇게 코드를 짰더니, 결과는 Success
하지만, Runtime도 좋았습니다.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/ea3ba6ee-d939-4dc4-869b-92be90e146f8/%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%202021-07-23%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.05.23.png" alt=""></p>
<h3 id="2️⃣-번째-방법best-example">2️⃣ 번째 방법(best example)</h3>
<p>한 번에 완료하고나서 앞에 더 좋은 example들을 살펴보았습니다.</p>
<p>제가 사용한 방법과 비슷한 맥락으로 코드가 대부분 짜여져있었는데요.
조금 특이한 방식을 봤습니다.</p>
<p><strong>&quot;where&quot;</strong></p>
<p>저는 SQL이후로 where를 오랜만에 보는 것 같습니다.
swift에도 where이 있더라구요..</p>
<pre><code class="language-swift">func maxProfit(_ prices: [Int]) -&gt; Int {
    var profit = 0

    for index in 1..&lt;prices.count where prices[index-1] &lt; prices[index] {
        profit += prices[index] - prices[index-1]
    }

    return profit
}</code></pre>
<p>if문 대신에 where를 써서 for문 조건에다가 where조건을 달아줬더라구요.
정말 신기했습니다.</p>
<p>이렇게 쓸 수 있을뿐만 아니라 값 바인딩, 타입 캐스팅, 익스텐션에서도 사용할 수 있었습니다.
나중에 한 번 써보려구요.
<a href="https://velog.io/@kevinkim2586/%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EB%AC%B8%EB%B2%95-where-%EC%A0%88"># where reference</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Leetcode) Remove Duplicates from Sorted Array ]]></title>
            <link>https://velog.io/@yoonah-dev/Leetcode-Remove-Duplicates-from-Sorted-Array</link>
            <guid>https://velog.io/@yoonah-dev/Leetcode-Remove-Duplicates-from-Sorted-Array</guid>
            <pubDate>Fri, 23 Jul 2021 15:04:02 GMT</pubDate>
            <description><![CDATA[<p><strong>Top Interview Questions</strong>
<strong>Easy Collection</strong></p>
<p><strong><a href="https://leetcode.com/explore/interview/card/top-interview-questions-easy/92/array/727/">Link of Problem</a></strong></p>
<p><strong>LEVEL : 🌕 🌑 🌑 🌑 🌑 (최하)</strong></p>
<hr>
<p>Easy Collection의 첫번째 문제인 <code>Remove Duplicates from Sorted Array</code>를 풀어봤습니다.</p>
<p>영어로 문제가 써져있다보니 문제를 해석하는 것부터가 어렵더라구요. 
하지만 문제 제목에서 유추할 수 있듯이 Sorted된 Array에 있는 중복된 숫자를 제거하는 문제였습니다.</p>
<p>처음 풀었을 때도 고작 코드 3-4줄로 Solved를 했고 나중에 Runtime를 줄이기 위해서 다른 방식을 찾았을 때도 10줄이 안넘었던 거 같네요.</p>
<p>그럼 제가 문제를 해결해갔던 방향을 한 번 설명드리겠습니다.</p>
<h3 id="1️⃣-번째-방법">1️⃣ 번째 방법</h3>
<p>Duplicate라는 단어를 보자마자 생각났던게 Set이었습니다.
아시다시피 Set에 넣은 element들은 모두 중복이 제거된 상태로 저장이 됩니다.</p>
<p>그렇기 때문에 처음에 들어온 배열을 Set를 사용해서 중복을 제거해주고, 그 후에 <code>.sorted()</code>를 하는 방식을 선택했습니다.</p>
<pre><code class="language-swift">func removeDuplicates(_ nums: inout [Int]) -&gt; Int {
    let numset = Set(nums)
    nums = numset.sorted()
    return nums.count
}</code></pre>
<p>이렇게 코드를 짰더니, 결과는 <code>Success</code>
하지만, Runtime이 길더라구요.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/c52cd076-6583-41cc-b532-7fb3e84f048c/%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%202021-07-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.17.26.png" alt=""></p>
<p>그래서 시간을 줄이기 위한 여정이 시작되었습니다.</p>
<h3 id="2️⃣-번째-방법">2️⃣ 번째 방법</h3>
<p>혹시나 Set를 쓴 게 많은 시간을 소요한 건 아닐까 싶어서 이번엔 Set없이 for문으로 돌렸습니다.</p>
<pre><code class="language-swift">func removeDuplicates(_ nums: inout [Int]) -&gt; Int {
    var numset: [Int] = []
    for n in nums {
        if !numset.contains(n) {
            numset += [n]
        }
    }
    nums = numset
    return nums.count
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/b0a98b9d-41e4-4f82-81da-773de6990b32/%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%202021-07-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.30.06.png" alt=""></p>
<p>하지만, 전보다 더 긴 시간이 소요됐어요... 340ms..🥲</p>
<h3 id="3️⃣-번째-방법">3️⃣ 번째 방법</h3>
<p>Set도 for문도 아니면 뭘까. 엄청 생각을 하다가 뭔가 제가 신경쓰지 않고 있던 게 있다는 걸 깨달았습니다.</p>
<p>그건 바로 <strong>&quot;numset&quot;</strong></p>
<p>그냥 nums에서 처리하면 됐던 걸 numset까지 만들면서 nums와 numset으로 값을 왔다갔다 옮기고 있더라구요..</p>
<p>그래서 nums에서만 처리할 수 있도록 코드를 짰습니다.</p>
<pre><code class="language-swift">func removeDuplicates(_ nums: inout [Int]) -&gt; Int {
    guard nums.count &gt; 1 else { return nums.count }
    var cnt = 0

    for index in 1..&lt;nums.count {
        if nums[index] == nums[index-1]{
            cnt += 1
        } else {
            nums[index-cnt]=nums[index]
        }
    }
    return nums.count - cnt
}</code></pre>
<p><img src="https://images.velog.io/images/yoonah-dev/post/536b6c4f-03a8-4e78-85e0-cce70904d678/%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%202021-07-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.42.03.png" alt=""></p>
<p>결과는 56ms ! Set를 사용했을 때랑 30ms정도밖에 차이는 안나지만 쉬운 문제였기 때문에 시간에 집착을 좀 해봤습니다.</p>
<br/>

<h3 id="🙃-inout">🙃 inout</h3>
<p>이번 문제를 풀면서 처음 본 inout이라는 문법.</p>
<blockquote>
<p>함수의 파라미터를 함수 내부에서 변경하고 함수가 종료된 후에도 변경한 값이 지속되도록 하려면 변수의 주소값을 넘겨 직접 접근할 수 있도록 도와주는 inout 키워드 사용</p>
</blockquote>
<p>그렇다고 하네요. 파라미터를 함수 내부에서도 변경할 수 있도록 써주는 키워드라고 합니다. 
전에 배웠던 C, C++에 있던 포인터가 생각나는 키워드입니다.</p>
<p>위에 써있는 것처럼 주소값을 넘겨줘야 하기 때문에 C, C++과 동일하게 <code>&amp;</code>를 사용해서 인수를 명시해줘야 합니다.</p>
<pre><code class="language-swift">func start() {
    var ber = [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 7]
    let num: Int = removeDuplicates4(&amp;ber)
}</code></pre>
<p>이렇게 말이죠. </p>
<p>알고리즘 공부하면서 배워가는 것도 많은 것 같습니다.
<a href="https://2018-start.tistory.com/92"># inout reference</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Core data, CRUD 코드]]></title>
            <link>https://velog.io/@yoonah-dev/Core-data-CRUD-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@yoonah-dev/Core-data-CRUD-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Thu, 22 Jul 2021 17:17:07 GMT</pubDate>
            <description><![CDATA[<h2 id="💽-코어데이터">💽 코어데이터</h2>
<hr>
<p><strong>코어데이터 누구세요?</strong>
<a href="https://developer.apple.com/documentation/coredata">Apple Developer Documentation - Core Data 🌈</a></p>
<p><strong>Core Data는 데이터베이스가 아닙니다</strong>. 
데이터베이스의 역할을 하는 Persistence(SQLite)가 Core Data 기능 중 하나 일 뿐이지요. 
Core Data는 넓은 의미로 앱의 모델 계층이며, <strong>객체 그래프를 관리하는 Framework</strong>입니다.</p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/1cb3739e-3a6d-4415-a0b4-f6feb5b62204/%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%202021-07-23%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%202.13.43.png" alt=""></p>
<p><strong>코데 어떻게 생겼어요?</strong></p>
<p><img src="https://images.velog.io/images/yoonah-dev/post/19019edd-c300-44c0-97e2-86072c8b9a27/%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%202021-07-23%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%202.13.58.png" alt=""></p>
<p>코데는 이렇게 RelationShip를 지정할 수 있어요. </p>
<p>지금은 1:多 로 만들어진 모습입니다.</p>
<br/>

<p><span style="color:gray"><strong>CRUD 코드들 보여주세요!</strong></span></p>
<pre><code class="language-swift">// create
@discardableResult
func insertContent(content: Content) -&gt; Bool {
        let entity = NSEntityDescription.entity(forEntityName: &quot;Contents&quot;, in: self.context)

        if let entity = entity {
            let managedObject = NSManagedObject(entity: entity, insertInto: self.context)

            managedObject.setValue(content.title, forKey: &quot;title&quot;)
            managedObject.setValue(content.content, forKey: &quot;content&quot;)
            managedObject.setValue(content.date, forKey: &quot;date&quot;)

            do {
                try self.context.save()
                return true
            } catch {
                print(error.localizedDescription)
                return false
            }
        } else {
            return false
        }
}

// read 
func fetch() -&gt; [NSManagedObject] {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest&lt;NSManagedObject&gt;(entityName: &quot;Contents&quot;)

        // sort
        let sort = NSSortDescriptor(key: &quot;date&quot;, ascending: false)
        fetchRequest.sortDescriptors = [sort]

        let result = try! context.fetch(fetchRequest)
        return result
}

// update
func updateContent(title: String, content: String) {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest: NSFetchRequest&lt;NSFetchRequestResult&gt; = NSFetchRequest.init(entityName: &quot;Contents&quot;)
        fetchRequest.predicate = NSPredicate(format: &quot;title = %@&quot;, contentTitle)

        do {
            let test = try managedContext.fetch(fetchRequest)
            let objectUpdate = test[0] as! NSManagedObject

            objectUpdate.setValue(title, forKey: &quot;title&quot;)
            objectUpdate.setValue(content, forKey: &quot;content&quot;)
            objectUpdate.setValue(Date(), forKey: &quot;date&quot;)

            do {
                try managedContext.save()
            } catch {
                print(error)
            }
        } catch { print(error) }
}

// delete
func deleteContent(title: String) {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest: NSFetchRequest&lt;NSFetchRequestResult&gt; = NSFetchRequest.init(entityName: &quot;Contents&quot;)
        fetchRequest.predicate = NSPredicate(format: &quot;title = %@&quot;, title)

        do {
            let test = try managedContext.fetch(fetchRequest)
            let objectToDelete = test[0] as! NSManagedObject

            managedContext.delete(objectToDelete)
            do {
                try managedContext.save()
            } catch {
                print(error)
            }
        } catch {
            print(error)
        }
}</code></pre>
<p>CRUD 코드들 입니다.</p>
<p>CRUD를 하는 방법은 쉬워요! 하지만 그 이상으로 가는 건 어려운 것 같습니다.
지금 제 목표는 RelationShip를 사용해서 데이터를 사용하는 겁니다.
그 때까지 도-약해보겠습니다.🚀🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swipe에 따라 움직이는 상단바 구현]]></title>
            <link>https://velog.io/@yoonah-dev/Swipe%EC%97%90-%EB%94%B0%EB%9D%BC-%EC%9B%80%EC%A7%81%EC%9D%B4%EB%8A%94-%EC%83%81%EB%8B%A8%EB%B0%94-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@yoonah-dev/Swipe%EC%97%90-%EB%94%B0%EB%9D%BC-%EC%9B%80%EC%A7%81%EC%9D%B4%EB%8A%94-%EC%83%81%EB%8B%A8%EB%B0%94-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Thu, 22 Jul 2021 17:11:45 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yoonah-dev/post/657445d6-f45c-4b63-b282-182d8a9df532/ezgif-1-d900762452ee_(1).gif" alt="">
<strong><em>왜 Swipe에 맞춰서 움직이세요?</em></strong></p>
<p>너무 구현해보고 싶어서 다양한 도전끝에 길을 찾았습니다.
공유해볼게요!</p>
<p>...Λ＿Λ
（ㆍωㆍ)つ━☆<em>。
⊂　　 ノ 　　　.뾰
   し-Ｊ　　　°。로 <em>´¨)
                    ..　.· ´¸.·롱</em>´¨) ¸.·*¨)
                                  (¸.·´ (????¸.&#39;</em></p>
<br/>

<p>저는 저 안에 </p>
<p>[backButton]  <br/>
[bottomLineView] <br/>
[CollectionView]</p>
<p>이렇게 전체적인 뷰를 구성해줬어요.</p>
<p>이렇게 구성되어진 뷰를 기반으로 만들었기 때문에, 저랑 다르게 레이아웃을 잡았을 경우에는 다른 방법을 찾는 걸 추천드립니다!</p>
<p>저는 일단 CollectionView의 기반인 <strong>ScrollView가 Scroll되는걸 감지해서</strong> </p>
<p>저 bottomLineView가 움직이게 해줬어요.</p>
<pre><code class="language-swift">func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer&lt;CGPoint&gt;) { }</code></pre>
<p>이 함수를 사용해서 ScrollView의 Dragging이 끝날때쯤에 현재 CollectionView의 index를 감지해서 해당 인덱스에 맞게 LineView가 움직이도록 했어요.
<br/></p>
<pre><code class="language-swift">func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer&lt;CGPoint&gt;) {
                let cellWidthIncludingSpacing = UIScreen.main.bounds.size.width

                // targetContentOff을 이용하여 x좌표가 얼마나 이동했는지 확인 
                // 이동한 x좌표 값과 item의 크기를 비교하여 몇 페이징이 될 것인지 값 설정
        var offset = targetContentOffset.pointee
        let index = (offset.x + scrollView.contentInset.left) / cellWidthIncludingSpacing
        var roundedIndex = round(index)


                // scrollView, targetContentOffset의 좌표 값으로 스크롤 방향을 알 수 있다. 
                // index를 반올림하여 사용하면 item의 절반 사이즈만큼 스크롤을 해야 페이징이 된다. 
                // 스크로로 방향을 체크하여 올림,내림을 사용하면 좀 더 자연스러운 페이징 효과를 낼 수 있다.
        if scrollView.contentOffset.x &gt; targetContentOffset.pointee.x {
            roundedIndex = floor(index)
        } else if scrollView.contentOffset.x &lt; targetContentOffset.pointee.x {
            roundedIndex = ceil(index)
        } else {
            roundedIndex = round(index)
        }

                // 기존에는 스크롤한 값에 대해 페이징되는 인덱스 값을 구하여, 인덱스 크기만큼 페이징 처리를 했습니다.
                // 업데이트 된 코드에서는 페이징되는 인덱스 크기를 1로 수정하여 하나씩만 페이징 되도록 처리했습니다.
        if currentIndex &gt; roundedIndex {
            currentIndex -= 1
            roundedIndex = currentIndex
            moveNegativeDirection()
        } else if currentIndex &lt; roundedIndex {
            currentIndex += 1
            roundedIndex = currentIndex
            movePositiveDirection()
        }

                // 위 코드를 통해 페이징 될 좌표값을 targetContentOffset에 대입하면 된다.
        offset = CGPoint(x: roundedIndex * cellWidthIncludingSpacing - scrollView.contentInset.left, y: -scrollView.contentInset.top)
        targetContentOffset.pointee = offset
}

// + 방향으로 움직임
// 전체 width사이즈에서 현재 가지고 있는 text의 갯수만큼 나눈걸 index만큼 곱해주면
// index가 클 수록 멀게 이동한다
func movePositiveDirection() {
        UIView.animate(withDuration: 0.3, animations: {
            self.lineView.transform = CGAffineTransform(translationX: UIScreen.main.bounds.size.width/self.textCount * self.currentIndex, y: 0)
        })
}

// - 방향으로 움직임
// 전체 width사이즈에서 현재 인덱스를 빼준다
// index가 작아질수록 원래 자리로 돌아온다.
func moveNegativeDirection() {
        UIView.animate(withDuration: 0.3, animations: {
            self.lineView.transform = CGAffineTransform(translationX: UIScreen.main.bounds.size.width - UIScreen.main.bounds.size.width/self.textCount * (self.textCount - self.currentIndex), y: 0)
        })
}</code></pre>
<p>복잡하죠..?</p>
<ul>
<li><p><code>cellWidthIncludingSpacing</code>
  cellWidthIncludingSpacing를 스크린의 width로 지정했습니다. 
  나중에 cell 하나 하나의 크기를 알아야지 전체 스크롤해서 현재 index가 몇인지 알 수 있기 때문이지요.</p>
</li>
<li><p><code>offset</code>
  현재 target이 되는 content의 좌표를 나타내고 있어요.</p>
</li>
<li><p><code>index</code>
  현재 offset.x 좌표와 scrollView의 왼쪽 inset를 더한 다음에 셀 하나의 크기로 나눠서 현재 index로 넣어줬어요.</p>
</li>
<li><p><code>roundedIndex</code>
  roundedIndex를 통해서 계산한 index를 반올림했습니다. 
  뒤에 소수점이 생기는데 만약 소수점이 0.5 이상이면 위로 올리고 나머지는 그 밑으로 계산했어요.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[터치 애니메이션 구현하기]]></title>
            <link>https://velog.io/@yoonah-dev/%ED%84%B0%EC%B9%98-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yoonah-dev/%ED%84%B0%EC%B9%98-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 22 Jul 2021 17:06:23 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yoonah-dev/post/834f1014-0dba-4ad8-a1bf-b894a797aef9/Simulator_Screen_Recording_-_iPhone_12_-_2021-06-04_at_13.50.11.gif" alt=""></p>
<p><strong><em>누르면 +에서 x로 빙글 돌아가요!</em></strong></p>
<p>저 밑에 버튼은 누르면 빙글빙글 돌아가네요. 그래서 구현해봤습니다.
저는 일단 저 친구를 기본적으로 90도만큼 이미 돌아간 상태로 만들어뒀어요.
지금 .gif에서 보시다시피 </p>
<p><strong>버튼을 누른다 → + 표시에서 x로 움직인다 → 버튼을 다시 누른다 →  x 표시에서 +로 움직인다</strong></p>
<p>이런 루틴으로 진행되는 걸 알 수 있어요.</p>
<br/>

<p><span style="color:green"><strong>일단은 저 친구는 처음 뷰에 들어오면 -90도 돌아가 있지만,</strong></span></p>
<pre><code class="language-swift">// 왼쪽으로 90도 돌아가게 해주는 코드
transform = CGAffineTransform(rotationAngle: -(.pi/4))</code></pre>
<p><span style="color:green"><strong>이 코드를 통해서 원래 모습으로 돌려줄 겁니다.</strong></span></p>
<pre><code class="language-swift">UIView.animate(withDuration: 0.3, animations: {
     self.transform = .identity
})</code></pre>
<p>하지만 UIView.animate가 내 생각대로 안된다고 느낄겁니다. </p>
<p>왜냐면 내가 뷰를 키자마자 0.3만에 쇽샥 돌아가버려서 우리는 이미 빙글 돌아버린 x 표시만 볼 수 있습니다...
<br/></p>
<p><strong>그래서 어떻게 해줬는가?</strong></p>
<p>DispatchQueue을 모셨습니다.</p>
<pre><code class="language-swift">DispatchQueue.main.asyncAfter(deadline: .now() + 0.05, execute: {
   UIView.animate(withDuration: 0.3, animations: {
        self.transform = .identity
   })
})</code></pre>
<p>DispatchQueue는 뷰가 켜지고 나서 0.05 후에 저 animate를 불러주기 때문에 우리는 돌아가는 x 표시를 볼 수 있게 됩니다.🌈</p>
<br/>


<p><strong>다시 원래대로 돌아가면서 dismiss시키는건요?</strong></p>
<p>아마 animate와 dismiss를 함께 시키면 animate가 구동되는걸 보지도 못한채 차갑게 dismiss되는 뷰를 볼 수 있습니다. </p>
<pre><code class="language-swift">UIView.animate(withDuration: 0.3, animations: {
       self.exitButton.transform = CGAffineTransform(rotationAngle: -(.pi/4))
})
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15, execute: {
       self.dismiss(animated: true, completion: nil)
})</code></pre>
<p>그렇기 때문에 일단 animate를 보여주고 0.15뒤에 dismiss될 수 있도록 <strong>DispatchQueue</strong>을 불러주시면 될 것 같습니다.</p>
]]></description>
        </item>
    </channel>
</rss>