숫자로 이루어진 문자열 t
와 p
가 주어질 때, t
에서 p
와 길이가 같은 부분문자열 중에서, 이 부분문자열이 나타내는 수가 p
가 나타내는 수보다 작거나 같은 것이 나오는 횟수를 return하는 함수 solution을 완성하세요.
예를 들어, t
="3141592"이고 p
="271" 인 경우, t
의 길이가 3인 부분 문자열은 314, 141, 415, 159, 592입니다. 이 문자열이 나타내는 수 중 271보다 작거나 같은 수는 141, 159 2개 입니다.
제한사항
p
의 길이 ≤ 18p
의 길이 ≤ t
의 길이 ≤ 10,000t
와 p
는 숫자로만 이루어진 문자열이며, 0으로 시작하지 않습니다.입출력 예
t | p | result |
---|---|---|
"3141592" | "271" | 2 |
"500220839878" | "7" | 8 |
"10203" | "15" | 3 |
입출력 예 설명
입출력 예 #1
본문과 같습니다.
입출력 예 #2
p
의 길이가 1이므로 t
의 부분문자열은 "5", "0", 0", "2", "2", "0", "8", "3", "9", "8", "7", "8"이며 이중 7보다 작거나 같은 숫자는 "5", "0", "0", "2", "2", "0", "3", "7" 이렇게 8개가 있습니다.
입출력 예 #3
p
의 길이가 2이므로 t
의 부분문자열은 "10", "02", "20", "03"이며, 이중 15보다 작거나 같은 숫자는 "10", "02", "03" 이렇게 3개입니다. "02"와 "03"은 각각 2, 3에 해당한다는 점에 주의하세요
이미 풀었던 문제지만, 초기화 후 다시 풀어보았다.
나의 풀이
풀이1)
import Foundation
func solution(_ t:String, _ p:String) -> Int {
var t = t
var count = 0
while t.count >= p.count {
if Int(t.prefix(p.count))! <= Int(p)! {
count += 1
}
t.removeFirst()
}
return count
}
전에 풀었던 풀이는 완전 탐색으로 배열의 처음부터 끝까지 모든 배열을 훑으며 p의 길이만큼 숫자를 꺼내서 확인한 후 t의 젤 앞의 값을 없애는 것이다.
테스트 1 〉 통과 (36.58ms, 16.1MB)
테스트 2 〉 통과 (706.98ms, 16.1MB)
테스트 3 〉 통과 (768.78ms, 16.4MB)
테스트 4 〉 통과 (192.76ms, 16.5MB)
테스트 5 〉 통과 (30.34ms, 16.6MB)
테스트 6 〉 통과 (966.31ms, 16.5MB)
테스트 7 〉 통과 (834.34ms, 16.6MB)
테스트 8 〉 통과 (159.02ms, 16.4MB)
테스트 9 〉 통과 (12.57ms, 16.3MB)
테스트 10 〉 통과 (1.46ms, 16.2MB)
테스트 11 〉 통과 (232.04ms, 16.3MB)
테스트 12 〉 통과 (900.32ms, 16.5MB)
테스트 13 〉 통과 (354.77ms, 16.4MB)
테스트 14 〉 통과 (208.24ms, 16.4MB)
테스트 15 〉 통과 (254.65ms, 16.3MB)
테스트 16 〉 통과 (153.59ms, 16.5MB)
테스트 17 〉 통과 (485.94ms, 16.4MB)
테스트 18 〉 통과 (696.91ms, 16.4MB)
테스트 19 〉 통과 (129.26ms, 16.6MB)
테스트 20 〉 통과 (27.79ms, 16.3MB)
테스트 21 〉 통과 (0.13ms, 16.2MB)
테스트 22 〉 통과 (2.56ms, 16.3MB)
테스트 23 〉 통과 (15.33ms, 16.2MB)
테스트 24 〉 통과 (0.17ms, 16.4MB)
테스트 25 〉 통과 (0.47ms, 16.3MB)
테스트 26 〉 통과 (0.27ms, 16.5MB)
테스트 27 〉 통과 (0.27ms, 16.2MB)
테스트 28 〉 통과 (0.20ms, 16.3MB)
테스트 29 〉 통과 (0.35ms, 16.3MB)
테스트 30 〉 통과 (13.07ms, 16.2MB)
테스트 31 〉 통과 (0.07ms, 16.5MB)
테스트 32 〉 통과 (0.09ms, 16.3MB)
테스트 33 〉 통과 (0.09ms, 16.4MB)
테스트 34 〉 통과 (0.11ms, 16.3MB)
테스트 35 〉 통과 (0.13ms, 16.1MB)
테스트 36 〉 통과 (0.15ms, 16.4MB)
테스트 37 〉 통과 (0.10ms, 16.2MB)
테스트 38 〉 통과 (0.15ms, 16.5MB)
풀이2)
import Foundation
func solution(_ t:String, _ p:String) -> Int {
return (0...(t.count-p.count)).filter{Int(t[String.Index(encodedOffset: $0)...String.Index(encodedOffset: $0+p.count-1)])! <= Int(p)!}.count
}
remove를 사용하지 않고, 문자열의 서브스트립트를 이용하여 풀었다.
더 깔끔해지고, 풀이 과정도 더 빨라진 것을 확인할 수 있었다.
사실 filter보다 for-in이 더 빠르다는 것을 알지만, count가 있어서 더 편하게 풀 수 있을 것 같아서 filter로 풀었다.
테스트 1 〉 통과 (9.42ms, 16.5MB)
테스트 2 〉 통과 (19.27ms, 16.5MB)
테스트 3 〉 통과 (14.06ms, 16.6MB)
테스트 4 〉 통과 (10.94ms, 16.5MB)
테스트 5 〉 통과 (7.81ms, 16.5MB)
테스트 6 〉 통과 (15.50ms, 16.7MB)
테스트 7 〉 통과 (62.08ms, 16.7MB)
테스트 8 〉 통과 (8.94ms, 16.5MB)
테스트 9 〉 통과 (4.10ms, 16.6MB)
테스트 10 〉 통과 (0.60ms, 16.4MB)
테스트 11 〉 통과 (16.79ms, 16.6MB)
테스트 12 〉 통과 (42.25ms, 16.5MB)
테스트 13 〉 통과 (23.79ms, 16.6MB)
테스트 14 〉 통과 (14.78ms, 16.7MB)
테스트 15 〉 통과 (12.73ms, 16.3MB)
테스트 16 〉 통과 (12.12ms, 16.6MB)
테스트 17 〉 통과 (44.44ms, 16.6MB)
테스트 18 〉 통과 (18.15ms, 16.7MB)
테스트 19 〉 통과 (9.36ms, 16.3MB)
테스트 20 〉 통과 (3.78ms, 16.3MB)
테스트 21 〉 통과 (0.19ms, 16.3MB)
테스트 22 〉 통과 (1.81ms, 16.5MB)
테스트 23 〉 통과 (4.49ms, 16.5MB)
테스트 24 〉 통과 (0.23ms, 16.3MB)
테스트 25 〉 통과 (0.76ms, 16.4MB)
테스트 26 〉 통과 (0.43ms, 16.6MB)
테스트 27 〉 통과 (0.55ms, 16.6MB)
테스트 28 〉 통과 (0.41ms, 16.6MB)
테스트 29 〉 통과 (0.34ms, 16.5MB)
테스트 30 〉 통과 (5.84ms, 16.6MB)
테스트 31 〉 통과 (0.14ms, 16.5MB)
테스트 32 〉 통과 (0.17ms, 16.5MB)
테스트 33 〉 통과 (0.18ms, 16.2MB)
테스트 34 〉 통과 (0.19ms, 16.3MB)
테스트 35 〉 통과 (0.21ms, 16.5MB)
테스트 36 〉 통과 (0.22ms, 16.4MB)
테스트 37 〉 통과 (0.16ms, 16.3MB)
테스트 38 〉 통과 (0.25ms, 16.6MB)
다른 사람 풀이
import Foundation
func solution(_ t:String, _ p:String) -> Int {
var answer = 0
for i in 0 ... t.count - p.count {
let subStr = t.dropFirst(i).prefix(p.count)
if let comp = Int(subStr), let val = Int(p) {
answer += comp - val <= 0 ? 1 : 0
}
}
return answer
}
이 풀이는 배열의 값을 없애고, 앞의 3을 꺼내어 비교하는 것을 dropFirst와 prefix를 사용하여 구현했다.
if let 문을 사용하여 Int()?를 벗겨내어서 비교하였다.
좋은 방법인듯 했지만, dropFirst를 하는 과정에서 좀 더 많은 실행 시간이 소요된다.
명함 지갑을 만드는 회사에서 지갑의 크기를 정하려고 합니다. 다양한 모양과 크기의 명함들을 모두 수납할 수 있으면서, 작아서 들고 다니기 편한 지갑을 만들어야 합니다. 이러한 요건을 만족하는 지갑을 만들기 위해 디자인팀은 모든 명함의 가로 길이와 세로 길이를 조사했습니다.
아래 표는 4가지 명함의 가로 길이와 세로 길이를 나타냅니다.
명함 번호 | 가로 길이 | 세로 길이 |
---|---|---|
1 | 60 | 50 |
2 | 30 | 70 |
3 | 60 | 30 |
4 | 80 | 40 |
가장 긴 가로 길이와 세로 길이가 각각 80, 70이기 때문에 80(가로) x 70(세로) 크기의 지갑을 만들면 모든 명함들을 수납할 수 있습니다. 하지만 2번 명함을 가로로 눕혀 수납한다면 80(가로) x 50(세로) 크기의 지갑으로 모든 명함들을 수납할 수 있습니다. 이때의 지갑 크기는 4000(=80 x 50)입니다.
모든 명함의 가로 길이와 세로 길이를 나타내는 2차원 배열 sizes가 매개변수로 주어집니다. 모든 명함을 수납할 수 있는 가장 작은 지갑을 만들 때, 지갑의 크기를 return 하도록 solution 함수를 완성해주세요.
제한사항
입출력 예
sizes | result |
---|---|
[[60, 50], [30, 70], [60, 30], [80, 40]] | 4000 |
[[10, 7], [12, 3], [8, 15], [14, 7], [5, 15]] | 120 |
[[14, 4], [19, 6], [6, 16], [18, 7], [7, 11]] | 133 |
입출력 예 설명
입출력 예 #1
문제 예시와 같습니다.
입출력 예 #2
명함들을 적절히 회전시켜 겹쳤을 때, 3번째 명함(가로: 8, 세로: 15)이 다른 모든 명함보다 크기가 큽니다. 따라서 지갑의 크기는 3번째 명함의 크기와 같으며, 120(=8 x 15)을 return 합니다.
입출력 예 #3
명함들을 적절히 회전시켜 겹쳤을 때, 모든 명함을 포함하는 가장 작은 지갑의 크기는 133(=19 x 7)입니다.
나의 풀이
import Foundation
func solution(_ sizes:[[Int]]) -> Int {
var w = [Int](), h = [Int]()
for i in sizes {
w.append(i.max()!)
h.append(i.min()!)
}
return w.max()! * h.max()!
}
배열을 이용해서 각각의 높이와 넓이의 최솟값 최댓값을 분리시켜 해당 배열의 최댓값을 곱해주었다.
다른 사람 풀이
import Foundation
func solution(_ sizes:[[Int]]) -> Int {
var maxNum = 0
var minNum = 0
for size in sizes {
maxNum = max(maxNum, size.max()!)
minNum = max(minNum, size.min()!)
}
return maxNum * minNum
}
배열을 사용하지 않고, 변수를 활용해 해당 사이즈들의 큰 수의 최댓값, 작은 수의 최댓값을 구하였다.
어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.
제한 조건
입출력 예
s | n | result |
---|---|---|
"AB" | 1 | "BC" |
"z" | 1 | "a" |
"a B z" | 4 | "e F d" |
나의 풀이
func solution(_ s:String, _ n:Int) -> String {
var answer = ""
for char in s{
if char.isLetter{
if char.isUppercase {
let scal = UnicodeScalar(String(char))!.value + UInt32(n)
answer += scal > 90 ? "\(UnicodeScalar(scal - UInt32(26))!)" : "\(UnicodeScalar(scal)!)"
} else {
let scal = UnicodeScalar(String(char))!.value + UInt32(n)
answer += scal > 122 ? "\(UnicodeScalar(scal - UInt32(26))!)" : "\(UnicodeScalar(scal)!)"
}
}else {
answer += " "
}
}
return answer
}
UnicodeScalar를 이용해서 푸는 문제였는데, 시간도 많이 걸리고 어려웠다.
유니코드를 사용하는 방법을 까먹어 전에 다른 문제에서 유니코드를 사용한 것을 참고하여 풀었다.
아직 문자열을 유니코드를 바꾸는 방법과 Int를 유니코드로 바꾸는 방법을 정확히 알지 못한 것 같다.
내일 정리하도록 하자!
다른 사람 풀이
func solution(_ s:String, _ n:Int) -> String {
return s.utf8.map {
var code = Int($0)
switch code {
case 65...90:
code = (code + n - 65) % 26 + 65
case 97...122:
code = (code + n - 97) % 26 + 97
default:
break
}
return String(UnicodeScalar(code)!)
}.joined()
}
이렇게 사용할 수도 있구나..
쩐다..
코드가 진짜 깔끔하다.
func solution(_ 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
})
}
와우.. 진짜 깔끔하다.
코드가 군더더기 없어..
코드 많이 짜보신 분이 푼 문제인거 같다.
-> 유니코드 사용법 정리하기