정규 표현식을 배웠으니 문제에 활용해 볼 수 있게 되었다. 마침 관련 문제를 몇 풀게 되어서 정리해본다.
1. Kotlin 문제
1-1. 문제
프로그래머스에 있는 문제 '옹알이 (2)'를 풀어보았다.
[문제]
- 문제 설명
머쓱이는 태어난 지 11개월 된 조카를 돌보고 있습니다. 조카는 아직 "aya", "ye', "woo", "ma" 네 가지 발음과 네 가지 발음을 조합해서 만들 수 있는 발음밖에 하지 못하고 연속해서 같은 발음을 하는 것을 어려워합니다. 문자열 배열 babbling이 매개변수로 주어질 때, 머쓱이의 조카가 발음할 수 있는 단어의 개수를 return하도록 solution함수를 완성해주세요.
- 제한사항
- 1 ≤ babbling의 길이 ≤ 100
- 1 ≤ babbling[i]의 길이 ≤ 30
- 문자열은 알파벳 소문자로만 이루어져있습니다.
- 입출력 예시
babbling | result |
["aya", "yee", "u", "maa"] | 1 |
["ayaye", "uuu", "yeye", "yemawoo", "ayaayaa"] | 2 |
1-2. 내가 처음 해보았던 풀이
내가 처음에 이 문제를 푼 방법은 다음과 같다. for문으로 babbling에 있는 요소들 하나하나를 검사하는 방법을 사용했다. 먼저 for문안에 str이라는 변수를 하나 선언하고 거기에 babbling에 있는 요소 하나에 해당하는 문자열을 집어넣었다. 그 다음 이 str이라는 문자열에서 "aya", "ye", "woo", "ma"에 해당하는 문자열을 빈 문자열("")로 치환했을때 str이 빈 문자열이 된다면 발음할 수 있는 단어라고 할 수 있을것이다 라는게 기본 아이디어였다.
그렇지만 "ayaaya", "yeye", "woowoo", "mama"는 들어갈 수 없었기 때문에 먼저 처리를 해줘야했다. str에 이 문자열들이 포함되어있다면 그 문자열에 해당하는 반복은 continue로 건너뛰도록 만들어줬다.
그리고 "aya", "ye", "woo", "ma"에 해당하는 문자열을 replace로 빈 문자열("")로 치환하는 것이 기본 아이디어였는데 잘 생각해보니 이렇게 하면 여러 예외적인 경우가 발생한다. 만약 "yayae" 같은 문자열이 있다고 해보자. 여기서 중간에있는 "aya"를 ""이렇게 바꾸고 나면 "ye"가 남게되고 "ye"를 ""로 바꾸고 나면 빈 문자열이 되어버린다. 발음할 수 없는 문자열임에도 빈 문자열이 되어버리는 것이다.
그렇게 때문에 ""대신에 " "(스페이스)로 치환해주었다.(알파벳 소문자가 아닌 다른 문자로 바꿔도 상관 없을 것이다.) "yayae"를 다시 예로 들면 "aya"가 " "로 바뀌게 되니 "y e"가 되게 된다. 이 상태에서는 "ye"에 해당하는 부분을 " "(스페이스)로 치환할 수 없게 된다. 이렇게 하면 예외적인 경우들을 없앨 수 있다.
그러고 난 뒤 str에 포함되게 된 " "(스페이스)들은 마지막에 모조리 빈 문자열로 바꿔주면 된다.
마지막 부분에는 str이 빈문자열이라면 answer의 값이 1 증가하도록 코드를 작성해주었다. 아래가 해당 답안이다.
class Solution {
fun solution(babbling: Array<String>): Int {
var answer: Int = 0
for (item in babbling) {
var str = item
if ("ayaaya" in str) continue
if ("yeye" in str) continue
if ("woowoo" in str) continue
if ("mama" in str) continue
str = str.replace("aya", " ")
str = str.replace("ye", " ")
str = str.replace("woo", " ")
str = str.replace("ma", " ")
str = str.replace(" ", "")
if (str == "") answer++
}
return answer
}
}
1-3. 정규 표현식을 이용한 다른 풀이
문제를 풀고나서 보니 정규 표현식을 이용한 한 줄 짜리 다른 사람의 풀이를 볼 수 있었다. 하지만 이 문제를 처음 풀었을 당시에는 정규 표현식을 몰라서 이해를 못하고 넘어갔었다. 이제 그 풀이를 참고해서 다시 답안을 작성해 보았다.
차근차근 문제의 조건을 생각하며 정규 표현식을 작성해 보았다.
먼저 "aya", "ye", "woo", "ma"만 전체 식에 하나 이상 들어가 있어야 한다. 따라서 "(aya|ye|woo|ma)+" 이렇게 작성해보았다.
그 다음 "ayaaya", "yeye", "woowoo", "mama"는 들어갈 수 없다. 따라서 "aya"뒤에 "aya"가 못 나오도록 부정형 전방탐색(?!aya)을 추가해주면 된다. 나머지 3개의 문자열에 대해서도 마찬가지로 해주면 된다.
따라서 "(aya(?!aya)|ye(?!ye)|woo(?!woo)|ma(?!ma))+"가 된다.
혹시 모를 오류를 방지하기 위에 정규식을 Kotlin 코드로 작성할 때에는 삼중 따옴표로 집어 넣었다.
class Solution {
fun solution(babbling: Array<String>) = babbling.count { ("""(aya(?!aya)|ye(?!ye)|woo(?!woo)|ma(?!ma))+""".toRegex()).matches(it) }
}
정상적으로 답안으로 제출 되었고 내가 기존에 썼던 코드보다 훨씬 실행속도도 개선되었다. 새로 배운 것을 적절히 사용해 볼 수 있어서 좋았다.
2. SQL 문제
2-1. 문제
leetcode에 있는 '1517.Find Users With Valie E-Mails' 문제를 풀어보았다.
[문제]
- 테이블 <Users>
Column Name (칼럼 명) | Type(자료형) |
user_id | int (정수형) |
name | varchar(가변길이 문자열) |
varchar(가변길이 문자열) |
user_id is the primary key (column with unique values) for this table.
user_id는 이 테이블의 기본 키(고유 값을 가진 열)입니다.
Write a solution to find the users who have valid emails.
A valid e-mail has a prefix name and a domain where:
- The prefix name is a string that may contain letters(upper or lower case), digits, underscore '_', period '.', and/or dash '-'. The prefix name must start with a letter.
- The domain is '@leetcode.com'
Return the result table in any order.
번역
유효한 이메일 주소를 가진 사용자를 찾는 솔루션을 작성하세요.
유효한 이메일은 다음과 같은 접두사 이름(보통 아이디에 해당)과 도메인을 가집니다:
- 접두사 이름은 문자(대문자 또는 소문자), 숫자, 밑줄 '_', 마침표 '.', 대시 '-'로 이루어진 문자열입니다. 접두사 이름은 반드시 문자로 시작해야 합니다.
- 도메인은 '@leetcode.com' 입니다.
순서와 관계없이 결과 테이블을 반환하세요
2-2. 풀이
매일 SQL 복습 겸 문제풀이를 하고 있었는데 마침 정규식을 활용해볼 수 있는 문제를 풀어볼 수 있게 되어 좋았다.
SQL에서 정규식을 사용하는 법을 간단하게 먼저 알아봐야 했다. where 절과 함께 regexp를 이용하면 되었다. 어떤 정규식을 포함하지 않는 값들을 골라내려면 not을 붙이면 된다.
WHERE mail REGEXP '^.+aBc$'
WHERE mail not REGEXP '^.+aBc$'
이제 문제로 돌아가서 차근차근 정규식을 작성하면 된다.
먼저 맨 앞에는 문자(알파벳)이 와야한다. 따라서 '^[A-Za-z]'가 먼저 와야된다.
그 다음에는 문자(대문자 또는 소문자), 숫자, 밑줄 '_', 마침표 '.', 대시 '-'가 0개 이상 오면 된다.
따라서 '^[A-Za-z][A-Za-z0-9_.-]'가 된다.
그 다음 도메인(@leetcode.com)을 입력해주고 그것으로 끝나야하기 때문에 앵커를 넣어주면 된다. .의 경우에는 모든 문자를 나타내는 의미가 있기 때문에 이스케이프 시켜줘야 한다. 두 가지 방법으로 가능하다.
'^[A-Za-z][A-Za-z0-9_.-]*@leetcode\\.com$'
'^[A-Za-z][A-Za-z0-9_.-]*@leetcode[.]com$'
둘 중 하나를 집어넣어 답안을 완성하면 된다.
SELECT *
FROM Users
WHERE mail REGEXP '^[A-Za-z][A-Za-z0-9_.-]*@leetcode\\.com$'
역시 답안이 통과되었다. 정규식을 이용하여 쉽게 문제를 해결할 수 있었다.
3. 오늘 알게 된 것
- 배운 정규식을 문제풀이에 직접 적용해 보았다. 잘 되는 걸 확인해서 기분이 좋았다.
- 배우고 적용해 보는 것에서 큰 재미를 느낄 수 있었다. 앞으로도 열심히 새로운 걸 배우고 적용해보는 연습을 해봐야겠다.
'오늘 배운 것' 카테고리의 다른 글
24-04-06 MySQL LIMIT, OFFSET (0) | 2024.04.06 |
---|---|
24-04-05 SQL Rank, Dense_Rank, Row_Number (0) | 2024.04.05 |
24-04-03 Kotlin에서 정규 표현식 사용하기 (3) (0) | 2024.04.03 |
24-04-02 Kotlin에서 정규 표현식 사용하기 (2) (0) | 2024.04.02 |
24-04-01 Kotlin에서 정규 표현식 사용하기 (0) | 2024.04.01 |