[iOS] swift 알고리즘, 코딩테스트에 필요한 tip 정리

ungchun·2022년 5월 6일
17
post-thumbnail

코딩테스트를 스위프트로 준비하면서 자주 검색하거나 사용하는 문법들을 정리해보려 합니다. 계속 추가하고 수정할 예정입니다.


기본 입력 받기

// return String
var input = readLine()!

// return Int
var input = Int(readLine()!)!

"1 2 3 4 5"와 같은 공백 있는 숫자 입력 받기

// split - return: [SubString] 
var nums = readLine()!.split(separator: " ").map {Int($0)!} 

// components - return: [String] -> import Foundation 필수
var nums = readLine()!.components(separatedBy: " ").map {Int($0)!}

// FileIO, 입력받으면서 리스트에 바로 추가하기
array.append((file.readInt(), file.readInt()))

"12345"와 같은 공백 없는 숫자를 배열로 입력 받기

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

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

// FileIO
let nums = [file.readInt(), file.readInt()]

입력값 시간초과 -> fread의 swift 버전 (라이노님 FileIO)

github

보통 입출력이 10~20만 줄 넘어가면 쓰는걸 추천
xcode 터미널에서 엔터가 아닌 EOF를 입력해야 입력 완료가 된다. 터미널에서 값을 입력한 뒤 제일 마지막에 Ctrl + D를 입력하면 출력값이 나온다.


prefix / suffix

let strData = "hello성훈!!"

// [prefix : 시작 기준으로 지정한 문자 개수 출력]
let startData = strData.prefix(5)
print(startData)  // hello

// [suffix : 종료 기준으로 지정한 문자 개수 출력]
let endData = strData.suffix(4)
print(endData) // 성훈!!


let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(2))
// Prints "[1, 2]"
print(numbers.prefix(10))
// Prints "[1, 2, 3, 4, 5]"

let numbers = [1, 2, 3, 4, 5]
print(numbers.suffix(2))
// Prints "[4, 5]"
print(numbers.suffix(10))
// Prints "[1, 2, 3, 4, 5]"

split(whereSeparator: {})

/// 기준이 되는 문자를 제외한 요소를 배열로 만들어 리턴
let dartResult = "1S2D*3T"
var scores = dartResult.split(whereSeparator: {!$0.isNumber}).map {Int($0)!}
print(scores)
// Prints "[1, 2, 3]"
let letters = dartResult.split(whereSeparator: {$0.isNumber})
print(letters)
// Prints "["S", "D*", "T"]"

subString

// 3번째부터 끝까지
let startIdx: String.Index = str.index(str.startIndex, offsetBy: 3)
var result = String(str[startIdx...])

// 처음부터 3번째까지
let endIdx: String.Index = str.index(str.startIndex, offsetBy: 3)
var result = String(str[...endIdx])

문자열 반복

let str = String(repeating: "ㅋ", count: 10)
print(str) // "ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ"

문자열에 특정 문자 바꾸기

// import Foundation 필수
let str = "ung!chun!"
let str2 = str.replacingOccurrences(of: "!", with: "?")
print(str2) // ung?chun?

개행없는 print

print("Hello", terminator:"")

forEach

let nums: [Int] = [1, 2, 3, 4]

nums.forEach {
	print($0) // 1 2 3 4
}

stride

// 3 6 9
for i in stride(from: 3, to: 12, by: 3) {
    print(i)
}

// 3 6 9 12
for i in stride(from: 3, through: 12, by: 3) {
    print(i)
}

절대값

// 11
abs(-11)

제곱

let value = 3.0 

// 9.0
pow(value, 2) 

제곱근 구하기

let value = 9.0

// 3.0
sqrt(value) 

자릿수 더하기

// n = 123, return = 6
String(n).map{ String($0)}.reduce(0){ $0 + Int($1)! }

배열 요소에 접근하기

var array = [1, 2, 3, 4, 5]

// [2, 3, 4]
array[1...3]    

배열에 요소 추가하기

var array = [1, 2, 3]

array.append(4) // [1, 2, 3, 4]
array.append(contentsOf: [5, 6, 7]) // [1, 2, 3, 4, 5, 6, 7]

배열에 원하는 값 index 찾아서 삭제하기

if let index = array.firstIndex(where: {$0 == value}) {
	array.remove(at: index)
}

1차원 배열 선언

let arr = [Int]() 

let arr = Array(repeating: 0, count: 5) 
let arr = [Int](repeating: 0, count: 5)

2차원 배열 선언

let arr = [[Int]]() 

let arr = Array(repeating: Array(repeating: 0, count: 3), count: 5) 
let arr = [[Int]](repeating: [Int](repeating: 0, count: 3), count: 5)

map

var string = ["1","2","3","4"]

// [1,2,3,4] 각 원소를 전부 Int로 맵핑
string.map { Int($0)! } 

filter

var array = [1,2,3,4]

// [2,4] 조건에 맞는 수만 뽑아냄
array.filter { $0 % 2 == 0 } 

reduce

// 초깃값이 3이고 정수 배열의 모든 값을 더하는 코드
let numbers: [Int] = [1, 2, 3]
var sumFromThree: Int = numbers.reduce(3) {
    print("\($0) + \($1)")
    // 3 + 1
    // 4 + 2
    // 6 + 3
    return $0 + $1
}
print(sumFromThree) // 9

// 간단하게는 이렇게도 가능하긴함
var array = [1,2,3,4]

// 숫자 합이 나타남. 문자열 합치기도 가능
array.reduce(0, +) 
// 문자열 합치기는 joined()를 사용하자. reduce가 훨씬 느림

joined()

joined는 배열의 문자열들을 하나의 문자열로 반환하는 것이기 때문에 배열의 요소들이 문자열 이어야 합니다.

var brands = ["Dell", "HP", "Apple"]

// DellHPApple
var result1 = brands.joined()

// Dell HP Apple
var result2 = brands.joined(separator:" ")

// Dell, HP, Apple
var result3 = brands.joined(separator:", ")

// 만약 문자열이 아니라면 문자열로 바꾸고 진행해야함
var result: [Int] = [1, 2, 3, 4]
result.map{String($0)}.joined() // [1, 2, 3, 4] -> 1234
result.map{String($0)}.joined(separator: ", ") // [1, 2, 3, 4] -> 1, 2, 3, 4

flatMap(), compactMap()

let array1 = [1, nil, 3, nil, 5, 6, 7]
let flatMapTest1 = array1.flatMap{ $0 }
let compactMapTest1 = array1.compactMap { $0 }

// flatMapTest1 : [1, 3, 5, 6, 7]
// compactMapTest1 : [1, 3, 5, 6, 7]
  • 1차원 배열에서는 둘 다 동일한 결과를 나타내지만 Swift 4.1 부터는 1차원 배열에서 nil을 제거하고 옵셔널 바인딩을 하고싶을때는 flatMap 말고 compactMap을 사용하라고 한다.
let array2: [[Int?]] = [[1, 2, 3], [nil, 5], [6, nil], [nil, nil]]
let flatMapTest2 = array2.flatMap { $0 }
let compactMapTest2 = array2.compactMap { $0 }

// flatMapTest2 : [Optional(1), Optional(2), Optional(3), nil, Optional(5), Optional(6), nil, nil, nil]
// compactMapTest2 : [[Optional(1), Optional(2), Optional(3)], [nil, Optional(5)], [Optional(6), nil], [nil, nil]]
  • flatMapt과 compactMap은 nil을 제거하지않고 1차원 배열일때만 nil 제거
  • flatMap은 2차원배열을 1차원배열로 flatten 하게 만들어주는 반면, compactMap은 1차원 배열로 만들지 않습니다. -> 2차원 배열을 1차원으로 만들때는 flatMap 사용
let array2: [[Int?]] = [[1, 2, 3], [nil, 5], [6, nil], [nil, nil]]
let flatMapTest2 = array2.flatMap { $0 }.compactMap{ $0 }

// flatMapTest2 : [1, 2, 3, 5, 6]
  • flatMap 으로 flatten 하게 만들고 compactMap 으로 처리하면 편하게 2차원 배열을 옵셔널 바인딩 한 1차원 배열로 출력 가능
let array3 = [[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]]

let flatMapTest3 = array3.flatMap { $0 }
// [[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]

let doubleflatMapTest3 = flatMapTest3.flatMap { $0 }
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • 3차원 배열도 flatMap 2번 사용하면 flatten 하게 처리 가능

Set

  • 정렬되지 않은 컬렉션
  • 중복 허용 x
  • 해시를 통해 값을 저장해서 배열에 비해 검색 속도가 빠르다. (저장되는 자료형은 Hashable 프로토콜 준수해야함)
// 생성
var tempSet: Set<Int> = []
var tempSet = Set<Int>()

var tempSet: Set<Int> = [1, 2, 5, 0]

let count: Int = tempSet.count            // Set 갯수 확인 : 4
let isEmpty: Bool = tempSet.isEmpty       // Set 비었는지 확인 : false

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()  

dictionary

// 생성
var dict: [String: Int] = [:]  
var dict = [String: Int]()

// 갯수 확인
let count: Int = dict.count
let isEmpty: Bool = dict.isEmpty

var dict = ["height": 165, "age" : 100]

let height = dict["height"] // Optional(165)
let weight = dict["weight"] // nil

dict["weight"] = 100 // 해당 Key가 없다면, 추가 (insert)
dict["height"] = 200 // 해당 Key가 있다면, Value 덮어쓰기 (update)                                

dict["weight"] = nil // 해당 Key가 없어도 에러 안남
dict["height"] = nil // 해당 Key가 있다면, 해당 Key-Value 삭제
dict.removeAll() // 전체 삭제

dict.keys // "height, "age"
dict.keys.sorted() // "age", "height

dict.values // 165, 100
dict.values.sorted() // 100, 165

dict.sorted(by: {$0.value > $1.value})

dict.filter(condition) // 해당 클로저를 만족하는 요소만 모아서 새 딕셔너리로 리턴 

var v = [[Int]]()
var xDic = [Int: Int]()
xDic[v[i][0]]
let x = xDic.filter {$0.value < 2}.keys
ans.append(contentsOf: xDic.values.filter {$0 < 2})

2차원 배열 정렬하기

var arr = [[0, 3], [1, 9], [2, 6]]
let sortedArray = arr.sorted(by: {$0[1] < $1[1] }) // 각 배열 두 번째 수 기준으로 오름차순
let sortedArray = arr.sorted(by: {$0.1 < $1.1 }) // 같은 결과
print(sortedArray) // [[0, 3], [2, 6], [1, 9]]

init (repeating: count: )

// 수박수박수박수박
let watermelon4 = String(repeating: "수박", count: 4)
print(watermelon4)

// [false, false, false, false, false]
let liar = Array(repeating: false, count: 5)
print(liar)

배열안에 담긴 숫자만큼 일일이 print하면 매번 print하는 것도 상당히 느리기때문에 시간초과 되는 경우가 많은데 String - init ( repeating: count: ) 로 한번에 만들어서 String에 저장해서 출력하면 시간초과를 막을 수 있다. -> 수 정렬하기 3 참고

var answer = ""
// \n 이용해서 한 줄에 하나씩 출력
answer += String(repeating: "\(value)\n", count: countValue)
// 공백 이용해서 한 줄에 띄어서 출력
answer += String(repeating: "\(value) ", count: countValue)
// 한 줄에 붙여서 출력
answer += String(repeating: "\(value)", count: countValue)
print(answer)

최대공약수, 최소공배수

// 최대공약수
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)
}

heap / 우선순위 큐


순열과 조합


0개의 댓글