📍 카드 뭉치
코니는 영어 단어가 적힌 카드 뭉치 두 개를 선물로 받았습니다. 코니는 다음과 같은 규칙으로 카드에 적힌 단어들을 사용해 원하는 순서의 단어 배열을 만들 수 있는지 알고 싶습니다.
문자열로 이루어진 배열 cards1
, cards2
와 원하는 단어 배열 goal
이 매개변수로 주어질 때, cards1
과 cards2
에 적힌 단어들로 goal
를 만들 있다면 "Yes"를, 만들 수 없다면 "No"를 return하는 solution 함수를 완성해주세요.
cards1
의 길이, cards2
의 길이 ≤ 10cards1[i]
의 길이, cards2[i]
의 길이 ≤ 10cards1
과 cards2
에는 서로 다른 단어만 존재합니다.goal
의 길이 ≤ cards1
의 길이 + cards2
의 길이goal[i]
의 길이 ≤ 10goal
의 원소는 cards1
과 cards2
의 원소들로만 이루어져 있습니다.cards1
, cards2
, goal
의 문자열들은 모두 알파벳 소문자로만 이루어져 있습니다.문제를 풀기위해 풀이를 생각한 흐름은 다음과 같다.
.*aaa.*bbb.*
이다.class Solution {
fun solution(cards1: Array<String>, cards2: Array<String>, goal: Array<String>): String {
val cards1Regex = cards1.joinToString(".*", ".*", ".*").toRegex()
val cards2Regex = cards2.joinToString(".*", ".*", ".*").toRegex()
val strGoal = goal.joinToString("")
return if (cards1Regex.matches(strGoal) && cards2Regex.matches(strGoal)) "Yes" else "No"
}
}
결과는 실패했다. 내가 간과했던 점은 모든 cards 내의 원소들을 사용할 필요가 없다는 것이고, 주어지는 goal은 이미 cards1과 cards2의 원소들로만 구성되어 있다는 것이었다.
정규식으로도 풀.. 수 있었을까? 확실한 건 지금 나의 지식으로는 정규식을 계속 붙잡고 있는건 시간 낭비라는 것이다. 그래서 다른 방법을 생각해보았다. 이번에는 다음과 같은 흐름으로 풀어보았다.
class Solution {
fun solution(cards1: Array<String>, cards2: Array<String>, goal: Array<String>): String {
var cards1Idx = goal.filter { cards1.contains(it)}.map { cards1.indexOf(it) }
var cards2Idx = goal.filter { cards2.contains(it)}.map { cards2.indexOf(it) }
return if ((cards1Idx == cards1Idx.sorted()) && (cards2Idx == cards2Idx.sorted())) "Yes" else "No"
}
}
그렇다. 이번에도 실패했다. 내가 또!! 간과했던 점은 중간에 건너뛰는 카드가 있으면 안된다는 것이다! 위의 코드로는 건너뛰는 카드가 있더라도 Yes를 반환한다. 아오 문제를 제대로 좀 읽고 풀자.
세 번째에는 다음과 같이 생각하면서 풀이했다.
class Solution {
fun solution(cards1: Array<String>, cards2: Array<String>, goal: Array<String>): String {
var (c1, c2) = Pair(cards1, cards2)
for (word in goal) {
if (!c1.isEmpty() && c1[0] == word) c1 = c1.drop(1).toTypedArray()
else if (!c2.isEmpty() && c2[0] == word) c2 = c2.drop(1).toTypedArray()
else return "No"
}
return "Yes"
}
}
나는 잦은 형변환을 싫어한다. 뭔가뭔가.. 성능에 이슈가 있을 것 같이 생겼기 때문이다. 그래서 성공은 했지만 이번에도 꾸역승의 느낌이 있어서 다른 사람들의 풀이를 더 열심히 찾아봤다.
세 번째 풀이의 방식으로 푼 사람들이 많았다. 다만, 배열의 첫 원소를 날려버리는 게 아닌 인덱스를 하나씩 올려가며 푼 풀이가 있었다.
class Solution {
fun solution(cards1: Array<String>, cards2: Array<String>, goal: Array<String>): String {
var idx1 = 0
var idx2 = 0
goal.forEach {
if (idx1 < cards1.size && it == cards1[idx1]) idx1++
else if (idx2 < cards2.size && it == cards2[idx2]) idx2++
else return "No"
}
return "Yes"
}
}
이렇게 하면 배열로 바꾸지 않아도 돼서 더 좋은 방식이라 생각했다.
분명 문제를 제대로 읽었다 생각했는데 풀이를 하다보면 하나씩 빼먹는 것 같다. 이제까지는 어떻게 풀어야 하지?를 먼저 생각하기 보다 냅다 코드 먼저 작성해서 풀었었는데, 이번 문제는 생각을 먼저하고 풀게 되더라.. 아마 코드로 반환값 확인해가면서 푸는 방식에 익숙해져 있어서 생각 먼저 하다보니 여러가지 조건을 놓친게 아닐까하는 생각이 든다. 내일도 만약 이런 문제가 있다면 꼼꼼히! 꼭!! 꼼꼼히!!! 풀이해야겠다.