Neoself의 기술 블로그

알고리즘 지식 정리(10월 15일)[프로그래머스 레벨 1] 본문

개발지식 정리/알고리즘

알고리즘 지식 정리(10월 15일)[프로그래머스 레벨 1]

Neoself 2024. 10. 15. 16:09

이상한 문자 만들기

func solution(_ s:String) -> String {
    var ans:String = ""
    var id = 0
    
    for ch in s {
        if ch == " " {
            ans.append(ch)
            id = 0
        } else {
            if id%2==0 {
                ans.append(ch.uppercased())
            } else {
                ans.append(ch.lowercased())
            }
            id+=1
        }
    }
    return ans
}

단어마다 짝수 및 홀수 번째인지를 구분하는 것이였기 때문에, id값을 공백이 나올 경우 0으로 초기화하는 로직을 추가해주었고, 공백이 아닐 경우에 id값을 1씩 늘리면서, 대문자 및 소문자 추가 로직을 구현하였다.

 

삼총사

func solution(_ number:[Int]) -> Int {
    var ans = 0
    for i in 0..<number.count {
        for j in i+1..<number.count {
            for k in j+1..<number.count{
                if number[i]+number[j]+number[k] == 0 { ans+=1 }
            }
        }
    }
    return ans
}

3중 for문을 써야할 순간이 있다는 것을 깨닫게 해준 문제... 그래도 같은 학생을 중복해서 확인하는 경우를 없애고자 j와 k의 순회 범위를 각각 i+1과 j+1로 줄였기에 시간초과가 발생하지 않았던 것이 아닐까 한다.

 

시저암호

func siger(_ s:String, _ n:Int) ->String  {
    let alpha = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
    return s.map { $0==" " ? " " : $0.isLowercase ?
        alpha[(alpha.firstIndex(of: String($0))! + n)%alpha.count] :
        alpha[(alpha.firstIndex(of: String($0).lowercased())! + n)%alpha.count].uppercased()
    }.joined()
}

알파벳으로 이루어진 배열을 생성한 후에, 공백인지, 아닐 경우 소문자인지 여부로 3가지 상황을 분기하여 반환값을 다르게 처리하였다. 이때 n이 커서 인덱스 값이 범위를 벗어나는 케이스를 방지하고자 나머지 연산자를 사용하였다.

아래는 같은 문제의 다른 사람의 답변인데, 예술작품에 가까워서 같이 올린다..

func siger(_ s:String, _ n:Int) ->String  {
	let alphabets = "abcdefghijklmnopqrstuvwxyz".map { $0 }
    return String(s.map {
        guard let index = alphabets.firstIndex(of: Character($0.lowercased())) else { return $0 }
        let letter = alphabets[(index + n) % alphabets.count]
        return $0.isUppercase ? Character(letter.uppercased()) : letter
    })
}

간단히 알파벳순으로 나열된 String값을 map 함수를 통해 array로 생성해주었고, guard문을 통해 공백일 경우를 대응하였으며, String을 감싸는 것으로 String 타입 배열을 단일 String으로 다시 합쳤다.

 

가장 가까운 같은 글자

func nearestSameString(_ s:String) -> [Int] {
    var ans:[Int] = []
    let arr = s.reversed().map{$0}
    for i in 0..<arr.count {
        var cnt = -1
        for j in i+1..<arr.count {
            if arr[j]==arr[i] {
                cnt = j-i
                break
            }
        }
        ans.append(cnt)
    }
    return ans.reversed()
}

자신보다 이전에 있는 글자들로부터 offset을 구하는 것이기 때문에, for문에서 범위를 쉽게 명시하고자 먼저 reversed함수로 순서를 뒤집어주었습니다 그 이후로, 이중 for 문을 통해 이전 값들 중 같은 문자가 있을 경우 id값 간의 차를 cnt 변수에 할당시키고, 없을 경우 기본값 -1을 유지시킨 후, ans 배열에 추가하는 식으로 구조를 구성했습니다.

 

숫자 문자열과 영단어

func numAndEng(_ s:String) -> Int {
    var ans = s
    let tupleArr = [(0,"zero"),(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five"),(6,"six"),(7,"seven"),(8,"eight"),(9,"nine")]
    
    for tuple in tupleArr {
        while true{
            if let range = ans.range(of: tuple.1) {
                ans.replaceSubrange(range, with: String(tuple.0))
            } else {
                break
            }
        }
    }
    return Int(ans)!
}

숫자와 영어의 쌍으로 이루어진 튜플을 생성해준 후에, 각 튜플마다 주어진 인자값에 영단어가 있는지 확인한 후, 포함되어있을 경우 String.range(of: String) 함수를 통해 기준 영어String이 위치한 범위 객체를 생성한 후, replaceSubrange(Range,with: String) 함수를 통해 앞서 생성한 범위를 String 타입으로 변경한 숫자로 대체하였습니다. 이때 주어진 인자값에 같은 숫자에 대한 영단어가 2개 이상 있는 경우도 있기 때문에, 영단어가 없을때까지 replace작업을 계속하도록 하였습니다.

 

다른사람의 답변을 보니 range 객체를 별도로 생성하지 않고, String.replacingOccurences(of:String,with:String)으로도 해결가능한것을 알 수 있었습니다...

func solution(_ s:String) -> Int {
	let arr = ["zero","one","two","three","four","five","six","seven","eight","nine"]
    var str = s
    for i in 0..<arr.count {
        str = str.replacingOccurrences(of: arr[i], with: String(i))
    }
    return Int(str)!
}

 

감사합니다.