<문제 설명>
어느 한 게임에서 사용되는 아이템들은 업그레이드가 가능합니다.
'ITEM_A'->'ITEM_B'와 같이 업그레이드가 가능할 때
'ITEM_A'를 'ITEM_B' 의 PARENT 아이템,
PARENT 아이템이 없는 아이템을 ROOT 아이템이라고 합니다.

(중략)....

 

<문제>
아이템의 희귀도가 'RARE'인 아이템들의 모든 다음 업그레이드 아이템의 아이템 ID(ITEM_ID), 아이템 명(ITEM_NAME), 아이템의 희귀도(RARITY)를 출력하는 SQL 문을 작성해 주세요. 이때 결과는 아이템 ID를 기준으로 내림차순 정렬해 주세요.

 


 

 

처음에 대충 생각하고 접근했더니 원하는 정답을 얻어내기 어려웠던 문제입니다!

 

다시 정신을 집중하고, RIGHT 조인과 서브쿼리를 이용해서 문제를 바로 해결했어요.

 

제가 풀이한 방법을 설명해 보겠습니다.



https://school.programmers.co.kr/learn/courses/30/lessons/273711

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 


 

 

먼저 아이템의 희귀도가 'RARE'인 아이템들을 뽑아내서 시각화해 봅니다.

SELECT * FROM ITEM_INFO WHERE RARITY = 'RARE'

 

우리는 이 4개의 아이템들의 다음 업그레이드 아이템을 찾아야 합니다. 이를 위해서는 ITEM_TREE 테이블을 확인해 보아야 해요.

 

 

ITEM_TREE 테이블을 보고 직관적으로 이해하기가 어려웠어요. 딱 봤을 때 구조가 한눈에 들어오지 않았습니다. (쉽게 보이시는 분이 계시다면.... 멋지십니다! 따봉!)

 

 

그래서 이렇게 간단히 그래프를 그려 봤더니 쉽게 이해가 되었습니다. 우리가 구한 RARE 아이템은 0, 1, 3, 4였어요. 이 아이템들의 다음 업그레이드 아이템은 (0으로부터) 1, 2번 아이템 + (2로부터) 3, 4번 아이템 => 총 1, 2, 3, 4번 아이템이 해당됩니다. 이해가 되셨을까요?

 

그렇다면 일반화된 쿼리문으로 작성하려면 어떻게 해볼 수 있을까요? 우선 우리가 구한 RARE 아이템 0, 1, 3, 4가 부모가 되는 아이템, 즉 0, 1, 3, 4의 자식 아이템을 찾아야 해요. 이를 위해서 ITEM_TREE 테이블의 PARENT_ITEM_ID와, ITEM_INFO 테이블의 ITEM_ID가 동일한 부분을 연결해 주면 됩니다.

 

SELECT * FROM ITEM_INFO I
	RIGHT JOIN ITEM_TREE T
	ON I.ITEM_ID = T.PARENT_ITEM_ID
WHERE RARITY = 'RARE'

 

1) ITEM_INFO 테이블에서 RARITY가 'RARE'에 해당하는 아이템 중에서,

2) 그 아이템이 ITEM_TREE 테이블에 있는 어떤 놈의 PARENT_ITEM_ID에 해당한다면,

3) 그 놈들을 모두 뽑아내봐요.

 

라고 명령한 것과 같습니다. 그럼 위와 같이 결과를 시각화할 수 있는데요. 여기서 우리에게 필요한 것은 무엇일까요?

 

 

우리한테 필요한 것은 저기 저 1, 2, 3, 4번 아이템 번호밖에 없어요. T 테이블(ITEM_TREE)의 ITEM_ID만 뽑아내 주면 됩니다. SELECT 뒤에만 간단하게 바꾸어 줘 봅시다.

 

SELECT T.ITEM_ID FROM ITEM_INFO I
        RIGHT JOIN ITEM_TREE T
        ON I.ITEM_ID = T.PARENT_ITEM_ID
WHERE RARITY = 'RARE'

 

 

이제 우리가 원하는 아이디를 뽑아냈으니, 이 테이블을 서브쿼리로 기존의 ITEM_INFO 테이블과 조인해 주면 끝입니다!

 

SELECT X.ITEM_ID, I.ITEM_NAME, I.RARITY
FROM (SELECT T.ITEM_ID
      FROM ITEM_INFO I
      RIGHT JOIN ITEM_TREE T
      ON I.ITEM_ID = T.PARENT_ITEM_ID
      WHERE RARITY = 'RARE') X
JOIN ITEM_INFO I ON X.ITEM_ID = I.ITEM_ID
ORDER BY ITEM_ID DESC

 

서브쿼리는 X로 이름을 지정해 주었습니다. X의 아이템 아이디와 ITEM_INFO 테이블(I)의 아이템 아이디가 같다면 아이디/이름/레어리티를 셀렉하여 프린트하고, 아이템 아이디를 기준으로 내림차순 하여 정렬하도록 지정했습니다.

 

채점 결과 100.0

 

코드 통과, 정답입니다 :)

 

이해가 안 되는 부분이 있으시다면 댓글 달아주세요!

 

서브쿼리와 RIGHT JOIN 연습을 할 수 있었던 좋은 문제였습니다.

 

 

 

 

주제 : 심장과 혈관 의학 분야에서의 인공지능과 데이터과학

일시 : 2024년 4월 4일 (목) 20:00 - 21:10

강사 : 미국 Mayo Clinic 이은정

 

 

서론

4월 4일 목요일 Zoom을 이용한 실시간 화상 온라인 방식으로 진행된 이은정 강사님의 <심장과 혈관 의학 분야에서의 인공지능과 데이터과학> 세미나에 참여했습니다. 이은정 강사님께서는 서울대학교에서 석박사 과정을 마치신 뒤 미국에서 가장 큰 병원 중 하나인 Mayo Clinic에서 Senior Data Science anlayst로 계시면서 다양한 의학 인공지능 모델을 개발하고 데이터과학을 연구하고 계신 멋진 분이셨습니다. 저는 현재 고려사이버대학교에서 최대영 교수님의 빅데이터 개론 수업을 듣고 있는데, 교수님께서 본 세미나에 참가할 수 있도록 초대해 주신 덕분에 좋은 기회로 참여할 수 있었습니다.

 

제 주변에 의학 관련 분야에 종사하는 지인이나 친인척이 몇 있습니다. 그래서 저는 평소 의학 분야에도 어느 정도 관심을 가지고 있었습니다. 특히 의료 분야에서 데이터의 중요성, 인공지능의 빠른 성장에 대해서는 익히 들어본 바가 있어 큰 호기심을 가지고 있었습니다. 그러나 의료 분야는 어쩐지 진입장벽이 있다고 느껴졌어요. 어디서부터 관련 도메인 지식을 수집해 나갈지 막막했습니다. 그렇게 멀게만 느껴지던 의학 도메인에 조금 더 가까워지는 계기가 되기를 바라며 강의를 듣기 시작하였습니다.

 

본론

(1)

 

먼저 강의는 미국의 심혈관 질환에 대한 통계 자료와 분석으로 시작하였습니다. 2016년 데이터를 기준으로 미국 인구의 약 절반이 고혈압을 가지고 있는 것으로 추정되며, 2035년까지 미국 인구의 약 45%가 심장 관련 질병 가지게 될 것으로 예상된다고 하는데요. 이를 뒷받침하는 자료로 미국에서는 성인 5명 중 오직 1명만이 적정한 양의 운동을 하고, 전자담배의 사용으로 흡연률이 치솟고 있는 등 다양한 통계를 함께 볼 수 있었습니다.

 

2022년 잠깐이나마 뉴욕에서 어학연수를 했던 기억을 떠올려 보았습니다. 뉴욕에는 확실히 한국보다 다양한 체형을 가진 사람들이 있었어요. 다양한 사이즈의 체형이 용납되는 개방적이고 자유로운 사회적 분위기가 저는 참 좋았던 기억이 있습니다. 지금 돌아보니 빅 사이즈 국민들의 건강 관리가 그만큼 중요한 과제가 될 수도 있겠다는 생각이 드네요. 이렇게 미국에서는 큰 사회적 이슈가 되고 있는 심혈관 질병 진단과 관리를 위해 인공 지능이 다양하게 개발되고 활용되고 있다고 합니다.

미국에서 심혈관 질환 관련 의료 마켓에서 AI의 성장률을 확인해볼 수 있는 그래프 자료입니다.

(2) - 1

다음으로 심혈관 질환을 위한 인공지능 모델 개발을 위한 데이터 자료에 관해 말씀해 주셨습니다. AI 트레이닝, 테스팅 데이터로 활용되는 가장 대표적인 데이터 자료 두 가지는 환자 기록과 검사 결과입니다. 환자 기록으로는 몸무게, 키, 혈압, 피검사, 환자 내원시 상담 내용 등이 있습니다. 검사 결과로는 ECG라고 불리는 심전도 검사 결과, 심초음파, 혈관조영상, 망막이미지 등이 있습니다. (심혈관 질병 관련)

 

요즘은 스마트 워치로도 간단하게 심전도 측정이 가능한 세상입니다. 이렇게 스마트 워치를 활용하여 측정한 심전도 자료 역시 인공지능 개발에 활용이 되기도 한다고 합니다. 물론 병원의 전문 장비를 이용한 측정 결과랑 비교하자면 신뢰도가 많이 떨어지기 때문에, 이렇게 신뢰도가 낮은 데이터를 가지고 모델 개발을 하면 그만큼 정확도가 떨어질 수밖에 없다고 하셨습니다. 그래도 집에서 간단하게 간이 방식으로 심전도를 측정하여 문제 상황을 조금이나마 예측하고 예방할 수 있다면 큰 도움이 되겠지요. 언젠가 병원의 전문 장비만큼 실력이 짱짱한 스마트 워치가 보급될 지도 모를 일입니다.

 

망막 이미지와 목소리에 관련해 말씀해 주신 부분이 굉장히 흥미로워 기억에 남는데요. 요즘은 망막 이미지 하나만으로도 나이, 성별, 흡연여부, 혈압 비만도 등의 건강 정보를 예측을 할 수 있는 수준으로 모델 개발이 이루어져 있다고 합니다. 굉장히 신기했어요. 또 목소리를 이용하여 심장 관련 진환을 예측을 할 수 있다고도 하셨습니다. 목소리라고 하면 기관지 컨디션이나 기분 정도만 짐작해볼 수 있는게 아니냐고들 생각하지만 목소리에는 예상 외로 몸에서 발생하는 이상 신호들이 잘 반영된다고 합니다. 생각보다 예측율이 높은 편이라고 해서 정말 신기했어요. 이렇게 상식을 뛰어 넘는 재밌는 모델링 연구 작업에 저도 참여할 수 있다면 얼마나 좋을지 기대가 되었습니다. 의료 도메인에도 꾸준한 관심을 가지고 포트폴리오를 구축해 나가 봐야 겠다는 욕심이 들었어요.

 

(2) - 2

다음으로 데이터를 활용해 어떤 모델을 개발할 수 있는지에 대해 말씀해 주셨습니다. 가장 큰 연구가 이루어지고 있는 분야는 바로 질병을 예측할 수 있는 모델 개발이라고 합니다. 가격이 비싼 혈관조영상 촬영 없이 상대적으로 저렴한 심장 박동, 심초음파 검사 결과만으로 좌심방의 크기와 대동맥 판막 협착증을 예측하는 모델을 예시로 들어 주셨습니다. 초기에 잡아냈다면 미리미리 관리하여 쉽게 치료할 수 있었던 질병들을 뒤늦게 발견해서 큰 문제가 되는 경우가 많잖아요. 저희 외조모께서도 대장암을 초기에 발견하지 못해 결국 투병하시다가 2년만에 돌아가셨었거든요. 인공지능 모델을 통해 세계적으로 질병 예측의 시기가 앞당겨지고 정확성이 크게 증진될 수 있기를 바라는 마음입니다.

 

또 기존에는 상위 검사만으로 측정이 가능했던 수치들을 하위 검사로 측정 가능할 수 있도록 돕는 모델 개발에 관해서도 언급하셨습니다. 상위 검사는 검사 방법이 복잡한 대신 정확도가 높은 특징이 있습니다. 그만큼 비용이 높을 수밖에 없는데, 특히 미국의 악랄한 의료비에 대해서는 다들 잘 알고 계시지요. 대부분의 상위 검사들을 한국에서는 어렵지 않게 받을 수 있지만 미국에서는 그렇지가 못한 현실이라고 해요. 이렇게 상위 검사만으로 측정 가능했던 수치들을 하위 검사 결과로부터 예측해낼 수 있는 모델들을 개발하는 겁니다. 이게 보편화가 된다면 비용때문에 의료 서비스를 받지 못했던 사회적 약자들에게 커다란 도움이 되겠다는 생각을 했습니다. 저도 뉴욕에 있을 때 갑자기 엄청난 복통이 찾아와 응급실에 갔다가 아픈 것보다도 병원비를 걱정하느라 마음 고생을 했던 경험이 있거든요. 질 좋은 의료 서비스를 모두가 평등하게 받을 수 있는 세상을 만드는 데 저도 도움이 될 수 있으면 좋겠습니다.

 

그 밖에 인공지능 모델 개발을 위해 데이터 레이블링하는 작업에 큰 시간과 비용이 소요되는데, 이런 레이블링을 대신하는 모델을 역시 활발하게 개발이 이루어지고 있다고 알려 주셔서 흥미로웠습니다. 인공지능 모델 개발을 돕는 모델이라니! 미래에는 인공지능끼리 주르륵 체인을 이루면서 인간의 개입이 전혀 필요하지 않은 세상이 언젠가 오겠다는 귀엽고도 무서운 생각을 해 봤어요. 그 안에 나의 역할이 무언가 있기를 바랄 뿐입니다.

 

(3)

마지막으로 메이요 클리닉에서 개발하고 있는 인공지능 모델 예제를 몇가지 알려 주셨습니다. 간단히만 정리해 보겠습니다.

 

[1] 정상 심장 리듬에서 심방세동을 예측하는 모델

  • 심방세동은 간헐적으로 발생하며 특이한 증상이 없는 경우가 많아서 진단에 어려움이 많다.
  • 심방세동의 정확한 진단 및 예측을 위해서는 환자가 병원에 긴 시간 내원해야 한다. 대체로 환자가 24시간동안 몸에 리드줄을 부착하고서 수집한 데이터로 판단을 내리는 방식으로 진단이 이루어졌다고 한다.
  • 메이요 클리닉에서 보관하고 있는 18만명이 넘는 환자들의 데이터, 65만개가 넘는 ECG 기록을 가지고 단시간 측정한 정상 리듬에서도 심방세동을 예측해낼 수 있는 인공지능 모델을 개발하였다.
  • 기존의 진단이 여러 전문 인력의 수작업으로 이루어져 시간과 자원이 과하게 소모되었으나 이 과정들을 인공지능으로 대체할 수 있게 되면서 시간과 자원 비용을 크게 절약하게 되었다.

[2] 비대성 심근병증 (HCM) 분류

  • 비대성 심근병증은 심장 근육이 비정상적으로 두꺼워져 형태가 변형되고 기능이 악화되는 질환으로, 특히 미국에서는 HCM으로 돌연사하는 프로, 아마추어 운동선수가 많아서 사회적 이슈라고 한다.
  • 메이요 클리닉에서 저렴한 심장 박동 검사 결과만을 가지고 HCM을 예측할 수 있는 모델을 개발하였다. 심장 박동 검사는 비용이 저렴할 뿐만 아니라 다양한 시설에 보편화가 많이 되어 있어서 접근성이 무척 높은 하위 검사이다.
  • 테스팅 어큐러시가 0.95 - 0.97으로 무척 높았는데, 미국 뿐만 아니라 다른 여러 나라들에서도 이벨류에이팅을 해 보니 역시 높은 어큐러시 결과가 나왔다고 한다.

[3] ECG(심전도)를 이용한 좌심실 이완기능 평가

  • 좌심실의 이완 기능은 심장 기능 평가에 있어서 아주 중요한 사항이다. 좌심실 이완 시 높은 filling pressure는 다양한 심혈관 질환과 관련되는 악조건이다. 현재 미국에서 70세 이상의 노인의 70%가 불완전한 좌심실 이완 기능을 가지고 있다는 통계 결과가 있다고 한다.
  • 좌심실 이완 기능 평가는 혈관조영상으로 판단하는 것이 가장 이상적이다. 그러나 혈관조영상 촬영은 굉장히 어렵고 복잡하며 비용이 높은 상위 검사이다. 이를 대체하기 위해 심초음파 결과를 이용하는 경우가 많은데, 정확성이 매우 떨어진다고 한다.
  • 메이요 클리닉에서 ECG(심전도) 검사 결과를 통해 좌심실 이완 기능을 평가하는 인공지능을 개발하였다. 검사 결과로 Grade 1-2-3 세 단계의 등급을 매기게 되는데, 등급이 높을 수록 위험한 상태를 의미한다.

 

결론

이번 이은정 강사님의 세미나는 심혈관 질환의 예측과 진단에 데이터와 인공지능이 어떻게 활용되고 있는지 그 실제 사례를 알아볼 수 있는 무척 좋은 학습 기회였습니다. 평소 '미래에는 인공지능이 의사를 대체할 것이다!'는 무시무시한 이야기를 들어만 보았지, 실제로 병원에서 어떤 식으로 개발이 되고 활용이 되고 있는지 그 개별 사례를 알아보기가 쉽지는 않았거든요. 강사님께서 실제 사례와 경험을 토대로 강의해 주신 덕분에 앞으로 심혈관 질환 뿐만 아니라 다른 분야에서도 인공지능 적용 사례를 찾아보기가 수월해질 것 같습니다.

 

이런 의료 도메인에서의 인공지능의 개발은 질 높은 의료 서비스를 더 많은 사람들이 받을 수 있도록 돕습니다. 그만큼 사회적, 인도적으로 큰 의미가 있다고 생각해요. 과학 기술 발달의 바람직한 예라고 할 수 있겠죠. 특히 저는 초등교육에 제 20대 모두를 바쳤던 만큼 어린이와 청소년의 신체건강, 정신건강에 특히 큰 관심을 가지고 있는데요. 학생 개인정보 보호를 위해 자세한 사례를 여기에 세세히 밝힐 수는 없지만, 타고난 유전병으로 인해 자유로운 활동이 어려운 학생을 가르쳐 보았고, 신체적 장애를 가지고 있어 신체활동에 제약이 있는 학생도 가르쳐 보았고, 자폐 스펙트럼을 가지고 태어나 친구를 사귀기 어려워하는 학생도 가르쳐 보았습니다. 가정환경이 어려워 필요한 만큼 의료 서비스를 받지 못하는 친구도 있었는데 제가 도울 방법이 제한적이라 참 안타깝고 미안했었어요. 이렇게 다양한 어려움을 가지고 있는 학생들을 도울 수 있는 인공지능 모델에는 무엇이 있을지 앞으로 계속해서 고민해 보고, 관련 데이터를 찾아보고 분석해 보고자 합니다.

 

질의응답 시간에 이은정 강사님께 어린이를 대상으로 인공지능 모델을 개발해 본 경험이 있으신지 질문을 드렸었는데요. 어린이들은 신체적으로 어른과 무척이나 다르기 때문에 어른을 대상으로 개발한 모델을 어린이들에게 동일하게 적용하기는 어렵다고 하셨습니다. 따라서 영유아나 어린이를 대상으로 한 모델의 경우 성인을 대상으로 개발한 성공적인 모델을 가지고 수정 보완하여 만들어내는 경우가 많다고 하셨어요. 좋은 답변이 되었습니다. 추후에 시간을 내어 구체적인 사례를 찾아보기로 하였습니다.

 

마지막으로 이렇게 개발된 인공지능 모델이 완전히 전문인력을 대체하고 있는 상황은 아니라고 말씀을 해 주셨습니다. 의료진이 진단을 하고 판단을 내리는 데 근거가 되는 하나의 수단으로 인공지능 모델의 예측 결과를 활용하고 있다고 하셨어요. 데이터를 분석하고 모델을 개발할 줄 아는 능력 있는 데이터 사이언티스트는 이렇게 원하는 분야의 전문 인력과 협업할 수 있구나! 좋은 자극이 되었습니다. 열심히 노력해서 저 역시 이렇게 세상의 발전에 기여하고 다른 이들에게 영감이 되는 전문가가 되겠다고 다짐하며, 이번 세미나 리뷰를 마칩니다.

 

 

 

읽어주셔서 감사합니다.

 

 

 

프로그래머스의 MySQL 코딩테스트 연습문제 '노선별 평균 역 사이 거리 조회하기' 를 풀었습니다. 서브쿼리와 ORDER BY에 대해 정리해두기 좋은 문제인 것 같아 블로그 포스팅을 해 보도록 하겠습니다.

 

https://school.programmers.co.kr/learn/courses/30/lessons/284531

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

먼저, 1차로 제출한 정답코드입니다. (오답)

SELECT ROUTE, 
        CONCAT(ROUND(SUM(D_BETWEEN_DIST), 1), "km") AS TOTAL_DISTANCE,
        CONCAT(ROUND(AVG(D_BETWEEN_DIST), 2), "km") AS AVERAGE_DISTANCE
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY TOTAL_DISTANCE DESC

 

테스트 케이스는 통과했으나 정답으로 제출하면 결과가 틀리다고 나와 저를 당황스럽게 하였습니다. 무엇이 문제였을까요? 문제 조건을 다시 한 번 살펴보겠습니다.

1) 총 누계 거리와 평균 역 사이 거리의 컬럼명은 각각 TOTAL_DISTANCE, AVERAGE_DISTANCE 
2) 총 누계거리는 소수 둘째자리에서, 평균 역 사이 거리는 소수 셋째 자리에서 반올림 한 뒤 단위(km)를 함께 출력
3) 결과는 총 누계 거리를 기준으로 내림차순 정렬

 

왠지 CONCAT으로 스트링으로 만들어버린 값을 정렬하면서 3번에서 문제가 생기지 않을까 싶었어요. 그래서 1차로 제출했던 코드에서 CONCAT 함수를 제외한 전체를 서브쿼리로 사용해 보기로 했습니다. 

 

(SELECT ROUTE, 
        ROUND(SUM(D_BETWEEN_DIST), 1) AS TOTAL_DISTANCE,
        ROUND(AVG(D_BETWEEN_DIST), 2) AS AVERAGE_DISTANCE
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY TOTAL_DISTANCE DESC) BF

 

먼저 CONCAT을 빼버린 부분을 전체 ( ) 괄호로 묶어서 임시 테이블 BF로 만들어 자기참조합니다.

그럼 2차로 제출한 정답코드를 보여드리겠습니다.

SELECT BF.ROUTE,
       CONCAT(BF.TOTAL_DISTANCE, "km") AS TOTAL_DISTANCE,
       CONCAT(BF.AVERAGE_DISTANCE, "km") AS AVERAGE_DISTANCE
       
FROM (SELECT ROUTE, 
        ROUND(SUM(D_BETWEEN_DIST), 1) AS TOTAL_DISTANCE,
        ROUND(AVG(D_BETWEEN_DIST), 2) AS AVERAGE_DISTANCE
FROM SUBWAY_DISTANCE
GROUP BY ROUTE
ORDER BY TOTAL_DISTANCE DESC) BF

 

합계: 100.0 / 100.0 (정답)

 

FROM 뒤에 임시 테이블(이너 테이블) BF를 넣어 줍니다. TOTAL_DISTANCE를 기준으로 내림차순 정렬은 이미 임시 테이블 BF에서 숫자형태로 완료가 된 상태입니다. 이렇게 정렬이 완료된 임시 테이블에서 CONCAT을 이용해 "km"을 붙이고 스트링화 해주었더니 정답으로 인정이 되었습니다.

 

 

서브쿼리와 정렬에 대해 생각해볼 수 있는 좋은 문제였습니다.

 

 

 

 

 

작년에 의원면직(사직)을 한 후 꽤 긴 시간이 흘렀습니다. 이제는 전 동료가 된 교사 친구들이 SNS에 올리는 새 학기 소식을 보면 '강 건너 불구경이 따로 없구먼' 하는 표정으로 흐뭇하게 미소를 짓게 됩니다.

 

 

 

나는 준비된 상태로 사직하지 못했습니다. 이 일을 그만두고 난 뒤의 미래에 대해서 꾸준히 고민했지만 답을 알 수 없었습니다. 결국 해답을 찾지 못한 채로 의원면직을 해 버렸습니다. 용기와 치기 사이, 무모와 대담 가운데 어딘가에 있었던 결정이었습니다. 지금 돌아보면 그때 열심히 고민만 했던 게 문제였습니다.

 

 

 

이전에 글 쓴 대로, 첫 3개월은 미친 듯이 수능 공부를 했습니다. 그땐 내가 할 수 있는 게 그것밖에 없었습니다. 어떠한 분야로 진출한다는 것은, 괜찮은 대학에서 관심 있는 학과를 전공하고 관련 분야로 취직한다는 것, 그게 내가 알고 있는 전부였기 때문입니다.

 

 

 

결과적으로 나쁘지 않은 성적을 받았음에도 대학에 가지 않았습니다. 누군가는 시간을 버렸다고 말할 수도 있겠습니다. 그렇지만 그동안 잊고 살았던 고등수학과 천문학을 공부하며 내가 논리와 알고리즘을 좋아하는 사람이라는 것을 알게 되었고, 소프트웨어공학 분야로 진출하겠다는 결심을 하게 됐고, 나는 반드시 해낼 수 있다는 자기 확신을 얻었습니다. 내가 만약 실리를 따져 가면서 수능 공부를 하지 않았더라면 그런 결심을 할 수 있었을까요.

 

 

 

나는 수능 다음날부터 파이썬 기초 문법을 시작으로 본격적으로 코드를 독학하기 시작했습니다. 비전공자도 개발을 배울 수 있는 콘텐츠는 세상에 넘쳐흐르고 있었습니다. 나의 생각과 논리가 코드로 고스란히 기록에 남는 일은 짜릿했습니다.

 

 

 

그러고 보니, 내가 교사 일을 왜 좋아했는지도 다시금 돌아보게 되었습니다. 학교 현장은 학생에 관한 수많은 데이터의 정글입니다. 초등교사는 흘러 넘치는 학생들의 데이터를 수집하고 분석하고 통찰하며 학급을 이끌고 교육과정을 운영해야 합니다. 그중에서도 나는 특히 학생을 이해하는 일을 잘해서 학생과 학부모들에게 인기가 좋았습니다. 모든 일에는 원인과 결과가 있다는 나의 원칙이 있었기 때문에 가능한 일이었습니다. 어른의 시각에서 이해하기 어려울 수도 있었던 아이들의 행동들을 나는 늘 이해했습니다. 그 일이 어렵지 않았습니다. 아이들의 크고 작은 갈등해결은 생각보다 간단합니다. 데이터를 수집하고 분석하여 의미 있는 결과를 도출하는 일과 다름없어요. 내가 할 일은 별게 없습니다. 귀를 기울이고 원인과 결과를 파악한 다음 교육자, 보호자, 어른으로서 나의 생각을 뽑아내 조언합니다. 아이들은 자신의 이야기에 귀를 기울이고 이해하는 어른이 있다는 사실 하나만으로도 반성하고 성장하더라고요. 그런 아이들을 보면서 제가 오히려 배우곤 했습니다.

 

 

 

교육과정과 학습목표, 성취기준을 분석하고 창의적으로 수업을 구성하여 이끌어가는 일도 좋았습니다. 초등학교 담임에게는 학급 교육과정 운영의 자율성이 주어지는 편입니다. 나는 내 입맛대로 학급을 이끌어 나가는 일이 즐거웠습니다. 아이들의 수업 태도와 참여도를 능동적으로 관찰 평가하면서 수업을 개선하고 새로운 교수 학습 기법을 적용해 보는 등 다양한 시도를 멈추지 않았습니다. 나의 수업은 학생들 사이의 대화로 넘쳐흘렀습니다.  내가 가르친 학생들은 요즘 같은 삭막한 시대에 꼭 필요한 의사소통 역량을 조금은 배워갔을 것입니다.

 

 

 

비록 새로운 가치와 성장을 찾아 학교를 떠나게 되었으나 교사로 일하는 동안 정말 행복했어요. 말장난같이 들릴 수 있겠지만 내가 만약 학교에서 일하지 않았다면 학교를 떠날 일도 없었겠지요. 나는 도전과 실패에 대한 두려움을 떨치고 학교를 떠나기로 결정한 스스로가 이제는 자랑스러워요. 그리고 학교를 떠날 수 있도록 나에게 가르침을 준 학생들에게 고맙습니다.

 

 

 

제목에 진로를 결정했다고 썼지요. 나는 데이터 사이언스와 AI 엔지니어링 분야에 뜻을 품었습니다. 처음에는 모두가 그렇듯 웹개발을 위주로 공부를 시작했는데, 궁금한 분야를 파고 파고 파다 보니 여기까지 도착했습니다. 지금은 텐서플로우 코드와 함께 딥러닝을 공부하는 데 몰두하고 있습니다. 처음엔 이것이 외계어가 아니면 뭐란 말인가, 싶을 만큼 어렵고 막막했어요. 그런데 어려운 만큼 결국엔 이해하고 소화해 냈을 때의 쾌감은 이루 말할 수 없을 만큼 짜릿합니다. 나는 이게 정말 재밌어요. 엄청난 재능이 있는 것 같지는 않은데, 30대에는 여기에 내 모든 걸 쏟아봐도 좋겠다는 생각이 들 만큼의 열정이 있어요.

 

 

 

작년에 수능 준비를 하면서 수학 선택 과목으로 미적분을 열심히 공부했었거든요. 간당간당하게 1등급도 받았었고요. 그때 미적분을 공부해 둔 게 딥러닝을 공부하는 지금 도움이 되네요. 어떤 도전이든 나에게 손해 될 것은 없다는 것을 다시금 확인합니다.

 

 

 

또 재밌는 건, 제가 이번에 사이버대학에 편입을 했어요. 작년에 수능까지 봐 놓고서 사이버대학에 들어가다니 웃기지요? 독학으로 공부를 하다 보니 전공자들은 학부에서 어떤 것들을 배우는지 궁금했거든요. 나중에 혹시 공대 대학원에 진학해서 석사과정을 밟을 수도 있으니까 공학 학사를 따 두면 도움도 될 것 같았고요. 하지만 오프라인 대학을 다니는 기회비용을 감당하고 싶진 않았기 때문에 사이버대학교 3학년으로 편입을 했어요. 이번 학기에는 수업 4개를 듣는데, 수업 하나하나가 기대했던 것 이상으로 알차서 정말 만족하고 있습니다.

 

 

 

특히 빅데이터 개론을 들으며 학문적 기반을 다지고, 데이터와 인공지능을 다룰 때 정말 정말 중요한 통계학 수업을 들으며 부족했던 수학 지식을 보충할 수 있는 게 좋습니다. 실무에 필요한 코드 작성은 내 취향에 맞게 독학하고, 거기다 조금만 시간을 더 내어 집에서 간편히 대학 수업을 들을 수 있다니, 정말 편리하고 행복합니다. 내가 만약 네임밸류에 집착하며 오프라인 대학을 고집했다면 이렇게 시간을 알뜰히 활용할 수 없었을 거예요. 배움에는 왕도가 없습니다.

 

 

 

이전에 말한 것처럼 해외 진출에 대한 열망은 아직도 건재합니다. 그런데 조금 바뀐 점이 있다면, 지금 당장 해외로 무조건 나가고 말겠다는 생각은 사라졌습니다. 일단 열심히 공부하고 배울 생각입니다. 좋은 기회가 온다면 국내 기업에서도 경력을 쌓고 싶어요. 그런 다음 나가도 늦지 않을 것 같습니다. 아니면 글로벌하게 일할 수 있는 외국계 기업에 취업하는 것도 좋겠지요. 글로벌 역량을 키우기 위해 모든 독학은 영어 콘텐츠로 진행하고 있습니다. 강의 하나를 들어도 영어로 된 강의를 보고, 책 하나를 봐도 원서로 봅니다. 조금 더 기본기가 탄탄해지면 논문 리딩과 분석도 해보려고 합니다.

 

 

 

말은 뻔지르르하게 했지만, 사실 저는 그냥 공부하고 있는 백수입니다. 그렇지만 지금 행복합니다. 언제든 취업은 하겠지요. 그게 올해가 되든 내년이 되든 지금은 내가 할 수 있는 것에 집중하려고 합니다. 열심히 공부하고 적극적으로 기록하고 있습니다. 브런치에도, 앞으로 더 자주 글을 쓰겠습니다. 의원면직을 고민하는 많은 교사들, 또 직무전환을 고려하는 많은 직장인들에게 저의 이야기가 조금이나마 위로가 되었으면 좋겠습니다.

 

 

 

또 찾아올게요! 감사합니다.

 

 

 

 

 


 

 

[붙임]

11월 말부터 3월까지 4달 동안 공부한 것들을 순서대로 정리해 봅니다.

 

  • 파이썬 기본 문법
  • 파이썬 Flask 라이브러리
  • HTML, CSS, Boostrap5
  • Git, Github
  • 자바스크립트
  • MySQL
  • 정보처리기사 필기(합격)
  • 파이썬 Numpy, Pandas, Matplotlib, Seaborn 라이브러리
  • Linux 커맨드라인
  • R
  • OPIC AL / TOEIC 970
  • 프로그래머스/해커랭크 코딩테스트 문제해결 (현재진행 중, 아직 많이 부족해요)
  • 고려사이버대학(편입) - 확률과 통계, 소프트웨어공학, 빅데이터개론, 파이썬 강의 수강 중
  • 파이썬 Tensorflow와 함께 Neural Network 이론 학습 (현재진행 중, 많이 부족하지만 즐겁게 하고 있습니다.)

 

https://brunch.co.kr/@suriring/46

 

사직 후 진로를 결정하다

초등교사 의원면직 04 | 작년에 의원면직(사직)을 한 후 꽤 긴 시간이 흘렀습니다. 이제는 전 동료가 된 교사 친구들이 SNS에 올리는 새 학기 소식을 보면 '강 건너 불구경이 따로 없구먼' 하는 표

brunch.co.kr

 

 

 

 

 

  의원면직을 결심하고 나서 나에게 주어진 가장 큰 과제는 이후 행로에 대해 방향을 잡는 것이었습니다. 그 큰 틀이 세워져야 세부적인 계획도 세울 수 있을 테니까요. 내가 원하는 것은 무엇인가, 나는 어떤 사람인가를 꾸준히 탐색하려고 노력했습니다. 부모님과 대화도 주기적으로 했고, 스스로를 돌아보기도 했으며, 전문가의 상담을 받기도 했어요.

 

 

 

 

 

 

나는 올해 대학수학능력시험에 응시했습니다. 갑자기 수능이라니, 뜬금없어 보일 수 있겠지만 지금 내가 할 수 있는 최선은 수능이라고 판단이 되었어요. 

 

 

 

학교 일은 재밌었지만 공교육은 교사 개인의 노력의 결과가 눈에 수치화되지 않으며 그에 따라 보상도 받을 수 없는 구조여서 이과적 성향이 짙은 나에게는 충분한 동기부여가 되지 않았습니다. 무능력에 따른 책임을 고스란히 내가 모두 떠안아야 한대도 상관없으니 앞으로는 내 성향에 맞는 이공계나 과학 분야의 일을 선택하고 싶었어요. 

 

 

 

또 학교가 답답했던 나는 더 넓은 세상에서 살고 싶었습니다. 기회가 온다면 반드시 해외로 진출할 수 있는, 또 내가 그런 기회를 만들어갈 수 있는 직업을 갖고 싶었어요. 학교에서는 영어를 아무리 잘해봤자 결국 원어민 뒤치다꺼리나 하게 되었던 게 큰 불만이었고, 짧지만 강렬했던 뉴욕 생활을 통해 글로벌 인재로 거듭나고 싶은 욕구도 커져 있었거든요.

 

 

 

그래서 그게 뭔지 잘은 모르겠지만 일단 수학 과학을 할 줄 알아야 뭐든 할 수 있지 않을까 싶었습니다. 그래서 수능 공부를 하면서 고등 수학 과학을 리마인드도 하고 내가 어떤 과목을 왜 흥미로워하는지 살펴도 보기로 했어요. 만약 수능 점수가 기대 이상으로 잘 나온다면 내가 동물을 좋아하니 수의대를 가면 어떨까? 하고 막연하게 생각하기도 했습니다. 어릴 때부터 컴퓨터 프로그램 다루는 걸 너무 좋아하고 잘했어서 소프트웨어 공학에도 관심이 있었습니다.

 

 


 

 

 

 

세 달간 매일 15시간씩 수능 공부를 했어요. 수능 대신 소프트웨어 개발 공부를 할까 고민도 했지만, 수능은 때와 시기가 있으니 수능이 우선이었습니다. 11년 만에 돌아간 수능판은 완전히 달라져 있어서 정말 너무너무 낯설었어요. 그렇지만 적응하는 데 여유 부릴 시간도 없어 닥치는 대로 미친 듯이 공부만 했습니다.

 

 

 

수의대 얘기가 나왔으니 말인데, 나는 살면서 공부를 못해본 적은 없습니다. 그러나 나는 자기 객관화가 잘 되어 있는 사람입니다. 내가 정시로 메디컬을 노리기엔 참 애매하고 부족한 사람이라는 걸 잘 알아요. 게다가 10년 동안 손 놓고 있던 공부를 두세 달 공부해서 전국 1% 안에 들 수 있을 리가요. 그럼 결국 안 될 일이니 적당히 공부했냐 하신다면 그건 또 아닙니다. 그와 상관없이 모든 걸 쏟았어요. 칼같이 매일 여섯 시에 일어났고 밥 먹을 시간도 아껴가며 공부에 매진했습니다. 나를 테스트하고 싶었어요. 앞으로 몇 년 더 수능에 도전하며 수의대 진학을 노릴 것인가? 막상 건드려보니 수학 과학에 흥미도 능력도 없으므로 이공계 진출은 포기하고 기획이나 마케팅 등 새로운 분야를 탐색할 것인가? 다 떠나서, 새로운 분야에 뛰어들어 공부할 의지와 열정이 있기는 한가? 머릿속을 맴도는 수없는 질문에 스스로 답하고 싶었어요. 나는 이번 입시를 통해 짧고 굵고 빠르게 판단하기로 했습니다.

 

 

 

성적은 괜찮고도 아쉬웠습니다. 미적분과 영어에서 1등급을 받았습니다. 근의 공식도 잊어버려서 중학교 수학부터 출발해야 했던 걸 생각하면, 그리고 투자한 기간과 대비하면 현실적으로 괜찮은 결과였습니다. 부모님께서는 기대 이상의 성적을 보시곤 기뻐하셨습니다. 내가 아쉬워서 재도전할 거라고 생각하셨을 거예요. 근데 말이죠.... 공부하는 동안 모든 과목 중에서 생명과학 공부가 정말 더럽게 싫었어요. 재미도 없었어요. 그러니 수의대에 가겠다고 이 짓을 몇 년 더 하고 싶지도 않았어요. 몇 년 더 공부한다고 꼭 붙을 수 있는 곳도 아니고 말이죠. 명예롭고 안정적인 전문직을 가지고 싶다고 스스로를 설득하고 싶지 않았습니다.

 

 

 

나를 가장 즐겁게 했던 과목은 수학과 지구과학이었습니다. 고등학생 때 지구과학을 선택하지 않았던 터라 스스로도 놀랐습니다. 우주과학 공부가 그렇게 재밌더라고요. 나는 확실히 깔끔하게 떨어지는 논리와 계산, 알고리즘이 좋았습니다. 그러니 소프트웨어로 가야겠다고 결론지었어요. 이렇게 후회나 미련 없이 깔끔하게 판단을 내릴 수 있었던 건 누구보다 열심히 했기 때문입니다. 매일 6시에 일어나 밥 먹을 시간도 아껴가며 15시간씩 공부한 세 달이 전혀 아깝지 않았습니다. (아, 그리고 우주과학은 관련 서적을 찾아 읽고 다큐멘터리와 영화도 찾아보는 등 계속해서 취미로 즐기고 있습니다.)

 

 

 

그래서 수능 다음날 아침부터 바로 개발 공부를 시작했습니다. 국비지원제도 덕분에 요즘 너도 나도 개발에 뛰어들었다가 중도 포기하는 사람이 참 많은 것을 잘 알고 있습니다. 하지만 지난 세 달 동안 미친 듯이 공부에 매진하는 스스로를 보면서... 나는 분명 개발 공부도 열심히 꾸준히 할 수 있겠다는 자기 확신을 얻었습니다. 그 덕분에 도전을 시작할 수 있었어요. 지금은 책과 인터넷 강의를 통해 독학으로 입문 기초를 닦으면서 어떤 개발 분야가 나에게 맞을지 찬찬히 알아보고 있는 중으로, 백엔드도 재밌고 프런트엔드도 재밌어서 풀스택으로 가야 할지 등등 이런저런 즐거운 고민을 하고 있습니다. 또 수능 점수가 괜찮으니 늦깎이 새내기(일명 헌내기)로 입학을 해서 학위를 따 볼지, 아니면 4년을 다 다시 다니기는 좀 너무하니 편입을 또 준비해야 할지와 같은 고민도 하고 있습니다.

 

 

 

앞으로는 개발자가 되기 위해 고군분투하는 과정을 틈틈이 브런치에 기록하도록 하겠습니다. 세상의 모든 도전은 아름답습니다. 그리고 도전하는 나는 아름답습니다. 나는 나를 응원해요. 세상의 모든 도전하는 사람들에게 응원과 격려의 메시지를 전해 봅니다.

 

 

 

 

 

  일을 관둔다고 했을 때 모든 사람이 공통적으로 물었습니다. 학교 일이 그렇게 안 맞아요? 그러면 나는 답했습니다. 아뇨, 일은 정말 재밌었어요. 배운 것도 많고요. 더 이상 애들을 못 본다고 생각하면 마음도 아프고 많이 아쉽기도 해요. 그런데 여기서 평생 일할 생각은 없을 뿐이에요.

 

 

  학교가 끔찍이 싫은 것도 애들과 학부모를 상대하는 일이 적성에 더럽게 안 맞는 것도 아니었습니다. 내가 마주한 가장 큰 문제의식은 앞으로 학교에서의 내 모습이 그려지지 않는다는 것이었어요. 나는 학교에서라면 먼 미래는커녕 당장 5년 뒤의 가까운 미래에조차 원하는 게 없었거든요. 승진을 해서 관리자(교감, 교장)가 되고 싶지도 않았고, 대학원에서 교육학을 연구해서 석박사를 따고 싶지도 않았고, 그렇다고 장학사가 되거나 교육청으로 진출해서 공교육 체계 수립에 기여하고 싶은 마음도 없었어요. 계속 고민했습니다. 그렇다면 나는 여기서 앞으로 어떻게 성장할 것인가?

 

 

  우리나라 학교는 나뿐만 아니라 그 누구에게도 열정을 불태울 수 있을 만한 공간이 아닙니다. 교사가 시간과 노력을 아무리 투자해도 따라오는 보상이 고작 개인적 만족감쯤에 그치고 말기 때문이에요. 신규 발령을 받고 1-2년만 일해도 쉽게 깨달을 수 있습니다. '학교는 열심히 하면 손해를 보는 곳'이라는 사실을. 안타까운 현실이에요. 만약 나에게 결혼과 출산, 육아가 인생의 큰 목표였다면 이야기가 달랐을 지도 모르겠습니다. 학교는 분명, 기혼자에게는 굉장히 메리트가 있는 직장입니다. 나는 확고한 비혼인은 아니긴 합니다만 가정을 일구는 걸 인생에 꼭 이뤄야 할 과업으로 여기진 않습니다.

 

 

<프렌즈>의 레이첼이 센트럴 퍼크의 웨이트리스를 때려치운 덕분에 원하는 패션 일을 하며 행복해질 수 있었던 것, 기억 하시나요?

 

 

  30대를 눈앞에 둔 지금 나에게 필요한 것은 목표의식과 도전의식을 심어주고 성장할 수 있는 새로운 환경인 것 같습니다. 조금 더 나의 열정을 불태우게 만드는 일을 하고 싶어요. 부끄럽지만 그게 무엇인지는 아직 확실히 하지 못했습니다. 아무것도 정해진 바 없이, 심지어 꼭 하고 싶은 다른 일을 확정하지도 못한 채로 의원면직을 저질렀어요. 누군가는 나를 멍청하다고 생각할 수도 있겠지만 이상하게 후회는 안 돼요. 

 

 

 

 

  다음 편으로는 일을 그만둔 젊은 공립 초등교사의 장래 고민, 나의 적성과 새로운 커리어 방향을 뒤적이는 글을 써보도록 하겠습니다.

 

 

 

 

 

https://brunch.co.kr/@suriring/37

 

학교를 그만둔 이유

초등교사 의원면직 02 | 일을 관둔다고 했을 때 모든 사람이 공통적으로 물었습니다. 학교 일이 그렇게 안 맞아요? 그러면 나는 답했습니다. 아뇨, 일은 정말 재밌었어요. 배운 것도 많고요. 더 이

brunch.co.kr

 

 
 

 

 

  오늘 마지막 출근을 했습니다. 짐을 정리하고 인수인계를 하느라 조금 더 바빴을 뿐 평소와 다를 것 없는 보통의 하루였습니다.

 

 

 

 

 

  임용고시를 통과한 정교사가 사직을 하는 일은 가뭄에 콩 나듯 드물어요. 일을 그만둔다고 해도 교대 졸업장으로 할 수 있는 뾰족한 다른 일이 있는 것도 아니거니와, 마음이 바뀌어 복직을 하려면 임용고시를 다시 봐야 하기 때문입니다. 누구도 그런 모험을 하고 싶어 하지 않습니다. 특히 말 잘 듣는 교사들이라면 더욱요.

 

 

 

  나도 남들과 다를 바 없는 같은 고민을 했습니다. 일을 그만두고 후회하지 않을 수 있을까? 이만한 직업이 또 있을까? 내가 다른 일을 한다면 뭘 할 수 있을까? 치열한 고민 끝에 내린 결론은 결국 사직이었습니다. 학교를 떠나 후회하는 것도 무섭지만, 그게 무서워 학교에 평생 갇혀 있는 삶은 더 무서웠습니다. 그렇다면 떠나는 게 맞겠죠. 오히려 결심을 하고 나니 모든 게 선명해집니다.

 

 

 

  결정을 내리는 데에는 부모님과의 대화가 가장 큰 도움이 되었습니다. 아빠는 직장 생활을 하는 평생 동안 가슴 한편에 '내 일'을 하는 꿈을 꾸었다고 했습니다. 그러나 부양해야 할 가족이 있어 쉽게 결단을 내리지 못했다고. 그러니 젊고 자유로운 나는 무엇이든 새로 도전해도 된다고, 늦었다고 생각하지 말라며 차분하고 진지하게 말해주셨습니다. 서른이나 된 나를 애기라고 하셨어요. 아빠의 경험에서 우러나온 진심 어린 이야기들이 나에게는 아주 커다란 위로와 용기가 되었습니다.

 

 

 

 

 

 

 

 

  그렇게 나는 안정적인 삶을 포기하고 불투명한 미래를 선택하기로 했습니다. 내 앞에 펼쳐질 모든 고난과 역경을 온몸으로 받아들일 마음의 준비를 기꺼이 하면서요. 긴장도 되고 설레기도 합니다. 불안하지 않다면 거짓말이겠지만, 옳은 선택을 했다는 믿음에는 변함이 없습니다.

 

 

 

  앞으로 우여곡절이 있을 때마다 아이들과 쌓은 예쁜 추억들을 하나씩 꺼내어 보면서 힘을 내어 보도록 할게요.

 

 

 

 

프로그래머스 코딩테스트 1단계에 수록되어있는 카카오 인턴십 '키패드 누르기' 문제를 풀었습니다. 풀고 나서 코드가 좀 길다고 생각했는데 다른 사람들의 풀이를 보니 다들 비슷한 길이라서 안심이 되었습니다. (한심...ㅎ) 길다고 무조건 나쁜 코드, 짧다고 무조건 좋은 코드는 아니긴 합니다. 그래도 최대한 니트하고 간결하게 작성하고싶은 욕심이 드는 건 어쩔 수가 없네요 ㅎ_ㅎ (그럼에도 불구하고 제 코드는 항상 긴 편인거 같아요.)

 

저는 키패드에 좌표 개념을 도입하여 간단하게 문제를 풀어보았습니다. 문제 풀이 시간은 5분-10분정도로 그래도 최근에 연습했던 알고리즘 문제들에 비교하면 비교적 수월했던 문제였던 것 같습니다. 그럼 풀어보겠습니다!

 

 

문제 상황 : 이 전화 키패드에서 왼손과 오른손의 엄지손가락만을 이용해서 숫자만을 입력하려고 합니다. 맨 처음 왼손 엄지손가락은 * 키패드에 오른손 엄지손가락은 # 키패드 위치에서 시작하며, 엄지손가락을 사용하는 규칙은 다음과 같습니다.

1. 엄지손가락은 상하좌우 4가지 방향... (중략....)


자세한 문제 상황과 조건, 입출력, 테스트 케이스 등은
꼭 프로그래머스에서 확인해 보세요!

https://school.programmers.co.kr/learn/courses/30/lessons/67256

 

 

 

1. 문제의 이해

먼저 정수로 이루어진 리스트 numbers가 인풋으로 주어집니다. 문제 조건을 보면, 정수가 1, 4, 7일 때에는 바로 왼손을, 3, 6, 9일때는 바로 오른손을 쓰면 되기 때문에 아무런 제약이 없어서 굉장히 쉽습니다. 우리가 고민해야 할 부분은 정수가 2, 5, 8, 0일 때입니다.

 

2, 5, 8, 0이 주어졌을 때 조건에 맞게 손가락을 움직이기 위해서는

 1)  그 전의 손가락 위치를 알고 있어야 합니다.

 2)  그 전의 손가락 위치와 2/5/8/0 사이의 거리를 숫자로 나타낼 수 있어야 합니다.

 3)  왼손, 오른손과 2/5/8/0 사이의 거리를 비교할 수 있어야 합니다.

 

그럼 위 세 가지를 고민하면서 문제를 풀어보겠습니다.

 

 

2. 풀이

[1] 변수와 좌표 설정

def solution(numbers, hand):
    answer = ""
    current_left_thumb = (4, 1)
    current_right_thumb = (4, 3)

 

저는 키패드 1이 있는 곳을 좌표 (1, 1)으로, 

키패드 3이 있는 곳을 좌표 (1, 3)으로,

키패드 *이 있는 곳을 좌표 (4, 1)으로,

키패드 #이 있는 곳을 좌표 (4, 3)으로 놓았습니다.

 

첫줄을 파이썬 인덱싱과 같이 0부터 시작할까 하다가 보다 직관적으로 하기 위해 1부터 시작해줬는데, 0부터 시작해도 큰 상관은 없습니다.

 

current_left_thumb, current_right_thumb라는 변수명을 사용하여 왼손/오른손을 구분하여 현재 손가락이 어디 있는지를 좌표값으로 표현했습니다. 변수명이 조금 길고 번잡하긴 하지만 직관적으로 이해할 수 있어서 스스로 코드 이해하기가 편했습니다. 이 두 가지 변수는 앞으로 numbers에 주어진 정수값에 따라 손가락이 움직일 때 함께 업데이트가 되어 갈 예정입니다!

 

 

[2] 1/4/7, 3/6/9 처리

    for number in numbers:
        if number == 1:
            answer += "L"
            current_left_thumb = (1, 1)
        elif number == 4:
            answer += "L"
            current_left_thumb = (2, 1)
        elif number == 7:
            answer += "L"
            current_left_thumb = (3, 1)
        elif number == 3:
            answer += "R"
            current_right_thumb = (1, 3)
        elif number == 6:
            answer += "R"
            current_right_thumb = (2, 3)
        elif number == 9:
            answer += "R"
            current_right_thumb = (3, 3)

 

다음으로 numbers 리스트의 값(value)를 가지고 하나씩 살펴보면서 이터레이션을 돌려줍니다. 리스트 이터레이션은 습관적으로 인덱스로 하게 되는데, 이번 문제에서는 굳이 인덱스로 조회할 필요가 없어서 편했습니다.

 

만약 number가 1/4/7중에 하나라면 answer 스트링에 L을 추가하고 해당 좌표값으로 왼손을 움직입니다(current_left_thumb 변수의 좌표를 업데이트합니다.). 만약 number 3/6/9중에 하나라면 answer 스트링에 R을 추가하고 해당 좌표값으로 오른손을 움직입니다(current_right_thumb 변수의 좌표를 업데이트합니다.). 

 

이 부분의 문법이 어쩔수없이 위처럼 길어지게 되었는데, 어떻게 하면 더 짧게 쓸 수 있을까 잠깐 고민했어요. 하지만 지금 이대로도 아주 직관적이고 이해하기 편하기 때문에 굳이 줄이지 않아도 되겠다고 판단하고 다음 단계로 넘어갔습니다.

 

 

[3] 2/5/8/0 처리

        elif number in [2, 5, 8, 0]:
            if number == 2: x = 1
            if number == 5: x = 2
            if number == 8: x = 3
            if number == 0: x = 4

 

다음으로 가장 중요한 2, 5, 8, 0입니다. 저는 2, 5, 8, 0이 모두 같은 세로줄에 있다는 점에 착안하여 아이디어를 얻어서 2/5/8/0의 열(y)을 2로 고정하고 행(x)만 변수로 각각 1/2/3/4를 할당해 주었습니다. 더 자세히 설명해보겠습니다.

 

숫자 2의 좌표값은 (1, 2)입니다.

숫자 5의 좌표값은 (2, 2)입니다.

숫자 8의 좌표값은 (3, 2)입니다.

숫자 0의 좌표값은 (4, 2)입니다.

 

따라서 숫자 2, 5, 8, 0의 좌표를 (x, 2)와 같이 표현하고 x에만 각각 1/2/3/4를 할당해 주어 반복을 줄이겠다는 의미입니다.

 

distance_r = abs(current_right_thumb[0] - x) + abs(current_right_thumb[1] - 2)
distance_l = abs(current_left_thumb[0] - x) + abs(current_left_thumb[1] - 2)

# 가독성을 위해 인덴트를 없앴습니다

 

이제 거리 구하기로 넘어갑니다. 우리는 current_left_thumb와 current_right_thumb 라는 변수에 각각 왼손과 오른손 엄지의 직전 좌표값을 저장해 두고 있어요. 우리가 가고자 하는 2/5/8/0의 좌표값과 왼손, 오른손 사이의 거리를 각각 구해보도록 하겠습니다.

 

일반화된 식을 쓰기 전에 예시를 가지고 생각을 열어 볼게요. 키패드 2와 6 사이의 거리는 2입니다. 좌표로 어떻게 구할 수 있을까요? 키패드 2의 좌표는 (1, 2), 키패드 6의 좌표는 (2, 3)입니다. x값의 차이 1과 y값의 차이 1을 더해 주면 간단히 2가 나오는 것을 알 수 있어요. 키패드 8과 키패드 1의 경우는 어떨까요? 우선 거리는 3입니다. 좌표로 확인해 봅니다. 키패드 8의 좌표는 (3, 2)입니다. 키패드 1의 좌표는 (1, 1)입니다. x값의 차이 2와 y값의 차이는 1이며 둘을 더해 주면 3이 됩니다. 이제 일반화가 되었습니다.

 

abs(current_right_thumb[0] - x) : 오른손 엄지손가락의 행좌표와 2/5/8/0의 행좌표(x)의 차(절댓값)

abs(current_right_thumb[1] - 2) : 오른손 엄지손가락의 행좌표와 2/5/8/0의 열좌표(2)의 차(절댓값)

 

이 두개를 더해 주면 오른손이 움직이는 거리(distance_r)가 되고,

같은 방법으로 왼손이 움직이는 거리(distance_l)도 구해준 거예요.

 

            if distance_r < distance_l:
            # 오른손이 가야 하는 거리가 더 짧을 때
                answer += "R"
                current_right_thumb = (x, 2)
            elif distance_r > distance_l:
            # 왼손이 가야 하는 거리가 더 짧을 때
                answer += "L"
                current_left_thumb = (x, 2)
            else:
            # 왼손 = 오른손 거리가 같을 때
                if hand == 'right':
                # 오른손잡이라면
                    answer += "R"
                    current_right_thumb = (x, 2)
                else:
                # 왼손잡이라면
                    answer += "L"
                    current_left_thumb = (x, 2)

 

이제 거리를 비교합니다. 오른손이 가야 하는 거리가 더 짧을 때, 왼손이 가야 하는 거리가 짧을 때, 왼손과 오른손이 가야할 거리가 같을 때로 크게 셋으로 나누어 생각합니다. 특히 왼손, 오른손 거리가 같다면 왼손잡이인지 오른손잡이인지를 판단하는 것이 중요합니다.

 

 

이제 제가 작성한 함수를 한 번에 보겠습니다.

def solution(numbers, hand):
    answer = ""
    current_left_thumb = (4, 1)
    current_right_thumb = (4, 3)

    for number in numbers:
        if number == 1:
            answer += "L"
            current_left_thumb = (1, 1)
        elif number == 4:
            answer += "L"
            current_left_thumb = (2, 1)
        elif number == 7:
            answer += "L"
            current_left_thumb = (3, 1)
        elif number == 3:
            answer += "R"
            current_right_thumb = (1, 3)
        elif number == 6:
            answer += "R"
            current_right_thumb = (2, 3)
        elif number == 9:
            answer += "R"
            current_right_thumb = (3, 3)
        elif number in [2, 5, 8, 0]:
            if number == 2: x = 1
            if number == 5: x = 2
            if number == 8: x = 3
            if number == 0: x = 4

            distance_r = abs(current_right_thumb[0] - x) + abs(current_right_thumb[1] - 2)
            distance_l = abs(current_left_thumb[0] - x) + abs(current_left_thumb[1] - 2)
            if distance_r < distance_l:
                answer += "R"
                current_right_thumb = (x, 2)
            elif distance_r > distance_l:
                answer += "L"
                current_left_thumb = (x, 2)
            else:
                if hand == 'right':
                    answer += "R"
                    current_right_thumb = (x, 2)
                else:
                    answer += "L"
                    current_left_thumb = (x, 2)
    return answer
정확성: 100.0 합계: 100.0 / 100.0
 
 

숫자가 2, 5, 8, 0일 때 열 좌표가 2로 모두 동일하다는 점에 착안하여 행 좌표만 x로 변수 할당을 해줌으로써 반복을 줄일 수 있었습니다. 비록 엄청 짧은 코드는 아니지만 깔끔하고 직관적으로 풀이할 수 있어서 좋았습니다!

 

부족한 풀이었지만 도움이 되었으면 좋겠네요~ 감사합니다.

 

 

 

https://school.programmers.co.kr/learn/courses/30/lessons/159994

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

프로그래머스 코딩테스트 1단계에 수록되어 있는 '카드 뭉치' 문제를 풀었습니다. 다른 사람의 풀이와 비교해보니 제가 조금 독특하게 풀었더라구요. 제 코드가 좀 지저분하긴 하지만 남들과 다른 아이디어로 푼 게 마음에 들어 sorted 문법 정리할 겸 풀이과정을 작성해보고자 합니다.

 

 

우선 제출한 답안은 다음과 같습니다.

def solution(cards1, cards2, goal):
    cards1_sorted = sorted(enumerate(cards1), 
    	key = lambda x: (goal.index(x[1]) if x[1] in goal else len(goal) + 1))
    cards2_sorted = sorted(enumerate(cards2), 
    	key = lambda x: (goal.index(x[1]) if x[1] in goal else len(goal) + 1))
                           
    index_1 = [index for index, value in cards1_sorted]
    index_2 = [index for index, value in cards2_sorted]
    
    if index_1 != sorted(index_1) or index_2 != sorted(index_2):
        return "No"
    else:
        return "Yes"
정확성: 100.0, 합계: 100.0 / 100.0

 

하나씩 쪼개어 정리해 보겠습니다.

테스트케이스의 2번째 예시로 설명해 보겠습니다.

 

 

 

1. 먼저, cards1과 cards2에 enumerate() 함수를 이용해서 (인덱스, 카드)값이 되도록 만들어 줍니다. list()함수를 씌워 결과값을 눈으로 확인하면 다음과 같습니다.

cards1 = ["i", "water", "drink"]
cards2 = ["want", "to"]	
goal = ["i", "want", "to", "drink", "water"]	

list(enumerate(cards1))
# [(0, 'i'), (1, 'water'), (2, 'drink')]

list(enumerate(cards2))
# [(0, 'want'), (1, 'to')]

 

 

 

 

2. 저는 이렇게 추출한 이뉴머레이트 결과값을, sorted()를 이용해서 정렬을 해줄 거에요. 이 때 정렬을 해 주는 기준으로 goal을 넣어 주어서, goal에 있는 순서대로 정렬되도록 하겠습니다.

cards1_sorted = sorted(enumerate(cards1), key = lambda x: goal.index(x[1])
cards2_sorted = sorted(enumerate(cards2), key = lambda x: goal.index(x[1])

cards1_sorted
# [(0, 'i'), (2, 'drink'), (1, 'water')]

cards2_sorted
# [(0, 'want'), (1, 'to')]

 

key = lambda x: goal.index(x[1]) 와 같이 정렬 조건을 걸어줌으로써, cards1의 이뉴머레이트 결과값의 인덱스 1번 벨류가 goal에 어떤 순서대로 있느냐?를 기준으로 정렬한 값을 반환하도록 하였습니다. 결과값을 확인해보니 cards2는 그대로이지만 cards1은 drink가 앞으로 온 것을 확인할 수 있습니다. 그런데 이 문법에는 문제가 있습니다. 만약 cards1에 있는 단어가 goal에 없다면 어떻게 될까요?

 

2 - (1)

cards1 = ["i", "water", "drink", "apple"]
cards1_sorted = sorted(list(enumerate(cards1)), key = lambda x: goal.index(x[1]))

# ValueError: 'apple' is not in list

 

cards1에 'apple'을 추가해 보니, 벨류 에러가 발생합니다. 따라서 이렇게 없는 값이 있을 경우에는 cards1_sorted의 맨 뒤에다가 값을 추가해주도록 조건을 걸어주겠습니다.

cards1_sorted = sorted(list(enumerate(cards1)), 
             	   key = lambda x: (goal.index(x[1]) if x[1] in goal else len(goal) + 1))
cards2_sorted = sorted(list(enumerate(cards2)), 
            	   key = lambda x: (goal.index(x[1]) if x[1] in goal else len(goal) + 1))

 

만약 x[1]이 goal에 있다면 기존대로 정렬을 하고, 없다면 뒤에 추가하도록 if else 구문을 사용하여 조건을 걸어줬습니다. 이 부분은 챗지피티의 도움으로 완성할 수 있었습니다^_ㅠ 엄청 직관적인 문법이 아닌것 같긴 합니다만 그래도 자주 사용해서 자유자재로 구사할 수 있도록 하려고 합니다.

 

다시 apple이 없었던 원래의 예시문제로 돌아가서 계속해서 설명해보겠습니다.

 

 

 

 

3.

index_1 = [index for index, value in cards1_sorted]
index_2 = [index for index, value in cards2_sorted]


index_1
# [0, 2, 1]
index_2
# [0, 1]

 

 

이제 cards1_sorted와 cards_2sorted에서 인덱스만 뽑아서 깔끔한 리스트 index_1, index_2로 뽑아냅니다. 저는 이 index 리스트의 결과값이 0-2-1처럼 순서에 맞지 않을 경우 카드를 앞에서부터 차례로 사용하는 조건에 어긋난다는 점을 발견했습니다. 

 

따라서 index_1, index_2가 오름차순으로 정렬되어 있다면 "Yes"를, 그렇지 않다면(순서가 뒤죽박죽이라면) "No"를 리턴하도록 함수를 작성했습니다.

def solution(cards1, cards2, goal):
    cards1_sorted = sorted(enumerate(cards1), key = lambda x: (goal.index(x[1]) if x[1] in goal else len(goal) + 1))
    cards2_sorted = sorted(enumerate(cards2), key = lambda x: (goal.index(x[1]) if x[1] in goal else len(goal) + 1))

    index_1 = [index for index, value in cards1_sorted]
    index_2 = [index for index, value in cards2_sorted]
    
    if index_1 != sorted(index_1) or index_2 != sorted(index_2):
        return "No"
    else:
        return "Yes"

 

 

 

최근에 sorted() 함수에 대해서 리뷰를 했으며 특히 key 뒤에 lambda 함수를 어떻게 활용할 수 있는 지 여러번 살펴보았기 때문에 위와 같은 아이디어로 문제를 풀 수 있었습니다. 다른 사람의 풀이를 확인해보니 이런 방식으로 풀이를 하신 분은 찾아보기 어려웠고 더 짧고 깔끔하고 반듯하게 푸신 분이 많아서 존경스러웠습니다! 아주 깔끔한 코드는 아니지만 그래도 재밌는 아이디어로 풀어낸 점을 스스로 높게 평가하고자 합니다 ^_^!

 

 

 

감사합니다.

 

 

 

더보기

N by M 크기의 얼음 틀이 있습니다. 구멍이 뚫려 있는 부분은 0 칸막이가 존재하는 부분은 1입니다.  구멍이 뚫려있는 부분끼리 상, 하, 좌, 우로 붙어있는 경우 서로 연결되어 있는 것으로 판단합니다. 이러한 경우에서 얼음 틀의 모양이 그래프로 주어진다면 생성되는 아이스크림의 갯수는 몇 개일까요?

graph_45 = [
    [0,0,1,1,0],
    [0,0,0,1,1],
    [1,1,1,1,1],
    [0,0,0,0,0]
]

n = 4
m = 5

 

첫째 / BFS 방식으로 풀기

 

출발점에서부터 점진적으로 진행해가는 방식으로 접근하는 경우 BFS를 고려해볼 수 있습니다.

일단 BFS니까 아묻따 디큐부터 임포트해주고 시작합니다.

 

from collections import deque

 

 

1. 함수를 작성합니다. 입력받은 출발점 좌표로부터 시작하여 출발점 좌표가 1이면 바로 False를 리턴하고, 출발점 좌표가 0이면 주변을 탐색하면서 0이 있으면 1로 바꾸고, 더이상 바꿀 0이 없는 경우에는 True를 리턴하는 함수를 작성합니다.

2. 함수 작성 이후, 주어진 그래프의 (0, 0)부터 시작하여 n*m 좌표마다 함수를 적용하도록 이터레이션을 돌립니다. True가 반환되는 갯수가 곧 음료수 얼음 덩어리의 갯수가 됩니다.

 

def ice_bfs(row_init, col_init):
    # 만약 주어진 좌표가 0이라면 가보자고!
    if graph[row_init][col_init] == 0:
        q = deque([[row_init, col_init]])
        # ---------------------------------------- 무한 루프 
        while True:
            if not q:
                return 1

            row, col = q.popleft()
            for [dx, dy] in [[0, -1], [0, 1], [1, 0], [-1, 0]]:
                # 이동한 값이 지도 안에 있고
                if 0 <= row + dx < n and 0 <= col + dy < m:
                    # 얼릴 수 있다면
                    if graph[row+dx][col+dy] == 0:
                        # 1번 도장을 찍고, 그 다음 할일 추가하세요
                        graph[row+dx][col+dy] = 1
                        q.append([row+dx, col+dy])
        # ---------------------------------------- 무한 루프 
    else:
        return 0
result = 0

for row in range(n):
    for col in range(m):
        result += ice_bfs(row, col)

print(result)
# 3

 

 

둘째 / DFS 방식으로 풀기

위에서 작성한 함수를 DFS방식을 활용한 재귀함수로 바꾸어 작성해 봅시다. (같은 기능!)

 

def dfs_recursive(row, col):
    # 주어진 점이 틀 밖이라면 바로 함수 종료
    if row <= -1 or row >= n or col <= -1 or col >= m:
        return False
    
    # [1] 주어진 점이 0이라면 True를 반환
    if graph[row][col] == 0:
        
        graph[row][col] = 1  # 일단 True 반환 전에 0->1로 바꾸고
        dfs_recursive(row, col-1)
        dfs_recursive(row-1, col)
        dfs_recursive(row, col+1)
        dfs_recursive(row+1, col) # 상하 좌우도 전부 점검해주기!

        return True

    # [2] 주어진 점이 1이라면 False를 반환
    else:
        return False

 

같은 방식으로 모든 좌표점에 작성한 함수를 돌려주면서 True가 반환되는 개수를 세어 주면 끝~

 

result = 0

for row in range(n):
    for col in range(m):
        result += dfs_recursive(row, col)

print(result)
# 3

 

 

 

짱짱 재밌군!

BFS도 DFS도 자유자재로 활용할 수 있도록 열심히 반복!

 

 

다음 문제로는 카카오 2022 블라인드 공개채용 <양과 늑대> 문제를 풀어봅시다...

 

 

 

 

탐색으로 풀어보려고 했으나 경우의 수를 모두 나누기가 어려웠습니다. 다른사람들의 풀이를 참고해 보니 direction 값을 right부터 시작하여 순차적으로 바꾸어나가는 이터레이션을 돌리면 간단하게 해결이 가능했습니다.

 

문제 설명 : 양의 정수 n이 매개변수로 주어집니다. n × n 배열에 1부터 n2 까지 정수를 인덱스 [0][0]부터 시계방향 나선형으로 배치한 이차원 배열을 return 하는 solution 함수를 작성해 주세요.

 

 

코드로 작성해 봅시다.

# 예시 (n=3일 때)

n = 3
graph = [[0] * n for _ in range(n)]

graph
# [[0, 0, 0],
#  [0, 0, 0],
#  [0, 0, 0]]

 

먼저 함수 초반에 그래프의 초기값은 다음과같이 세팅해줍니다. 확실히 리스트 컴프리핸션은 자유자재로 쓸 수 있어야 합니다.

 

# 기본 뼈대

for i in range(1, n**2+1):
    if dir == 'r':
        y += 1
    elif dir == 'd':
        x += 1
    elif dir == 'l':
        y -= 1
    elif dir == 'u'
        x -= 1

 

방향의 값은 오른쪽부터 시작해서 나선형으로 오른쪽 -> 아래 -> 왼쪽 -> 위 -> 오른쪽 ...(반복) 순서로 뱅글뱅글 돌아가게 해줄 겁니다. 그럼 완성된 함수로 작성해 보겠습니다.

 

def solution(n):
	# 만약 n이 1인 경우 빠르게 종료
    if n == 1:
    	return [[1]]
        
    # 초기값 세팅 : (0, 0)으로부터 오른쪽 이동부터 시작한다.
    graph = [[0] * n for _ in range(n)]
    x = 0
    y = 0
    direction = 'R'
	
    # n의 제곱번 이터레이션을 돌려 준다.
    for i in range(1, n**2 + 1):
    	graph[x][y] = i
        
        # right : x값 고정, y값만 1 증가
        if direction == 'R':
            y += 1
            # 만약 끝까지 갔거나 그 다음 값이 0이 아니라면 방향 변경
            if y == n-1 or graph[x][y+1] != 0:
            	direction = 'D'

        # down : y값 고정, x값만 1 증가
        elif direction == 'D':
        	x += 1
            # 만약 끝까지 갔거나 그 다음 값이 0이 아니라면 방향 변경
            if x == n-1 or graph[x+1][y] != 0:
            	direction = 'L'

        # left : x값 고정, y값만 1 감소
        elif direction == 'L':
        	y -= 1
            # 만약 끝까지 갔거나(y값이 0) 그 다음 값이 0이 아니라면 방향 변경
            if y == 0 or graph[x][y-1] != 0:
            	direction = 'U'
                
        # up : y값 고정, x값만 1 감소
        elif direction == 'L':
        	x -= 1
            # 만약 끝까지 갔거나 그 다음 값이 0이 아니라면 방향 변경
            if x == n-1 or graph[x-1][y] != 0:
            	direction = 'R'
                
        return graph

 

완성된 함수에는 더이상 갈 곳이 없거나 가야할 곳에 0이 아닌 숫자가 있는 경우 방향을 변경해주는 기능이 추가되었습니다. 25번 이터레이션을 돌면서 각각의 순서에 맞게 번호가 부여됩니다.

 

아휴 재밌다

 

 

백준 2178번 미로탐색

https://www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

 

 

n = 4
m = 6

graph = [
	[1, 0, 1, 1, 1, 1],
 	[1, 0, 1, 0, 1, 0],
 	[1, 0, 1, 0, 1, 1],
 	[1, 1, 1, 0, 1, 1]
 ]

 

0과 1로 이루어진 n * m 크기의 미로 그래프가 있다. 미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다. 위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

 

 

dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]

 

먼저 상하좌우로 움직일수 있는 x, y 델타값을 리스트로 작성한다.

def dfs_escape(start = (0, 0)):
	# x, y의 현재 포지션을 정해 준다. 
    x_pos = start[0]
    y_pos = start[1]
    
    # 할 일을 기록할 디큐 리스트 q를 작성한다.
    q = deque()
    
    # 가장 처음 초기값을 세팅해준다. x, y의 좌표값 위치를 튜플로 집어넣는다.
    q.append((x_pos, y_pos))
    
    # 할 일이 없을 때까지 반복!
    while q:
    	now_x, now_y = q.popleft()
        
        # 상하좌우 4번 반복
        for i in range(4):
        	next_x = now_x + dx[i]
        	next_y = now_y + dy[i]
            
            # 만약 다음으로 갈 좌표값이 미로를 벗어나지 않는다면
            if 0 <= next_x < n and 0 <= next_y < m:
                if graph[next_x][next_y] == 1:
                    graph[next_x][next_y] = graph[now_x][now_y] + 1
                    q.append((next_x, next_y))

 

bfs_miro()


graph
# [[3, 0, 9, 10, 11, 12],
#  [2, 0, 8, 0, 12, 0],
#  [3, 0, 7, 0, 13, 14],
#  [4, 5, 6, 0, 14, 15]]


graph[n-1][m-1]
# 15

 

 

 

+ Recent posts