2018 카카오 신입 공채 3차 코딩 테스트 Swift 풀이

# 문제 해설

https://tech.kakao.com/2017/11/14/kakao-blind-recruitment-round-3/

# N진수 게임

https://www.welcomekakao.com/learn/courses/30/lessons/17687

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import Foundation

// 진법변환
func convertBase(n: Int, base: Int) -> String {
    
    if n == 0 { return "0" }

    let list = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]
    
    var answer = [String]()
    var quotient = n // 몫
    var remainder = 0 // 나머지
    
    // 몫이 0이 될 때까지 n을 base로 계속 나누고 튀어나오는 나머지값을 역순으로 배치
    while (quotient > 0) {
        remainder = quotient % base
        quotient = quotient / base
        answer.append(list[remainder])
    }
    
    answer = answer.reversed()
    
    return answer.joined()
}

func solution(_ n:Int, _ t:Int, _ m:Int, _ p:Int) -> String {
    // 진법 n, 미리 구할 숫자의 갯수 t, 게임에 참가하는 인원 m, 튜브의 순서 p
    
    // 총 문자열 구하기
    var totalStr = ""
    for i in 0 ..< (t * m) {
        totalStr += convertBase(n: i, base: n)
    }
    
    var answer = ""
    for i in 0 ..< t {
        let str = String(totalStr[totalStr.index(totalStr.startIndex, offsetBy: p + (i * m) - 1)])
        answer += str
    }
    
    return answer
}

# 압축

https://www.welcomekakao.com/learn/courses/30/lessons/17684

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import Foundation

func solution(_ msg:String) -> [Int] {
    
    // 알파벳 리스트를 딕셔너리로 준비
    let alphabetList: [String] = (0..<26).map({String(UnicodeScalar("A".unicodeScalars.first!.value + $0)!)})
    var dict = [String : Int]()
    for (i, char) in alphabetList.enumerated() {
        dict[char] = i + 1
    }
    
    var answer = [Int]()
    var searchWord = ""
    
    for i in msg {
        searchWord += String(i)
        
        // 찾는 단어가 없으면
        if dict[searchWord] == nil {
            // 사전에 추가
            dict[searchWord] = dict.count + 1
            // 찾는 단어의 길이보다 한글자 작은 값의 인덱스를 반환값에 추가
            answer.append(dict[String(searchWord.dropLast())]!)
            // 다음 찾을 단어를 searchWord에서 찾지 못했던 맨 마지막 문자로 설정
            searchWord = String(searchWord.popLast()!)
        } else {
            continue
        }
    }
    
    // 맨 마지막에 남은 글자의 인덱스를 추가해줌
    if !searchWord.isEmpty {
        answer.append(dict[searchWord]!)
    }
    
    return answer
}

# 파일명 정렬

https://www.welcomekakao.com/learn/courses/30/lessons/17686

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import Foundation

func solution(_ files:[String]) -> [String] {
    var answer = [String]()
    // HEAD, NUMBER, FILENAME으로 구성된 사전 준비
    var dict = [(String, String, String)]()
    
    // dict 작성
    for file in files {
        // 처음으로 나오는 숫자를 찾음
        let range = NSRange(file.startIndex..., in: file)
        let numberRegex = try! NSRegularExpression(pattern: "[0-9]+", options: [])
        let numberMatch = numberRegex.firstMatch(in: file, options: [], range: range)
        let number = numberMatch.map { String(file[Range($0.range, in: file)!]) }!

        // head 작성
        let wordArr = file.map { String($0) }
        let head = wordArr[0...numberMatch!.range.lowerBound - 1].joined()
        
        dict.append((head, number, file))
    }
    
    // dict를 정렬
    for _ in dict {
        for i in 0 ..< dict.count - 1 {
            // head가 같으면
            if dict[i].0.lowercased() == dict[i+1].0.lowercased() {
                // number를 비교
                if (Int(dict[i].1)! > Int(dict[i+1].1)!) {
                    // i가 i+1보다 크면 스왑
//                    (dict[i], dict[i+1]) = (dict[i+1], dict[i])
                    dict.swapAt(i, i + 1)
                }
            } else {
                // head를 비교
                if dict[i].0.lowercased() > dict[i+1].0.lowercased() {
                    // i가 i+1보다 크면 스왑
//                    (dict[i], dict[i+1]) = (dict[i+1], dict[i])
                    dict.swapAt(i, i + 1)

                }
            }
        }
    }
    
    // 정렬한 순서대로 파일명을 꺼내 옴
    for value in dict {
        answer.append(value.2)
    }
    
    return answer
}

# 방금 그 곡

https://www.welcomekakao.com/learn/courses/30/lessons/17683

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import Foundation

func solution(_ m:String, _ musicinfos:[String]) -> String {
    // 입력의 샵문자를 일반 캐릭터로 변환
    var convertm = m
    convertm = convertm.replacingOccurrences(of: "A#", with: "H")
        .replacingOccurrences(of: "C#", with: "I")
        .replacingOccurrences(of: "D#", with: "J")
        .replacingOccurrences(of: "F#", with: "K")
        .replacingOccurrences(of: "G#", with: "L")
    
    var matchSong = ""
    // 실제 플레이 된 사운드와 타이틀을 매치시킨 사전 준비
    var dict = [String : String]()
    
    // dict 작성
    for info in musicinfos {
        let str = info.components(separatedBy: ",")
        var (start, end, title, sound) = (str[0], str[1], str[2], str[3])
        // 시간 변환
        let (starthh, startmm) = (start.components(separatedBy: ":")[0],
                                  start.components(separatedBy: ":")[1])
        let (endhh, endmm) = (end.components(separatedBy: ":")[0],
                              end.components(separatedBy: ":")[1])
        let time = (Int(endhh)! - Int(starthh)!) * 60 + (Int(endmm)! - Int(startmm)!)
        
        // 재생한 사운드 작성
        sound = sound.replacingOccurrences(of: "A#", with: "H")
            .replacingOccurrences(of: "C#", with: "I")
            .replacingOccurrences(of: "D#", with: "J")
            .replacingOccurrences(of: "F#", with: "K")
            .replacingOccurrences(of: "G#", with: "L")
        
        // 처음부터 끝까지 반복 + 남은거 붙이기
        let playedSound = String(repeating: sound, count: time / sound.count)
            + sound[sound.startIndex..<sound.index(sound.startIndex, offsetBy: time%sound.count)]
        
        // dict 작성
        dict[playedSound] = title
    }
    
    for song in dict.keys {
        // 비교하고 싶은 음이 사전에 있으면
        if song.contains(convertm) {
            // 재생된 시간이 같을 경우 먼저 입력된 음악 제목을 반환
            if matchSong == "" {
                matchSong = song
            } else {
                // 조건이 일치하는 음악이 여러 개일 때에는 라디오에서 재생된 시간이 제일 긴 음악 제목을 반환
                if matchSong.count < song.count {
                    matchSong = song
                }
            }
        }
    }
    
    if matchSong == "" { return "(None)" }
    return dict[matchSong]!
}

# 자동완성

https://www.welcomekakao.com/learn/courses/30/lessons/17685

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import Foundation

// 두 문자를 비교한 횟수를 반환
func compare2(object: [String], target: [String]) -> Int {
    for i in 1...object.count {
        // 일치하지 않은 부분이 나타난 인덱스를 반환
        // 타겟길이가 오브젝트길이보다 짧으면 비교할 인덱스를 최대값으로 고정
        if object[0..<i].joined()
            != target[0..<min(i, target.count)].joined() { return i }
    }
    
    // 겹치는 부분이 없었으면 (=for문을 중간에 빠져나오지 못했으면) 길이를 그대로 반환
    return object.count
}

// 세 문자를 비교
func compare3(object: [String], targetL: [String], targetR: [String]) -> Int {
    for i in 1...object.count {
        if (object[0..<i].joined() != targetL[0..<min(i, targetL.count)].joined())
            && (object[0..<i].joined() != targetR[0..<min(i, targetR.count)].joined()) {
            return i
        }
    }
    
    return object.count
}


func solution(_ words:[String]) -> Int {
    // 고속탐색을 위해 입력받은 문자열을 정렬한 뒤 배열화
    var wordsArr = [[String]]()
    for word in words.sorted() {
        let splitWord = word.map { String($0) }
        wordsArr.append(splitWord)
    }
    
    var answer = 0
    
    for idx in 0..<wordsArr.count {
        if idx == 0 {
            // 첫번째 단어는 오른쪽 단어와 비교
            answer += compare2(object: wordsArr[idx], target: wordsArr[idx+1])
        } else if idx == wordsArr.count - 1 {
            // 마지막 단어는 왼쪽 단어와 비교
            answer += compare2(object: wordsArr[idx], target: wordsArr[idx-1])
        } else {
            // 나머지 단어는 좌우 단어들과 비교
            answer += compare3(object: wordsArr[idx], targetL: wordsArr[idx-1], targetR: wordsArr[idx+1])
        }
    }
    
    return answer
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import Foundation

// 데이터 저장 및 커서관리용 노드
class Node {
    var key: Character?
    var data: String?
    // 노드간 연결용 이름표 컨테이너
    var children = [Character : Node]()
    // 노드 순서를 표시하는 컨테이너
    var order: Int = 0
    
    init (_ key: Character?, data: String? = nil) {
        self.key = key
        self.data = data
    }
}

// 트라이 자료구조 클래스
// 캐릭터를 트리를 이용하여 포도송이처럼 연결시킨 구조
class Trie {
    var head: Node
    
    init() {
        self.head = Node(nil)
    }
    
    // 삽입용 함수
    func insert(_ str: String) {
        var curr_node = self.head
        
        // 입력받은 단어의 트리작성
        for char in str {
            // 요소가 없으면 char를 가지는 새 노드를 연결
            if curr_node.children[char] == nil {
                curr_node.children[char] = Node(char)
            }
            
            // 다음 노드로 이동
            curr_node.order += 1
            curr_node = curr_node.children[char]!
        }
        
        // 맨 마지막 노드의 data는 str이다
        curr_node.data = str
    }
    
    // 입력 문자열에 대한 값 반환
    func countInputWord(_ str: String) -> Int {
        var curr_node = self.head
        var count = 0
        
        // 전 노드 검색
        for char in str {
            curr_node = curr_node.children[char]!
            count += 1
            // 일치하는 단어가 있거나 첫번째 노드에 데이터가 없으면 중지
            if curr_node.data == str
                || (curr_node.order == 1 && curr_node.data == nil) {
                return count
            }
        }
        
        return count
    }
}
    

func solution(_ words:[String]) -> Int {
    
    // 입력으로부터 트라이 구조 작성
    let trie = Trie()
    for word in words {
        trie.insert(word)
    }
    
    // 입력값 계산
    var answer = 0
    for word in words {
        answer += trie.countInputWord(word)
    }

    return answer
}

# 필기 시험

http://tech.kakao.com/files/kakao-blind-recruitment.pdf (새 창으로 열기)

Built with Hugo
Theme Stack designed by Jimmy