문제해설
http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/
비밀지도 (비트연산)
https://www.welcomekakao.com/learn/courses/30/lessons/17681
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
func solution(_ n:Int, _ arr1:[Int], _ arr2:[Int]) -> [String] {
var answer = [String](repeating: "", count: n)
var bitAdded = Array<Int>()
for i in 0..<n {
bitAdded.append(arr1[i] | arr2[i])
}
for i in 0..<n {
for _ in 0..<n {
// 2진수로 변환한 값의 맨 뒷자리가 튀어나온다
// 그걸 반환배열의 맨 앞으로 넣어준다
answer[i].insert(bitAdded[i] % 2 == 1 ? "#" : " ", at: answer[i].startIndex)
// 비트를 오른쪽으로 하나 옮김
bitAdded[i] >>= 1
}
}
return answer
}
|
다트 게임 (정규표현식)
https://www.welcomekakao.com/learn/courses/30/lessons/17682
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
|
import Foundation
// 정규표현식을 쓸수있도록 스트링 타입을 확장
extension String{
func getAllMatchAfterRegex(_ pattern: String) -> [String] {
// 옵셔널을 벗기기 위해 do-catch를 사용
do {
let regex = try NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(self.startIndex..., in: self)
let matches = regex.matches(in: self, range: range)
return matches.map {
String(self[Range($0.range, in: self)!])
}
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
}
func solution(_ dartResult: String) -> Int {
// 입력을 정규표현식으로 자르기
let pointArr = dartResult.getAllMatchAfterRegex("[0-9]+") // 두자리수까지 탐색
let bonusArr = dartResult.getAllMatchAfterRegex("[(S|D|T)]") // 고정인 알파벳만 탐색
let optionArr = dartResult.getAllMatchAfterRegex("(?<=S|D|T)[(*|#)]?") // 후방탐색
var result = [Int]()
for i in 0..<3 {
let newArray = [pointArr[i], bonusArr[i], optionArr[i]]
// 점수 결정
let point = Double(newArray[0])!
// 보너스값 결정
var bonus: Double = 1
if newArray[1] == "D" {
bonus = 2
} else if newArray[1] == "T" {
bonus = 3
}
// 옵션 결정 후 값 반영
if newArray[2] == "*" {
if i == 0 {
result.append(Int(pow(point, bonus) * 2))
} else {
// 바로 앞의 결과값에 2를 곱해줌
result[result.index(before: result.endIndex)] *= 2
result.append(Int(pow(point, bonus) * 2))
}
} else if newArray[2] == "#" {
result.append(Int(pow(point, bonus) * -1))
} else {
result.append(Int(pow(point, bonus)))
}
}
return result.reduce(0) { $0 + $1 }
}
|
캐시
https://www.welcomekakao.com/learn/courses/30/lessons/17680
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 solution(_ cacheSize:Int, _ cities:[String]) -> Int {
let CACHE_HIT = 1
let CACHE_MISS = 5
var answer = 0
var cache = [String : Int]()
var time = 0
if cacheSize == 0 {
answer += cities.count * CACHE_MISS
return answer
}
for city in cities {
time += 1
// 대소문자 구분 없앰
let city = city.lowercased()
if cache[city] != nil {
// 캐시가 히트하면 인덱스의 타임을 최신값으로 갱신
cache[city] = time
answer += CACHE_HIT
} else {
// 캐시미스일때 현재 캐시크기가 캐시사이즈보다 작으면 그냥 추가
if cache.count < cacheSize {
cache[city] = time
answer += CACHE_MISS
} else {
// 그렇지 않으면 가장 오래된 캐시를 삭제하고 값을 추가
let oldest = cache.min { a, b in a.value < b.value }!
cache.remove(at: cache.index(forKey: oldest.key)!)
cache[city] = time
answer += CACHE_MISS
}
}
}
return answer
}
|
셔틀버스 (문자열 시간변환, 딕셔너리)
https://www.welcomekakao.com/learn/courses/30/lessons/17678
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
84
85
86
87
88
89
90
91
92
|
import Foundation
func solution(_ n:Int, _ t:Int, _ m:Int, _ timetable:[String]) -> String {
// 문자열 타임테이블을 가공하기 용이하게 숫자로 변환
var cvtTimetable = [Int]()
// 시간을 네자리 정수로 변환
for time in timetable {
let convert = time[time.startIndex].wholeNumberValue! * 1000
+ time[time.index(time.startIndex, offsetBy: 1)].wholeNumberValue! * 100
+ time[time.index(time.startIndex, offsetBy: 3)].wholeNumberValue! * 10
+ time[time.index(time.startIndex, offsetBy: 4)].wholeNumberValue!
cvtTimetable.append(convert)
}
// 오름차순으로 소트
cvtTimetable = cvtTimetable.sorted(by: <)
// 버스 출발타임을 0900으로 설정
var busStartTime: Int = 0900
var answer: Int = 0
var crewIdx: Int = 0
// 각 버스에 대한 체크 시작
for _ in 0..<n {
var crewMember: Int = 0
var arriveTime: Int = 0
// 크루도착시간과 도착순서 관계 컨테이너 초기화
var watingCue = [Int : Int]()
// 버스 출발시간보다 빨리 온 크루의 도착시간 딕셔너리를 작성
while (crewMember < m && crewIdx < timetable.count) {
// 크루가 버스보다 늦게 왔으면 추가하지 않고 지나감
if (cvtTimetable[crewIdx] > busStartTime) {
break
}
// 버스 출발시간보다 빨리 온 크루를 딕셔너리에 순서대로 등록
watingCue[cvtTimetable[crewIdx]] = crewIdx + 1
crewIdx += 1
crewMember += 1
}
// 타려고 대기한 크루의 배열을 소팅함
let sortedCue = watingCue.sorted(by: <)
// 타려고 대기한 총 인원이 버스의 승차가능인보다 적으면 버스출발시간에 오면 됨
if (crewMember < m) {
answer = max(answer, busStartTime)
} else {
// 대기멤버가 승차가능인보다 많으면 연산시작
var check = 0
for cue in sortedCue {
// 탑승가능한 맨 마지막 크루에 대해 체크
if (check + cue.value >= m) {
// 그 크루보다 1분 빠르게 도착하도록 함
arriveTime = cue.key - 1
// 08:99를 08:59로 바꿔줌
if (arriveTime % 100 > 59) {
arriveTime -= 40
}
// 00:00 에서 -1 하면 24:00이 되도록 보정
if arriveTime < 0 {
arriveTime += 2400
}
}
check += cue.value
}
answer = max(answer, arriveTime)
}
// 시작시간을 버스 다음 도착시간으로 변경
busStartTime += t
// minute가 59보다 커질 경우 1 hour 추가하고 min에서 60을 빼줌
if (busStartTime % 100 > 59) {
busStartTime += 100
busStartTime -= 60
}
}
// 답 작성
var hh = String(answer / 100)
if (hh.count < 2) { hh = "0" + hh }
var mm = String(answer % 100)
if (mm.count < 2) { mm = "0" + mm }
return hh + ":" + mm
}
|
뉴스 클러스터링 (집합, 딕셔너리)
https://www.welcomekakao.com/learn/courses/30/lessons/17677
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
84
85
86
87
88
|
import Foundation
func solution(_ str1:String, _ str2:String) -> Int {
// 분리한 입력문자를 저장할 컨테이너
var splitstr1 = [String]()
var splitstr2 = [String]()
// 각 요소의 개수가 몇 개씩 있는지 기록할 딕셔너리 준비
var set1 = [String : Int]()
var set2 = [String : Int]()
var intersectSet: Int = 0 // 교집합 개수
var unionSet: Int = 0 // 합집합 개수
// 입력문자를 두개씩 분리
for i in 0..<str1.count - 1 {
// 대문자로 변환한 스트링을 앞에서부터 두 문자씩 빼옴
let first = String(str1[str1.index(str1.startIndex, offsetBy: i)]).uppercased()
let second = String(str1[str1.index(str1.startIndex, offsetBy: i + 1)]).uppercased()
// 문자가 알파벳일때만 배열에 추가
if "A" <= first && first <= "Z"
&& "A" <= second && second <= "Z" {
splitstr1.append(first + second)
}
}
// set1 작성
for elem in splitstr1 {
// 각 요소 개수세기
let count = splitstr1.filter { $0 == elem }.count
// 딕셔너리 형태로 저장
set1[elem] = count
}
// 입력문자를 두개씩 분리
for i in 0..<str2.count - 1 {
// 대문자로 변환한 스트링을 앞에서부터 두 문자씩 빼옴
let first = String(str2[str2.index(str2.startIndex, offsetBy: i)]).uppercased()
let second = String(str2[str2.index(str2.startIndex, offsetBy: i + 1)]).uppercased()
// 문자가 알파벳이면 추가
if "A" <= first && first <= "Z"
&& "A" <= second && second <= "Z" {
splitstr2.append(first + second)
}
}
// set2 작성
for elem in splitstr2 {
// 각 요소 개수세기
let count = splitstr2.filter { $0 == elem }.count
// 딕셔너리 형태로 저장
set2[elem] = count
}
// set1에 대해 set2를 비교
for it in set1 {
// set1의 키값이 set2에도 있으면
if (set2[it.key] != nil) {
// 작은값을 교집합에 추가
intersectSet += min(it.value, set2[it.key]!)
// 큰 값을 합집합에 추가
unionSet += max(it.value, set2[it.key]!)
} else {
// 키값이 없으면 합집합에 set1 요소만 추가
unionSet += it.value
}
}
// set2에 대해 set1을 비교
for it in set2 {
// set1에 대응되는 값이 없으면
if (set1[it.key] == nil) {
// 합집합에 set2 요소만 추가
unionSet += it.value
}
}
// 예외처리
if unionSet == 0 { return 65536 }
// 답안 작성
intersectSet *= 65536
return intersectSet / unionSet
}
|
프렌즈 4블록 (2차원배열, 스왑)
https://www.welcomekakao.com/learn/courses/30/lessons/17679
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
84
85
86
87
|
import Foundation
func solution(_ m:Int, _ n:Int, _ board:[String]) -> Int {
var isFinished = false
var answer = 0
// 입력받은 문자열배열을 2차원 캐릭터배열로 분리변환
var newBoard = [[String]]()
for elem in board {
var arr = [String]()
for e in elem {
arr.append(String(e))
}
newBoard.append(arr)
}
while true {
isFinished = true
var judgeBoard = [[Bool]](repeating: Array(repeating: false, count: n), count: m)
for row in 1 ..< m {
for col in 1 ..< n {
// 배열을 순회하면서 인접한 사각 요소를 가져옴
let a = newBoard[row - 1][col - 1]
let b = newBoard[row - 1][col]
let c = newBoard[row][col - 1]
let d = newBoard[row][col]
// 사각 요소가 모두 일치하는지 확인
if (a == b && b == c && c == d) {
if a == "-" { continue }
// 일치하면 다음 요소를 검색
isFinished = false
// 판정 보드에 트루라고 기록
judgeBoard[row - 1][col - 1] = true
judgeBoard[row - 1][col] = true
judgeBoard[row][col - 1] = true
judgeBoard[row][col] = true
}
}
}
// 배열을 순회하면서 true이면 newBoard값을 -로 변경
for row in 0 ..< m {
for col in 0 ..< n {
if judgeBoard[row][col] {
newBoard[row][col] = "-"
}
}
}
// 삭제하고 나서 떠있는 블럭을 밑으로 떨어뜨림
for row in 0 ..< n {
for j in (0 ... m - 1).reversed() {
// for j in stride(from: m - 1, through: 0, by: -1) {
var col = j
// 한 칸씩 내려보내다가 빈공간(-)이 없어지면 중단한다
while (col + 1 < m && newBoard[col + 1][row] == "-") {
// 아래 위 보드 내용을 스왑
let temp = newBoard[col][row]
newBoard[col][row] = newBoard[col + 1][row]
newBoard[col + 1][row] = temp
col += 1
}
}
}
// 처리가 끝났으면 종료한다
if (isFinished) { break }
}
// -의 갯수를 계수한다
for row in 0 ..< m {
for col in 0 ..< n {
if (newBoard[row][col] == "-") {
answer += 1
}
}
}
return answer
}
|
추석 트래픽 (문자열 시간변환)
https://www.welcomekakao.com/learn/courses/30/lessons/17676
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
|
import Foundation
func convertTime(_ input: [String]) -> [[Double]] {
var startList = [Double]()
var endList = [Double]()
for i in input {
let (timeStr, durationStr) = (i.split(separator: " ")[1], i.split(separator: " ")[2])
// 시간 문자열을 sec 스케일의 숫자로 변환
let timeSplit = timeStr.split(separator: ":")
let hour = Double(String(timeSplit[0]))! * 3600
let min = Double(String(timeSplit[1]))! * 60
let sec = Double(String(timeSplit[2][timeSplit[2].startIndex...timeSplit[2].index(after: timeSplit[2].startIndex)]))!
let subsec = Double("0." + String(timeSplit[2][timeSplit[2].index(timeSplit[2].startIndex, offsetBy: 3)..<timeSplit[2].endIndex]))!
// 간격 가져오기
let duration = Double(String(durationStr[durationStr.startIndex..<durationStr.index(before: durationStr.endIndex)]))!
// 시작과 종료시간을 각각 배열화
let endTime: Double = hour + min + sec + subsec
let startTime: Double = endTime - duration + 0.001
startList.append(startTime)
endList.append(endTime)
}
return [startList, endList]
}
func solution(_ lines:[String]) -> Int {
let converttime = convertTime(lines)
let (startList, endList) = (converttime[0], converttime[1])
var request = [Int]()
// 각 시작시간과 종료시간의 직전, 직후 윈도우 요청수만을 확인
for k in (startList + endList) {
var count = 0
for (i, j) in zip(startList, endList) {
if i < k + 1 && j >= k {
count += 1
} else {
count += 0
}
}
request.append(count)
}
return request.max()!
}
|