TIL/알고리즘 공부
프로그래머스 Lv. 2 Swift 알고리즘 - n^2 배열 자르기
여의도사노비
2023. 1. 8. 16:36
728x90
결국 시간초과와 Core dumped... 등의 오류로 못푼 문제이다...
그래서 구글링 좀 했는데 Swift 자료는 그리 많지 않았다.
그래서 한 분의 코드를 참고할 수 밖에 없었다.
도입부 부분은 내가 생각했던 것과 크게 다르지 않은데 전체적으로 적용되는 알고리즘을 전부 파악하고 깔끔하게 설계하신 것이...
정말 대단한 알고리즘 고수분들이 많다 ㅜ-ㅜ
그리고 나도 테스트 코드는 몇개 돌아가는데 결국 시간 초과 오류가 발생하는 것이 가장 큰 문제였다. 한 끗 차이로(?) 코드가 돌아가고 안돌아가고 하는데... 매번 시간 초과 오류로 문제를 겪는 나의 모습을 보면 Swift의 백그라운드에 있는 메모리 문제에 대해서 전혀 모르고 있는 것 같다.(그래서 관련 영상을 곧 구입하여 공부해볼 예정이다...)
이 문제를 풀면서 생각한 논리적 흐름
- 주어진 n과 문제의 논리를 따라가면 결국 1, 22, 333.. 이런 식으로 각 차수에 따라 원소가 정해진다.
- 그리고 이때 1, 22처럼 주어진 n의 개수보다 카운트 값이 작은 원소들은 그 뒤로 1씩 증가하는 값을 갖는다. (123, 223, 333)
- 그래서 먼저 1, 22, 333 식의 배열을 만들어둔다.
- 그 다음 n의 값보다 원소길이가 부족한 값들은 for문을 통해 2, 3 등의 값들을 붙여준다.
- 그렇게 붙여준 값들을 다시 붙여주고 각 원소들을 전부 Int로 매핑해준다.
- 그 다음 인덱스를 이용하여 프린트해준다.
- 여기까지가 내가 적은 틀린 코드의 논리이다.
- 참고한 답안 코드는 left, right을 n으로 나누어 1, 22 와 같은 배열을 완성해준다.
- 그리고 left, right을 n으로 나눈 나머지를 이용하여 그 위치의 값들을 구해준다.
- 훨씬 간단하고 직관적이다..! 문제의 제목인 n^2 배열 자르기라는 말이 왜 적용됐는지 바로 이해됐다...
* 내가 적은 틀린 코드
import Foundation
func solution(_ n:Int, _ left:Int64, _ right:Int64) -> [Int] {
let leftInt = Int(left)
let rightInt = Int(right)
var str: String = ""
var subStr: String = ""
var arr: [String] = []
var ans: String = ""
var ansArray1: [String] = []
var ansArray2: [Int] = []
var ansArray3: [Int] = []
for i in 1...n {
for _ in 1...i {
str += String(i)
}
arr.append(str)
str = ""
}
for i in 0...arr.count-1 {
if arr[i].count < n {
for _ in 0...(n-arr[i].count-1) {
subStr = String(Int(arr[i])! % 10 + 1)
arr[i] += subStr
}
}
}
ans = arr.joined()
ansArray1 = ans.map{String($0)}
ansArray2 = ansArray1.map{Int($0)!}
for i in leftInt...rightInt {
ansArray3.append(ansArray2[i])
}
return ansArray3
}
일단 이 코드를 짤때 변수명은 1도 신경쓰지 않았다... 너무 안풀려서 답을 내는 것에 온전히 초점을 맞추었다. 결과적으로 몇가지 테스트케이스들은 만족했지만, 대부분이 Coredumped, 시간초과 등의 오류가 발생하였다. 근데 내가 봐도 코드가 너무 더럽고 비효율적이다...
* 참고한 답안 코드
func solution(_ n:Int, _ left:Int64, _ right:Int64) -> [Int] {
let startColumn:Int = Int(left)/n
let endColumn:Int = Int(right)/n
let startRow:Int = Int(left)%n
let endRow:Int = Int(right)%n
var answer:[Int] = []
for i in startColumn...endColumn {
var numbers:[Int] = Array(repeating: i+1, count:i+1)
if i+1 < n {
let tail:[Int] = Array(i+2...n)
numbers.append(contentsOf: tail)
}
if startColumn == endColumn {
return Array(numbers[startRow...endRow])
}
if i == startColumn {
answer.append(contentsOf: Array(numbers[startRow...]))
continue
}
if i == endColumn {
answer.append(contentsOf: Array(numbers[0...endRow]))
continue
}
answer.append(contentsOf: numbers)
}
return answer
}
정리(Today I Learned)
- Array를 사용할 때 contentsOf를 사용한 적이 없었던 것 같다.
Sequence로 이루어진 값들을 추가할 때 사용하는 메서드인데, 이를 이용하면 좀 더 깔끔하게 코드를 수정할 수 있을 것 같다. - break 문은 많이 써봤지만 continue문은 사용한 적이 없었던 것 같다.
break가 진행되고 있는 반복구문을 바로 종료시킨다고 하면, continue는 continue 코드를 실행하는 시점부터 아래의 코드를 무시하고 다음 반복문을 돌리라는 뜻이라고 볼 수 있다.