ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [level2]조이스틱 - swift 풀이
    알고리즘/프로그래머스 2021. 4. 20. 03:16

    문제 

    https://programmers.co.kr/learn/courses/30/lessons/42860

     

    코딩테스트 연습 - 조이스틱

    조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA 조이스틱을 각 방향으로 움직이면 아래와 같습니다. ▲ - 다

    programmers.co.kr

     

    이 문제는 역시나 안일하게 생각했다가 큰 코 다친 문제였다. 예시로 나와있지 않은 테스트케이스 찾는게 아직도 어렵다.. 

    처음에 단순하게 앞에서부터 순서대로 보면서 다음 타겟을 찾고, 거기서 위/아래냐 좌/우냐만 검사해서 풀었더니 

     

    이런 결과가 나왔다 🥲

     

    XAAAAAAAYZ 와 같은 경우나 BAAAAIAAAAAAE 의 경우에는 탐색 방향이 앞으로 혹은 뒤로 가기도 한다. 

     

    예1) XAAAAAAAYZ

    0(X) -> 9(Z) -> 8(Y) => 좌우 이동 2번 

    * 노란색: 왼쪽으로 가는 구간 

     

    예2) BAAAAIAAAAAAE

    0(B) -> 12(E) ->  5(I) => 좌우 이동 7번

    * 노란색: 왼쪽으로 가는 구간

    * 초록색: 오른쪽으로 가는 구간 

     

    위의 경우를 고려하려다 보니까 꽤나 어려웠는데 결론적으로는 그리디이기 때문에 현재 위치에서

    앞으로 갈 때와 뒤로 갈 때 중 더 짧은 이동거리로 가면 된다. 

     

    나의 풀이 

     

    1️⃣다른 문자의 인덱스 저장

    for i in 0..<nameArray.count {
    	if nameArray[i] != stringArray[i] {
        	targets.append(i)
        }
    }

    우선 초기 문자열과 인자로 들어온 name 값을 배열로 만든 뒤 서로 다른 문자가 있는 인덱스를 targets 배열에 저장해 주었다. 

     

    2️⃣앞 뒤 타겟까지의 거리 중 작은 값 선택하기 (좌우 이동 계산)

    var forwardDistance = targets[forwardIndex] - targets[current]
    var backwardDistance = targets[current] - targets[backwardIndex]
    
    if targetCount == 0 {
    	forwardDistance = targets[0] - 0
        backwardDistance = 0 - targets[backwardIndex]
        forwardIndex = 0
    }
            
    if forwardDistance < 0 {
    	forwardDistance += nameArray.count
    }
            
    if backwardDistance < 0 {
    	backwardDistance += nameArray.count
    }
            
    answer += min(forwardDistance, backwardDistance)

    그 다음은 바꿔야하는 문자열이 다 바뀔 때까지 while 문을 이용하여 targets 배열 인덱스에 해당하는 문자들을 바꿔준다. 

    현재 위치에서부터 앞의 타겟과 뒤로 타켓으로 가는 거리 중 짧은 거리로 이동할 것인데, 맨 처음 예외처리를 해주는 것이 좀 까다로웠다.

    맨 처음엔 항상 위치가 0번에 있기 때문에 그 부분은 따로 거리 계산을 해주었다. 

    또한 앞 뒤로 이동할 때 한 바퀴를 돌아가는 경우 거리 계산시 음수가 될 수 있기 때문에 그런 경우에는 전체 길이만큼을 더해주었다. 

     

    if forwardDistance <= backwardDistance {
    	targetIndex = targets[forwardIndex]
        current = forwardIndex
    } else {
    	targetIndex = targets[backwardIndex]
        current = backwardIndex
     }

    앞 뒤 방향이 정해졌다면 문자 배열에서 바꿀 타겟 인덱스를 저장하고, 현재 타겟에서의 위치를 업데이트한다. 

     

    3️⃣문자 바꿔주기 (상하 이동 계산)

    let a = UnicodeScalar("A").value
    let z = UnicodeScalar("Z").value
    
    if nameArray[targetIndex] != stringArray[targetIndex] {
    	let value = UnicodeScalar(nameArray[targetIndex])!.value
        let forAlpha = Int(value - a)
        let backAlpha = Int(z - value + 1)    
        
        answer += min(forAlpha, backAlpha)
               
        stringArray[targetIndex] = nameArray[targetIndex]
        targetCount += 1
        done.append(current)
    }

    상하 이동은 아스키코드를 이용하여 마찬가지로 위로 올릴 때와 아래로 내릴 때를 비교해서 더 짧은 이동수로 더해준다. 

    편하게 쓰려고 a와 z의 값은 미리 저장해 두었다. 

     

    여기서 중요! 해당 타겟을 바꿨더라도 타겟 배열의 인덱스를 사용했기 때문에 타겟 배열은 그대로 두고

    대신, 완료한 타겟의 인덱스를 done 배열에 담아 타겟 인덱스를 구할 때 done에 없는 타겟 인덱스만 가져오도록 하였다. 

     

    후기 

    일단 풀리긴 했지만,, 코드가 깔끔하지 못하고 특히 예외처리 부분이 구구절절해서😭마음에 많이 걸린다. 

    그리고 아직 미흡해서 저 테스트 케이스 자체를 처음엔 발견하지 못했다. 

    갈길이 멀지만 그래도 조금씩 생각(?)을 해가면서 문제를 풀려고 노력하고 있다🔥

     

    전체 코드

    https://github.com/A-by-alimelon/PS-with-Swift/blob/master/Programmers/%EC%A1%B0%EC%9D%B4%EC%8A%A4%ED%8B%B1.swift

     

    A-by-alimelon/PS-with-Swift

    Swift5로 알고리즘 문제 풀이. Contribute to A-by-alimelon/PS-with-Swift development by creating an account on GitHub.

    github.com

     

    '알고리즘 > 프로그래머스' 카테고리의 다른 글

    [level2]튜플 - swift 풀이  (0) 2021.04.29

    댓글

Designed by Tistory.