본문 바로가기
Xcode/Swift - Algorithm

Swift ) 프로그래머스(Lv2) - 문자열 압축 (String)

by 후르륵짭짭 2020. 8. 28.
728x90
반응형

programmers.co.kr/learn/courses/30/lessons/60057

 

코딩테스트 연습 - 문자열 압축

데이터 처리 전문가가 되고 싶은 어피치는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다. 최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문자

programmers.co.kr

안녕하세요. 후르륵짭짭 입니다.

이 문제를 풀면서,,,, 왜 코딩 테스트 인데,,, 깔끔하게 해결 하려 했지?? 라는 생각을 많이 했습니다.

굳이 깔끔하게 풀지 않아도 되는데,,,,, 

그래서 오히려 시간이 더 걸렸던거 같습니다. 

(코딩 테스트는 빨리 풀어야하는데,,,,, 참 눈물 납니다 ㅠㅠ)

 

** 나의 코드 **

func solution(_ s:String) -> Int {
    
    let last = s.count / 2
    
    var current = 1
    let arrayOfs = Array(s)
    var answer = 1001
    
   while current <= last {
                
    let left = arrayOfs.count % current
    var string = ""
    var index = 0
    var cnt = 1
    
    while index < arrayOfs.count - left {
        
        let jump = index+current
        
        let word = arrayOfs[index..<jump]
        
        index = jump
        
        if jump + current > arrayOfs.count - left {
            
            string += makeString(cnt, String(word))
            break
            
        }
    
        let next = arrayOfs[jump..<jump+current]
        
        if word != next {
            string += makeString(cnt, String(word))
            cnt = 0
        }
        cnt += 1
        
    }
    
    if index < arrayOfs.count {
        string += String(arrayOfs[index..<arrayOfs.count])
    }
    
    //print(string)
    answer = min(answer,string.count)
    current += 1
        
    }
    
    return answer
}

func makeString(_ cnt : Int ,_ word: String) -> String{
    
    let number = cnt == 1 ? "" : String(cnt)
    return (number + word)
}

지금 부터 쫌 어려웠던 부분을 설명하도록 하겠습니다.

이 문제를 풀면서 가장 난해하고 어려웠던 부분이,,,, 동일 문자인지 체크해주는 부분이였습니다.

    while index < arrayOfs.count - left {
        
        let jump = index+current
        
        let word = arrayOfs[index..<jump]
        
        index = jump
        
        if jump + current > arrayOfs.count - left {
            
            string += makeString(cnt, String(word))
            break
            
        }
    
        let next = arrayOfs[jump..<jump+current]
        
        if word != next {
            string += makeString(cnt, String(word))
            cnt = 0
        }
        cnt += 1
        
    }

이 부분을 짜는데 가장 헷갈렸던 것은 마감처리를 어떻게 해야하는지 였습니다.

한개의 문자만 확인 한다면 어렵지 않지만,,, 만약에 aabbc 이렇게 되어 있고 두개의 문자를 확인 한다 했을 때,,,

마지막 c는 어떻게 해야하고 체크 범위는 어떻게 해줘야 좋을지 고민을 했습니다...

그러다가 문득 든 생각이 "어차피 동일 갯수만큼 이동하니깐,,, 나머지 갯수 까지만 확인 해주면 되겠다 "라고 들어서

let left = arrayOfs.count % current

arrayOfs.count - left

이렇게 해줬습니다.

 

저의 방법은 A : (현재 위치 ~ 현재위치 + 확인 단위) 와  B:(현재위치 + 확인 단위 ~ 현재위치 + 확인 단위 + 확인 단위) 가 동일한지 보는 것 입니다.

따라서 abaabc가 있다고 하고 3 단위씩 확인 한다면 aba | abc 를 확인 해주는 것 인데

만약에 A가 abc 가 되었다면 B는 out of index 오류가 발생 합니다.

따라서 예외 처리 해줘야하는데,,, 어떻게 해야할지 고민 했습니다.

        if jump + current > arrayOfs.count - left {
            
            string += makeString(cnt, String(word))
            break
            
        }

그런데 생각해 보니,,, 현재위치 + 확인 단위 + 확인 단위 가 확인 범위를 넘어간다면 더이상 확인 해줄 필요가 없었습니다.

따라서 마감 처리를 해주면 됐습니다.

 

어떻게 해보면 쉬운 문제 였는데,,,, 생각 보다 오래 생각 했습니다... (카카오도 광탈 느낌이 많이 납니다 ㅎㅎㅎ)

 

그외 여러가지 새롭게 정리 해야할 String 기법이 있어서 적어보도록 하겠습니다.

 

** PROG(Lv2) - 스킬트리 ** 

programmers.co.kr/learn/courses/30/lessons/49993

 

코딩테스트 연습 - 스킬트리

 

programmers.co.kr

** 저의 코드 ** 

더보기
func solution(_ skill:String, _ skill_trees:[String]) -> Int {
    
    var dict : [Character : Int] = [:]
    var answer : Int = 0
    for (index , element) in skill.enumerated(){
        dict[element] = index
    }
    
    let item = Array(skill)
    
    
    for mainElement in skill_trees {
        
        
        let filter = mainElement.filter { (char) -> Bool in
            
            if let _ =  dict[char] {
                return true
            }
            return false
        }
        
        if filter.isEmpty {
            answer += 1
            continue
        }
        
        for (index , element) in filter.enumerated(){
            
            if item[index] != element {
                break
            }
            
            if index+1 == filter.count {
                answer += 1
            }
            
        }
        
        
    }
    
    return answer
}

저는 일단 filter로 나눠주고 스킬트리의 순서를 지켜야하기 때문에 하나씩 확인 해주는 방식으로 해줬습니다.

하지만 이렇게 복잡하게 해줬는데,,,,

func solution2(_ skill:String, _ skill_trees:[String]) -> Int {

    func available(_ s: String, _ t: String) -> Bool {
        let alza = t.filter { s.contains($0) }
        return s.starts(with: alza)
    }

    return skill_trees.map { available(skill, $0) }.filter { $0 }.count
}

이 분도 filter로 나눠줬지만, 저 보다 훨씬 깔끔하게 contains를 활용해서 s의 요소 하나씩 확인하면서 나눠주었습니다.

(참고로 filter는 배열이면 배열로 반환 해주고 String이라면 걸러서 String으로 반환 해줍니다!!!)

그리고 처음 보는 함수가 있어서 정리 하도록 하겠습니다.

developer.apple.com/documentation/swift/string/2894028-starts

 

Apple Developer Documentation

 

developer.apple.com

Starts 는 문자A.starts(with : 문자B) 으로 사용 되는데 이는 문자B가 문자A와 동일한 순서 인지 알려주는 것 입니다.

let string  = "abada"
let test = string.filter { (char) -> Bool in
    return char == "a" ? true : false
}

var startTest = "aa"

print(test.starts(with: startTest))

startTest = "ab"

print(test.starts(with: startTest))

startTest = ""

print(test.starts(with: startTest))

//결과
true
false
true

결국 아래와 같은 코드이다.

        for (index , element) in filter.enumerated(){
            
            if item[index] != element {
                break
            }
            
            if index+1 == filter.count {
                answer += 1
            }
            
        }

 

** PROG(Lv2) - 다리를 지나는 트럭 ** 

programmers.co.kr/learn/courses/30/lessons/42583

 

코딩테스트 연습 - 다리를 지나는 트럭

트럭 여러 대가 강을 가로지르는 일 차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 트럭은 1초에 1만큼 움직이며, 다리 길이��

programmers.co.kr

** 저의 코드 **

더보기
func solution(_ priorities:[Int], _ location:Int) -> Int {
    
    var stack : [(pri : Int , location : Int)] = []
    var answer : Int = 0
    for index in 0..<priorities.count {
        stack.append((priorities[index], index))
    }
    
    while !stack.isEmpty {
        
        let topElement = stack[0].pri
        
        var isover = -1
        
        for (index, element) in stack.enumerated(){
            
            if element.pri > topElement {
                isover = index
                break
            }
            
        }
        
        if isover != -1 {
            
            var tempStack : [(pri : Int , location : Int)] = []
            
            for _ in 0..<isover{
                tempStack.append((pri: stack[0].pri, location: stack[0].location))
                stack.removeFirst()
            }
            
            stack.append(contentsOf: tempStack)
        
        }
        else{
            
            answer += 1
            
            let removedLocation = stack.removeFirst().location
            
            if removedLocation == location {
                return answer
            }
            
        }
        
//        print(isover)
//        print(stack)
//
    }
    
    return 0
}

저는 이 문제를 하나씩 더해주고 뺄 때가 되면 빼주는 식으로 풀었습니다.

쫌 비효율적으로 풀었습니다. 

그리고 이 문제를 풀 때, 더 큰 숫자가 있는지 확인 하기 위해 for 문으로 확인을 해주는데 

func solution2(_ priorities:[Int], _ location:Int) -> Int {
    var cPriorities = priorities
    var targetIndex = location

    while cPriorities.count > 0 {
        if cPriorities.contains(where: { $0 > cPriorities[0] }) {
            let first = cPriorities.removeFirst()
            cPriorities.append(first)
            targetIndex = targetIndex - 1 < 0 ? cPriorities.count - 1 : targetIndex - 1
        } else {
            if(targetIndex == 0) {
                return priorities.count - cPriorities.count + 1
            }

            cPriorities.removeFirst()
            targetIndex = targetIndex - 1
        }
    }

    return 0
}

이 분을 보면 contain(where)로 쉽게 찾아주고 있습니다.

 

확실히 이제 Lv2를 풀고 있는데,, Lv1은 쉽게 풀 수 있었던 반면,,,

Lv2 부터는 쫌 생각을 하고 시간이 더 오래 걸리는 거 같습니다 ㅠㅠ

목표는 Lv2를 30분만에 다 컷하는게 목표인데,,, 쉽지 않을 것 같습니다  

728x90
반응형

댓글