Swift 알고리즘공부 01.LongestPassword

dodiforth·2022년 5월 13일
0

코딜리티

목록 보기
1/2

튜토리얼 지옥에빠진 나의 동영상하나 없이 처음해본 문제풀이...

들어가기에 앞서

이 문제는 Codility Developer Training에 있는 https://app.codility.com/programmers/trainings/1/longest_password/
Easy단계에 해당하는 LongestPassword라는 문제풀이 이다.
사실 처음 해보는 문제풀이라 상당히 맨붕이 심하기도했고, 특히 더더욱이나
혼자 풀어보려고 별안간의 발악을 해서 문제 시간을 안정해두고 풀다보니 하루에 대략 1시간씩 투자해서 3-4일 걸린것 같다...


첫 문제풀이다보니 풀다가 안되거나 새로 아이디어가 떠오르면 저렇게 새로운 파일로 다시 밑바닥부터 다시 풀었다...해괴망측하다

이 글은 문제풀이해설 보다는 나의 나름의 의식흐름(?)을 남겨두려고 적은것이니, 해답만 보시려는 분들은 바로 건너뛰기를 추천드린다.. (아 참고로 Codility에서는 Swift3-4버전인가의 문법만됬다.<-근데 필자는 Swift5로 연습을하고 해서 막상 또 문제풀이때 좀 끙끙되었다.)

문제는 다음과 같다.

당신은 은행계좌를 위해 비밀번호를 설정해야한다. 그러나 비밀번호에는 세가지의 준수해야하는 사항들이 있다 :
1. 오직 alphanumerical characters로만 이루어져 있을것(a-z, A-Z, 0-9)
2. letter들은 짝수여야한다.
3. number들은 홀수여야 한다.

연속된 N개의 캐릭터들로 이루어진 String S가 주어졌을때 이걸 "단어"들로 쪼갤수 있으며, 공백을 지울수 있다. 목표는 단어들중 제일긴 유효한 단어(비밀번호)를 고를수 있어야한다.
여백의 수가 K개라면 string S안의 단어들은 K+1개 일것임을 유추할수 있다.

예를들자면 c가 주어졌을때, 여기엔 5개의 단어(비밀번호)가 있으며 3개는 유효한 비밀번호이다 : "5","a0A","pass007".
그러므로 제일 긴 비밀번호는 "pass007"이며 이것의 길이는 7이다.
"?"는 alphanumerical character가 아니고 "test"의 number는 짝수이므로(0) "test"와 "?xy1"는 유효하지 않은 비밀번호임을 유의하라.

다음과 같은 function을 써라 :

public func solution(_ S : inout String) -> Int

N개의 character로 이루어진, 비어있지않은 string S이 주어졌을때, 유요한 비밀번호 중 가장 긴 비밀번호의 글자길이를 리턴하는 함수를 적어야한다. 만일 조건에 충족하는 글자가 없다면 -1을 리턴해야한다.

예를 들자면, 위에서 설명한대로 S = "test 5 a0A pass007 ?xy1"가 주어졌을때 7을 리턴해야한다.

참고로 :

  • N은 1...200 사이의 양의 정수이다.
  • string S는 오직 출력가능한 ASCII 글자와 공백으로 이루어져있다.

문제의 풀이는, "정확성"에 초점을둔다. 풀이코드의 성능/효율에는 크게 집중하지 말것.

1. 마음만은 순조로운 출발(?)


부끄럽고, 한숨나온다...
지금보면 저 갈곳잃은 for loop와 굳이 alphanumerical을 확인하기위함을 따로 바깥에까지 빼서 왜 그랬을까 하겠지만, 처음엔 그저 하나의 string을 작은 string들의 array로 만들려고 거기서 비교하는데만 혈안되서 그랬다...

그리고 나중에 가서야 비로소 이 전체적인 function은 결국 Int를 반환해야함을 깨닫고,
for loop을 만들고 array의 각각 조건에 충족하는 비밀번호를 숫자로 전환해서
다시 새로운 array안에 ....

그러다가 이게 굉장히 비효율적이고 어디서부턴가 잘못되었다고 생각해 엎었다...

PS : func longestPassword의 리턴타입이 배열인 이유는 아직 테스트중이라 내가 의도하는대로 새로운 배열안에 각 비밀번호들의 길이를 저장하고 싶어서 그랬다.

2. 그러다가 stackoverflow에서 찾은 영감을 준 코드.

어디서부턴가 잘못되었다고 느꼈을때 쯔음, character들의 타입체크를 위한 인스턴스를 찾으려고 구글링하던 중 찾게된 stackoverflow 답변이었다.

3. 요시 감잡았어 !

stackflow에서 본 코드를 보고 토대를 잡아나가기로 결정했다.
처음에 받을 string을 " "로 쪼개 배열에다가 여러개의 string으로 저장하고
ex)

"test 5 a0A pass007 ?xy1"
-> ["test", "5", "a0A", "pass007", "?xy1"]

그렇게 생성한 배열을 변수에 할당하고

let arrayOfPassword = ["test", "5", "a0A", "pass007", "?xy1"]

그 다음부터는 stackoverflow에서 본 코드를 가져와
배열 각각의 string을 while루프로 돌려서 타입체크 인스턴스를 거치게끔한다음
아래의 변수들의 값 변동 따라 문제조건에 충족하는지를 돌려보는것이었다.

var numberOfDigits = 0
var numberOfLetters = 0
var numberOfSymbols = 0

근데 말이 쉽지...처음 제머리로만 코드를 작성해 내려가다보니, 뜻하는대로 되질않자 어디서 기억날듯한 말듯한 문법으로 var validCheckPassword? 같은 해괴한것도 만들었다..

4. 그렇게 거의 자포자기한 마음으로 2보 후퇴...


필자도 안다 문제풀이는 function하나만 구현해야한다는것...
하지만, 이쯤되었을땐 문제풀이는 그냥 자포자기 상태였고, 그래도 뭔가 기능적인 면만이라도 만들어보자 싶어서 만들려고 function을 쪼개고있었다.
func countElements -> 인풋으로 String을 받아 안에 글자, 숫자, 특수문자의 수를 계산한다.
func longestPassword -> 하나의 String을 받으면 단어별로 쪼개 String의 배열로 만든다.
func sortOutPassword -> 오직 조건에 부합하는 단어들만 배열로 재정립한다...
그런데 아무래도 이러면 죽도 밥도 못될것 같고, 이렇게 포기하기에는 조금 아깝기도했다.
그리고 스스로 이렇게 복잡할 정도로 코드를 짤 필요가 없다고 느꼈고, 특히나 전체적인
함수의 흐름보다는 인풋으로 들어가는 string의 element하나 하나에 너무 집착하는 느낌이 들었다... 결국엔 "조건에부합" + "그 중 제일긴문자의 길이" + "리턴의 타입은 결국 Int"
라고 천천히 간단명료하게 생각하기로 했다.

5. 그렇게 완성된 최종본...

string자체에 큰 집착보다는 character를 중심으로 if로 식별하여 숫자변수의 변화로 함수를 짜기로 마음먹으니 조금더 생각이 좀 더 명확해졌다.
거기다가 python으로 누군가 짜놓은 코드를 구글링하다 찾았는데,
혹시나해서 swift로 이식해보니 위와 같은 코드가 나오게되었다.

이번 알고리즘은 정말 튜토리얼 지옥에서 처음으로 벗어난 기분이랄까...
항상 튜토리얼이나 동영상만 따라하다 그런 것 하나없이 백지로 시작하니, 막막하기도 했지만 조금씩 코드를 치고, 구글링을 하다보니 내 스스로 찾아가고 공부한다는게 어떤 느낌인지 감이 잡혔다. 심지어 문법강의만 백만번은 본것같은데, 막상 동영상없이 혼자 처보려니 와...구글링이 없었다면 아마 거기서 엄청 헤맸을것 같다.

6. 어이쿠 문제와 내 IDE의 Siwft 버전이 다르네;;;

나의 오만한 머리는 코딜리티에서 검토하는 Swift버전이 내가 문제풀이를한 Swift와 버전이 다르단것을 조금도 예상하지 못했구나... 덕분에 다시 구글링으로 뒤져가며 조금만 다시 새로짰다.

알골리즘 문제풀이는 지루하고, 의미없으며, 오히려 이런 것 보다는 좀더 현업에 뛰어들수있는 코드를 공부하는게 낫다고 생각했었다. 하지만 이번 경험으로 확실히 코딩은 튜토리얼보다는 직접 처보는게 나으며, 알고리즘 문제풀이 역시 코딩 사고력에 큰 큰 도움을 줌을 느낀것같다. 특히나 이번기회로 튜토리얼 지옥에서 한발자국이라도 멀어진것 같아 기쁘다.

그런데 이제 첫 문제 풀이네 ㅎ....

profile
일단 개발자가 되고봅시다!

0개의 댓글