프로그래머스 스쿨의 코딩테스트 연습문제를 풀어 제출해 정답을 맞춘 후 다른 사람의 풀이를 확인하는데...
충격적으로 명료한 어떤 사람의 풀이가 나의 장황한 풀이와 너무 대비가 되었다...
아래의 댓글이 나의 충격을 대신 말해주고 있었다.
내가 풀이한 문제
https://school.programmers.co.kr/learn/courses/30/lessons/133499
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
나는 아래와 같이 생각했다.
- Loop 1. babbling 에 저장된 각 string 에 대하여:
- Loop 2. 2, 3글자 단위로 발음 가능한지 확인
- 확인할 글자가 더 이상 남지 않았으면 발음 가능. Exit Loop
- 1글자만 남았으면 발음 불가능. Exit Loop
- 첫 2글자가 유효한 발음인지 체크
- 유효 조건 : 발음할 수 있는지 && 마지막 발음과 다른지
--> substr(2) 으로 해당 2글자를 제외한 스트링에 대해 다시 Loop
- 유효하지 않으며, 마지막 2글자였다면 발음 불가, Exit Loop - 첫 3글자도 동일하게 체크
- 유효하지 않았으면 발음 불가 Exit Loop
- Loop 2. 2, 3글자 단위로 발음 가능한지 확인
지금까지 코딩테스트 연습문제를 풀며 관찰한 나의 습관? 같은 게 있다면...
스트링이나 컨테이너를 순환하며 '유효한가' 체크할 때, 판단을 최대한 빨리 하고 반복문을 빠져나오게 코드를 쓰는 습관이 있는 것 같다.
(최대한 일찍 loop 를 빠져나올 수 있도록 하는 것에 신경을 쓰는 습관이랄까...? 조건문 체크를 몇 차례 더 하더라도...)
(...코드도 성질 급한 나의 성미를 반영하나보다...)
아무튼 위의 로직을 아래와 같이 코드로 작성했다.
#include <string>
#include <vector>
using namespace std;
int solution(vector<string> babbling) {
int answer = 0;
for (string s : babbling) {
string temp = s;
string last = ""; // 마지막으로 일치한 발음
bool flag = false; // 발음 가능 여부
while (true) {
// 모든 글자가 유효했다면 발음 가능 - Set Flag & Exit Loop
if (temp.empty()) {
flag = true;
break;
}
// 1 글자 남았으면 발음 불가 - Exit Loop
if (temp.length() == 1) break;
// 첫 2글자와 비교
string FirstTwo = temp.substr(0, 2);
// 마지막 발음과 같으면 발음 불가 - Exit Loop
if (FirstTwo == last) break;
// 발음할 수 있는지 체크
if (FirstTwo == "ye") {
temp = temp.substr(2); // 확인된 2글자 제외
last = "ye"; // 마지막 일치한 발음 업데이트
continue;
}
else if (FirstTwo == "ma") {
temp = temp.substr(2);
last = "ma";
continue;
}
// 마지막 2글자를 확인했다면 발음 불가 - Exit Loop
if (temp.length() == 2) break;
// 첫 3글자와 비교
string FirstThree = temp.substr(0, 3);
// 위와 동일
if (FirstThree == last) break;
if (FirstThree == "aya") {
temp = temp.substr(3);
last = "aya";
continue;
} else if (FirstThree == "woo") {
temp = temp.substr(3);
last = "woo";
continue;
}
// 전부 일치하지 않았음
break;
}
// 발음 가능 flag 확인하여 카운트 증가
if (flag) answer++;
}
return answer;
}
딱 보기에도 장황하다...
다른 사람의 풀이
여느 때처럼 다른 사람의 풀이와 비교하기 위해 확인하는데, 충격적으로 명료하다!
#include <string>
#include <vector>
using namespace std;
int solution(vector<string> babbling) {
int answer = 0;
for(int i; i < babbling.size(); i++)
{
string temp1="";
string temp2="";
for(char c : babbling[i])
{
temp1+=c; // 발음 가능한지 확인할 스트링에 현재 character 추가
// 발음 가능한 경우
if(temp1 == "aya"||temp1 == "ye"||temp1 == "woo"||temp1 == "ma")
{
// 마지막 발음과 동일한 경우 발음 불가 --> exit loop
if(temp2 == temp1) break;
// 마지막 일치한 발음 저장
temp2=temp1;
// 테스트할 스트링 비움
temp1="";
}
}
// 마지막 발음과 동일하여 반복문을 빠져나오면,
// temp1 에 character 가 추가된 상태로 반복문을 빠져나오므로
// temp1 이 비었을 때만 유효한 발음
if(temp1.size()==0) answer++;
}
return answer;
}
글자 단위로 체크하기 때문에 조건 체크가 적고 코드 자체가 간단 명료하다.
- nested loop 안에서 조건체크가 1~2회 있다.
- 무조건 글자 수만큼 character 추가와 조건 체크를 실행한다.
비교해보자면, 내 코드는
- nested loop 안에 조건 체크가 9회 있다.
- 2~3글자씩 advance하며, 발음 불가가 판단되자마자 반복문을 빠져나온다.
만일 테스트할 스트링이 100글자라면,
내 코드는 안쪽 반복문을 best case 1번, worst case 50번 (yemayemayema... --> 2글자씩 50번) 수행하고,
위 코드는 안쪽 반복문을 무조건 100번 수행한다.
그래서 테스트 케이스 결과를 비교하고 싶어졌다. 뭐가 더 빠른지...
근소한 차이이긴 하지만, 2번과 4번 케이스 (0.02 vs 0.01) 를 제외하고 모든 케이스에서 내 코드가 더 짧은 시간이 걸린다.
최대로 차이 나는 케이스들은
0.03 vs 0.08
0.02 vs 0.07
스트링의 길이가 길어질 수록 차이가 더 나게 되지 않을까 생각한다.
무엇이 달랐을까?
나는 유효 케이스 스트링이 2 혹은 3글자라는 점에서 착안하여 코드를 작성했다는 것이 근본적인 차이였던 것 같다.
그래서 나의 코드는 이 연습문제에서 제시한 발음들에 한정된 풀이이고, 저 사람의 풀이는 어떤 발음이 오든 상관없이 유효한 풀이인 것이다.
만약 문제가 조금 달라졌다면, 나는 저런 풀이를 생각할 수 있었을까?
2~3글자라는 공통점이 없었다면 아마 한글자씩 체크하려고 하지 않았을까 생각한다.
물론 유효한 스트링이 아니라면 최대한 일찍 loop 를 벗어나는 방법을 고민했겠지...
그래서...글쎄...내 코드가 마냥 쓰레기가 아니었을 수도 있겠다는 생각을 했다...
'언리얼_엔진_게임개발_공부 > 알고리즘&자료구조' 카테고리의 다른 글
코드카타 - 문제에서 시키는 대로 하는 것에서 멈추지 마!!! (0) | 2025.02.05 |
---|---|
[코드카타] 재귀함수 / 꼬리 재귀 / 꼬리 호출 최적화 TCO (1) | 2025.01.22 |
[코드카타] 재귀함수로 문제 풀다가 실수한 것 정리 ㅠㅠ (0) | 2025.01.08 |
[자료구조] Queue - FIFO (First In First Out) 자료 구조 / Deque 조금 더 알아보기 (0) | 2025.01.03 |
[자료구조] 스택 Stack - LIFO(Last In First Out) / 벡터와 비교?! (0) | 2025.01.02 |