# 입출력

# 1. 기본 입출력

var input = readLine()! // String

var input = Int(readLine()!)! // Int
// 문자열 여러줄 출력시 개행문자로 더해서 출력하기
var result = ""
result += String(repeating: "H", count: 5)
result += String(repeating: "Y", count: 5)
// HHHHH
// YYYYY

# 2. 공백 숫자 입력

// 두개 동일
var nums = readLine()!.split(separator: " ").map { Int($0)! }
var nums = readLine()!.components(separatedBy: " ").map { Int($0)! }
// FileIO 클래스 활용
let file = FileIO()
let nums: [Int] = []

nums.append(contentsOf: [file.readInt(), file.readInt()]) // 1 2 -> [1, 2]

# 3. 공백 없는 숫자 입력

// readLine으로 입력받은 모든 문자를 `Int`로 변환
var nums: [Int] = []

nums = Array(readLine()!).map { Int(String($0))! }

# Prefix / Suffix

// prefix(idx: Int): 0번부터 idx-1 까지 문자열 출력
let string = "hello경준~!"
let prefixData = string.prefix(5) // 스트링 서브시퀀스 타입
// suffix(idx: Int): length - idx부터 length - 1까지 문자열 출력
let string = "hello경준~!"
let suffixData = string.suffix(3) // 경준~!
// prefix & suffix는 배열 인덱스 범위를 넘어도 됨
let arr = [1,2,3]
arr.prefix(5) // 1,2,3

# split(whereSeparator: {})

// 클로저에 separate할 기준 조건문을 정의
// 숫자가 아닌 대상을 구분자로 사용하겠다는 의미
let string = "12!@3"
let result = string.split(whereSeparator: { !$0.isNumber }).map { Int($0)! } // [12, 3]

# 서브스트링

let string = "Hello경준"
let startIdx: String.Index = string.index(string.endIndex, offsetBy: -2)

// ...으로 서브스트링
print(String(string[startIdx...])) // 경준

# 문자열 반복

String(repeating: "H", count: 5) // HHHHH

# 문자열에 특정 문자 대체하기

let string = "Hello!경준!"
string.replacingOccurrences(of: "!", with: "?") // Hello?경준?

# stride

for i in stride(from: 3, to: 12, by: 3) {
    print(i) // 3 6 9
}
// from through by면 12까지 출력

# 수식

// 1. 절댓값
abs(-11) // 11

// 2. 제곱
let value = 3.0
pow(value, 2) // 9.0

// 3. 제곱근
let value = 9.0
sqrt(value) // 3.0

// 4. 모든 자릿수 더하기
// 1 + 2 + 3 = 6
String(123).map { String($0) }.reduce(0){ $0 + Int($0)! }

# 배열

// firstIndex 찾아서 삭제하기
if let index = array.firstIndex(where: { $0 == value }) {
    array.remove(at: index)
}
// joined - [String]을 하나의 String으로 리턴
var strings = ["HI", "HELLO"]
strings.joined() // HIHELLO
strings.joined(separator: ",") // HI,HELLO

// 문자열이 아닌 배열을 하나의 문자로 합치려면 String 타입캐스팅 먼저 진행
var nums: [Int] = [1,2,3]
nums.map { String($0) }.joined() // "123"

# Set

  1. 비정렬 컬렉션
  2. 중복 없음. 중복된 값 삽입시 튜플에 false 리턴
  3. contains, insert, update, remove, removeAll 메서드 사용
tempSet.contains(1)                    // true
tempSet.contains(10)                   // false

// insert : 값을 추가하고, 추가된 결과를 튜플로 리턴 (중복이면 false, 추가된 값)
tempSet.insert(1)                // (false, 1)
tempSet.insert(10)               // (true, 10)

// update : 값이 존재하지 않으면 추가 후 nil 리턴, 존재할 경우 덮어쓰기 후 덮어쓰기 전 값 리턴
tempSet.update(with: 1)          // Optioanl(1)
tempSet.update(with: 120)        // nil

// remove() : 한 가지 요소 삭제할 때 사용, 삭제 후 삭제한 값 return (없는 요소 삭제 시 nil 리턴)
tempSet.remove(1)              // Optional(1)
tempSet.remove(10)             // nil

// removeAll() : 전체 요소 삭제
tempSet.removeAll()

# 최대공약수, 최소공배수

// 최대공약수
func GCD(_ a: Int, _ b: Int) -> Int {
    let mod: Int = a % b
    return 0 == mod ? min(a, b) : GCD(b, mod)
}

// 최소공배수
func LCM(_ a: Int, _ b: Int) -> Int {
    return a * b / GCD(a, b)
}

# FileIO 클래스

final class FileIO {
    private let buffer:[UInt8]
    private var index: Int = 0

    init(fileHandle: FileHandle = FileHandle.standardInput) {

        buffer = Array(try! fileHandle.readToEnd()!)+[UInt8(0)] // 인덱스 범위 넘어가는 것 방지
    }

    @inline(__always) private func read() -> UInt8 {
        defer { index += 1 }

        return buffer[index]
    }

    @inline(__always) func readInt() -> Int {
        var sum = 0
        var now = read()
        var isPositive = true

        while now == 10
                || now == 32 { now = read() } // 공백과 줄바꿈 무시
        if now == 45 { isPositive.toggle(); now = read() } // 음수 처리
        while now >= 48, now <= 57 {
            sum = sum * 10 + Int(now-48)
            now = read()
        }

        return sum * (isPositive ? 1:-1)
    }

    @inline(__always) func readString() -> String {
        var now = read()

        while now == 10 || now == 32 { now = read() } // 공백과 줄바꿈 무시

        let beginIndex = index-1

        while now != 10,
              now != 32,
              now != 0 { now = read() }

        return String(bytes: Array(buffer[beginIndex..<(index-1)]), encoding: .ascii)!
    }

    @inline(__always) func readByteSequenceWithoutSpaceAndLineFeed() -> [UInt8] {
        var now = read()

        while now == 10 || now == 32 { now = read() } // 공백과 줄바꿈 무시

        let beginIndex = index-1

        while now != 10,
              now != 32,
              now != 0 { now = read() }

        return Array(buffer[beginIndex..<(index-1)])
    }
}

# 순열

func permutation<T>(_ elements: [T], _ k: Int) -> [[T]] {
    var result: [[T]] = [[]]
    var visited: [Bool] = .init(repeating: false, count: elements.count)

    func permut(_ now: [T]) {
        if now.count == k {
            result.append(now)
            return
        }

        for i in 0..<elements.count {
            if visited[i] { continue }
            visited[i] = true
            permut(now + [elements[i]])
            visited[i] = false
        }
    }

    permut([])
    return result
}

# 조합

func combination<T>(_ elements: [T], _ k: Int) -> [[T]] {
    var result = [[T]]()

    func combi(_ index: Int, _ now: [T]) {
        if now.count == k {
            result.append(now)
            return
        }
        for i in index..<elements.count {
            combi(i + 1, now + [elements[i]])
        }
    }
    combi(0, [])
    return result
}

# 팩토리얼

func factorial(_ n: Int) -> Int {
    var n = n
    var result = 1
    while n > 1 {
        result *= n
        n -= 1
    }
    return result
}

# 외워야할 숫자

  1. 10! - 대략 360만
  2. 2^10 - 1024
  3. 3^10 - 대략 6만

시간복잡도 1억 이하면 시도할만한 알고리즘

# Reference

  1. 스위프트 코딩테스트 대비 잡다한 지식 (opens new window)
  2. swift 코딩테스트에 필요한 지식 정리 (opens new window)