Programmers) Lv2 [2020카카오공채] 문자열 압축
출처: https://programmers.co.kr/learn/courses/30/lessons/60057
분류: Lv2 문자열
접근방식
문자열의 길이 N의 절반 이상으로 자르면 압축할 수가 없습니다.
주의 할 개념은 이정도 나머지는 구현이 핵심입니다.
문자열을 다룰 수 있고, 아래 예시와 같이 문자열과 관련된 다양한 작업을 할 수 있는지 파악
- 문자열 자르기
- 부분 문자열 얻기
- 문자열 비교하기
- 문자열 길이 얻기
Swift 는 문자열 다루기가 상대적으로 까다로운데 자유자재로 사용하려면 역시 많은 연습이 필요하겠습니다 😥
해결방법
1 ~ N/2 까지 잘라가며 압축 문자열의 길이가 가장 작은 값을 찾아냅니다.
앞에서부터 압축 문자열의 길이로 잘라내면서 중복을 카운트합니다.
카운트가 1이면 중복을 카운트 없이 부분 문자열을 result 에 추가시키고
1 보다 크면 카운트를 앞에 붙여줍니다.
일일이 분기처리를 하기 싫어서 처음에 카운트가 "1" 이여도 일단 다 붙이고
이후에 1을 제거하는 방식도 생각했었는데
이렇게 하면 1000 과 같이 10 이상의 수의 1도 잘라버릴 수가 있습니다 😇
func solution(_ s:String) -> Int {
var resultCount = s.count
if s.count == 1 { return 1 }
for idx in 1...s.count/2 {
var result = ""
var indiceStr = ""
var cnt = 1
var str = s
while str.count >= idx {
let range = str.startIndex..<str.index(str.startIndex, offsetBy: idx)
if indiceStr == str[range] {
cnt += 1
} else {
if cnt == 1 {
result += "\(indiceStr)"
} else {
result += "\(cnt)\(indiceStr)"
}
indiceStr = String(str[range])
cnt = 1
}
str.removeFirst(idx)
}
if cnt == 1 {
result += "\(indiceStr)\(str)"
} else {
result += "\(cnt)\(indiceStr)\(str)"
}
if resultCount > result.count { resultCount = result.count }
}
return resultCount
}
개선된 코드
swift에는 기본적으로 문자열을 특정 길이로 자르는 함수는 제공하지 않습니다.
이 부분을 구현하는 부분 때문에 코드가 복잡해질 수 있는데,
문자열을 자르는 부분을 extension으로 처리해주면 보다 깔끔하게 처리할 수 있습니다.
extension String {
func split(by length: Int) -> [String] {
var resultString = [String]()
var string = self
while string.count >= length {
let range = string.startIndex..<string.index(string.startIndex, offsetBy: length)
resultString.append(String(string[range]))
string.removeFirst(length)
}
if !string.isEmpty { resultString.append(string) }
return resultString
}
}
func solution(_ s:String) -> Int {
if s.count == 1 { return 1 }
var resultCount = s.count
for idx in 1...s.count/2 {
let truncatedString = s.split(by: idx)
var duplicatedStr = ""
var dupCnt = 1
var result = ""
for str in truncatedString {
if str == duplicatedStr {
dupCnt += 1
} else {
if dupCnt == 1 {
result += duplicatedStr
} else {
result += "\(dupCnt)\(duplicatedStr)"
}
duplicatedStr = str
dupCnt = 1
}
//print(str, duplicatedStr, dupCnt, result)
}
if dupCnt > 1 {
result += "\(dupCnt)\(duplicatedStr)"
} else {
result += "\(duplicatedStr)"
}
//print(truncatedString, idx, result)
if resultCount > result.count { resultCount = result.count}
}
return resultCount
여전히 1을 분기처리 하는 부분이 두 번이나 사용되서
깔끔해 보이지 않아 맘에들지 않네요.. 더 좋은 방법이 있을까요 ㅠ-ㅠ
배운점
간단한 문제인데 꽤나 오랜 시간이 걸렸다.
문자열은 거의 빼놓지 않고 한 문제씩은 꼭 나오는 데 확실히 연습해서 시간을 단축하자.
역시 코드는 네이밍이 정말 중요하다..
문자열을 다룰 때는 subString이 많이 사용되기 때문에 str, s, 이런 식으로 사용하면
내 코드에 내가 빠져 허우적 허우적....
너무 줄이지 말고 깔끔하고 명확한 네이밍을 하자.
이름을 줄이지 말고 코드를 줄이자 😭😭
extension을 적극적으로 활용하면 더 가독성 높고 깔끔한 코드를 완성시킬 수가 있다.