[Swift] [8일차] 영어 끝말 잇기

·2024년 12월 14일
0

SwiftAlgorithm

목록 보기
10/105

programmer-영어끝말잇기

고려사항

  1. 같은 요소 나왔을때를 대비해서 배열에 담아주기
  2. 첫번째는 그냥 담아주기 위한 continue적용
  3. 저장배열의 마지막 단어의 마지막문자(last) 와 현재(value)의 first 비교

초기 풀이

import Foundation

func solution(_ n: Int, _ words: [String]) -> [Int] {
    var numOfTurn = 0
    var numOfCycle = 0
    var beforeWord: [String] = []
    for (idx, value) in words.enumerated() {
        if idx == 0 {
            beforeWord.append(value)
            continue
        }
        if beforeWord.contains(value) { // 이미 나왔던 단어면 실패 !
            let tmp = (idx + 1) % n
            numOfTurn = tmp == 0 ? n : tmp
            numOfCycle = tmp + ((idx + 1) / n)
            break
        }
        if beforeWord.last?.last != value.first {
            let tmp = (idx + 1) % n
            numOfTurn = tmp == 0 ? n : tmp
            numOfCycle = tmp + ((idx + 1) / n)
            break
        }
        beforeWord.append(value)
    }

    return [numOfTurn, numOfCycle]
}

채점결과 (으악)

정확성: 45.0
합계: 45.0 / 100.0

반타작정도가 났다. 어떤부분이 빠졌을지 한 번 더 훑어봤다.

반례를 참고하니

INPUT : 3, ["aba","aba","baa"]
EXPECTATION : [2,1]
내코드 출력 : [2,2]

그니까 이게 numOfCycle계산식이 문제였던 것이다.
현재는 numOfCycle = tmp + ((idx + 1) / n) 로 되어있는데 좀 이상하긴했다.
현재 턴의 사람이 몇 번째로 말하는지를 알아내는 것이니까 일단 차례대로 한번 써봤다.

간단 예시

피그마로 세상허접한 자료를 만들어봤다

다음과같은 idx와 상관관계가 있는것을보고 idx에 싸이클 수는 사람 수만큼 지났을때 카운팅 되는 것이기 때문에, (idx/사람수)+1 로 훨씬 간결하게 변경해주었더니 해결될 수 있었다.

정답코드

import Foundation

func solution(_ n: Int, _ words: [String]) -> [Int] {
    var numOfTurn = 0
    var numOfCycle = 0
    var beforeWord: [String] = []
    for (idx, value) in words.enumerated() {
        if idx == 0 {
            beforeWord.append(value)
            continue
        }
        if beforeWord.contains(value) { // 이미 나왔던 단어면 실패 !
            let tmp = (idx + 1) % n
            numOfTurn = tmp == 0 ? n : tmp
            numOfCycle = (idx / n) + 1
            break
        }
        if beforeWord.last?.last != value.first {
            let tmp = (idx + 1) % n
            numOfTurn = tmp == 0 ? n : tmp
            numOfCycle = (idx / n) + 1
            break
        }
        beforeWord.append(value)
    }
    return [numOfTurn, numOfCycle]
}

채점 결과

정확성: 100.0
합계: 100.0 / 100.0

개선작업

아무리봐도 현재 코드가 너무 번잡하다
1. 일단 코드가 중복되는 부분을 해소했다.

if beforeWord.contains(value) || beforeWord.last?.last != value.first { // 이미 나왔던 단어면 실패 and 끝말잇기 실패
            let tmp = (idx + 1) % n
            numOfTurn = tmp == 0 ? n : tmp
            numOfCycle = (idx / n) + 1
            break
        }
  1. numOfTurn 로직 수정
    쓸데없이 길던 로직을 이렇게 깔끔하게 바꿀 수 있었다. numOfTurn = (idx%n)+1
let tmp = (idx + 1) % n
numOfTurn = tmp == 0 ? n : tmp  -> X
numOfTurn = (idx%n)+1   ->  개선안
  1. idx==0 보다는 더 직관성이 높게 isEmpty를 활용해주었다.
if beforeWords.isEmpty {
            beforeWords.append(word)
            continue
        }
  1. 별도의 변수를 스지않고 바로 return 하면서 훨씬 간결한 코드가 될 수 있게 수정하였다.

최종 코드

import Foundation

func solution(_ n: Int, _ words: [String]) -> [Int] {
    var beforeWords: [String] = []

    for (idx, word) in words.enumerated() {
        if beforeWords.isEmpty {
            beforeWords.append(word)
            continue
        }
        if beforeWords.contains(word) || beforeWords.last!.last != word.first {
            let player = (idx % n) + 1
            let turn = (idx / n) + 1
            return [player, turn]
        }
        beforeWords.append(word)
    }
    return [0, 0]
}

느낀점

  1. 동일하게 continue를 통해서 반복문 skip할 수 있는구나를 알았고,
  2. Optional 끼리 비교했을때 의도대로 잘 출력되는 것을 활용해볼 수 있었다. (강제 언래핑안해도 괜찮은 경우 - isLast, isFirst 비교)
  3. includes처럼 contains로 원소를 찾아줄 수 있었다.
  4. 더 개선하려면 find하는데에 드는 시간을 상수시간으로 바꿀 수 있게 SET으로 데이터구조를 정의해도 괜찮을 것 같다는 생각을 했다.
profile
기억보단 기록을

0개의 댓글