문자열 s가 주어졌을 때, s의 각 위치마다 자신보다 앞에 나왔으면서, 자신과 가장 가까운 곳에 있는 같은 글자가 어디 있는지 알고 싶습니다.
예를 들어, s="banana"라고 할 때, 각 글자들을 왼쪽부터 오른쪽으로 읽어 나가면서 다음과 같이 진행할 수 있습니다.
b는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.
a는 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.
n은 처음 나왔기 때문에 자신의 앞에 같은 글자가 없습니다. 이는 -1로 표현합니다.
a는 자신보다 두 칸 앞에 a가 있습니다. 이는 2로 표현합니다.
n도 자신보다 두 칸 앞에 n이 있습니다. 이는 2로 표현합니다.
a는 자신보다 두 칸, 네 칸 앞에 a가 있습니다. 이 중 가까운 것은 두 칸 앞이고, 이는 2로 표현합니다.
따라서 최종 결과물은 [-1, -1, -1, 2, 2, 2]가 됩니다.
문자열 s이 주어질 때, 위와 같이 정의된 연산을 수행하는 함수 solution을 완성해주세요.
func solution(_ s:String) -> [Int] {
var answer: [Int] = []
var visitS: Set<String> = []
for (index, chr) in s.enumerated() {
if visitS.contains(String(chr)) {
let firstChr = s.enumerated().filter { $0.offset < index && $0.element == chr }.sorted(by: { $0.offset < $1.offset }).last!
let firstIndex = s.index(s.startIndex, offsetBy: firstChr.offset)
let currentIndex = s.index(s.startIndex, offsetBy: index)
let distance = s.distance(from: firstIndex, to: currentIndex)
answer.append(distance)
} else {
visitS.insert(String(chr))
answer.append(-1)
}
}
return answer
}

아무래도 기존의 코드는 filter나 sorted 등 고차함수를 많이 이용하고, 이 때문에 시간 복잡도도 증가하여 성능적으로 문제가 많아 보인다. 때문에 이를 보완하여 다시 제출해보도록 하였다.
Set<String> 제거 -> Dictionary로 대체enumerated().filter().sorted().last! 제거 -> 딕셔너리를 이용하여 O(1) 조회distance(from:to:)제거 -> index값 활용func solution(_ s: String) -> [Int] {
var answer = [Int]()
var lastIndex = [Character: Int]() // 문자별 마지막 등장 인덱스 저장
for (index, chr) in s.enumerated() {
if let prevIndex = lastIndex[chr] {
answer.append(index - prevIndex) // 이전 위치와 현재 위치 차이 저장
} else {
answer.append(-1) // 처음 등장하는 문자
}
lastIndex[chr] = index // 마지막 등장 위치 갱신
}
return answer
}
