- Published on
별 찍기
- Authors
- Name
- 심성헌 (SeongHeon Sim)
처음부터 시작하는 알고리즘
학원을 수료했지만 알고리즘이나 자료구조에 대해
내 입으로 말할 수 없는데 개발자라고 말할 수 있을까?
학원을 다니면서 프로젝트를 진행하며 기능을 만들 때 가장 힘들었던 점은 내가 짠 코드이지만 팀원들에게 명확하게 설명할 수 없을 때 정말 답답함을 많이 느꼈다. 특히나 코드에 대해 설명하면서도 내 말이 나 조차도 이해가 안 될 때는 정말 미쳐버리는 줄 알았다.
그래서 국비 학원을 다니는 약 6개월이라는 시간 내내 알고리즘, 자료구조에 대한 배움의 갈망이 정말 컸다.
또한 내가 내 입으로 "저 개발자예요!"라고 말할 수 있으려면 알고리즘과 자료구조에 대해 파악하고 있어야 한다고 생각했고, 내가 더 좋은 곳으로 취업하고 엄청난 영향력을 가진 개발자가 되려면 당연 필수라고 생각했다.
특히나 나는 내가 배운 것으로만 먹고살고, 제자리에 머무르고 싶지 않았다.
그래서 코딩 감각을 잃기 전에, 여러 가지 들을 위해서 며칠 쉬고 알고리즘과 자료구조 공부를 시작하게 되었다.
먼저, 학원을 다니기 전, 다니는 중간 즈음에 몇 번 백준 문제를 풀고 네이버 블로그에 글도 썼던 경험이 있다.
물론 그때의 그때의 나와 지금의 나는 명확한 실력 차이가 있지만, 그때의 나를 되돌아보면 그 당시 중첩 반복문을 이용한 별 찍기는 정말 죽어도 풀리지 않아서 미치기 직전에 포기했었다. (바보임이 틀림없다!😤)
언젠가는 그 별 찍기 문제를 꼭 내 힘으로 풀어보고 싶었는데, 그 날이 바로 오늘이다.
나는 자바로 프로그래밍을 시작했고 컴퓨터 공학에 대해서는 완전 문외한이었기 때문에 초보자의 마음가짐으로 다가가기 시작했다.
책에는 for문이나 if문을 활용한 여러 가지 실습 문제를 제일 처음에 제공한다.
대체로 처음 문제는 쉬웠고, 문제를 풀면서 어느 정도 내 머리가 조금은 틔였구나 싶었다.
별 찍기와 피라미드 문제를 다시 만나기 전까지는....
별 찍기
책에서는 처음에 4개의 별 찍기 문제가 나온다. 이중 for문을 활용한 문제다.
백준을 풀 때도 이렇게 다양했었나? 금방 포기해서 기억이 나질 않는다.
어쨌든! 책에서는
- 좌측 하단이 직각인 이등변 삼각형 만들기
- 좌측 상단이 직각인 이등변 삼각형 만들기
- 우측 하단이 직각인 이등변 삼각형 만들기
- 우측 상단이 직각인 이등변 삼각형 만들기
총 4개의 직각 이등변 삼각형을 매개변수를 받아 그에 맞게 만들어야 한다.
먼저 완성본부터 자랑하고 싶다! (국비 수료 후 처음으로 혼자 힘으로 풀어보았다!🥺)
*
**
***
****
*****
******
*******
********
*********
**********
***********
***********
**********
*********
********
*******
******
*****
****
***
**
*
***********
**********
*********
********
*******
******
*****
****
***
**
*
*
**
***
****
*****
******
*******
********
*********
**********
***********
모두 다 파라미터 값을 11로 설정하여 출력하였다.
처음 두 문제(좌측을 기준으로 한 이등변 삼각형)는 생각보다 금방 풀 수 있었다.
왜냐하면 빈 곳을 만들 필요 없이 System.out.println(); 로 다음 줄로 넘기면 되기 때문이다.
하지만 뒤에 두 문제(우측을 기준으로 한 이등변 삼각형)는 어떻게 공간을 만들어야 할지 머리를 쥐어 뜯게 만들었다.(확실히 바보다..)
그래서 어떻게든 문제를 풀어내려고 모든 문제를 손으로 그림을 그려가며 구조를 파악하려고 노력했다!
그렇다면 먼저 첫 번째 문제부터 차근차근 알아보도록 하자!
좌측 하단이 직각인 이등변 삼각형 만들기
// 좌측 하단이 직각인 이등변 삼각형 만들기
public static void triangleLB(int n) {
for(int i = 1; i <= n; i++) {
for(int k = 0; k < i; k++) {
System.out.print("*");
}
System.out.println();
}
}
첫 번째 문제는 이렇게 생각하면 쉬운 것 같다.
메소드의 매개변수 = 콘솔에 찍힐 가로줄의 개수 > 한 개의 가로줄에 찍힐 별의 개수 = 콘솔에 찍힌 가로줄의 번호(혹은 순서)
매개변수 값을 5라고 가정했을 때, 맨 윗줄부터 1, 2, 3, 4, 5 개의 별들이 직렬로 찍힌다. 위의 별 삼각형의 첫 번째 모양이다.
차례대로 별을 찍기 위해서는 이중 for문을 이용해야만 했고, 첫 번째 for문을 1부터 시작해 매개변수 5만큼 반복하도록 만들었다.
그래야지 총 5개의 가로줄이 만들어지기 때문이다.
이제 각각의 가로줄 안에 별들을 차례대로 어떻게 찍냐가 문제인데 나의 경우 첫 번째 for문 안에 두 번째 for문을 만들고 해당 for문의 조건을 기준 k 변수는 0의 값을 가지고 반복되는 횟수는 첫 번째 for문의 i 보다 작게 설정했다.
첫 번째 for문의 경우, 1부터 5까지(1,2,3,4,5) 반복하고, 두 번째 for문은 첫 번째 for문의 기준 i 변수의 값이 1,2,3,4,5 순으로 1의 값만큼 커질 때 기준 k 변수의 값이 i 변수만큼 반복하게 만들었다.
이렇게 되면
i = 1 / k = 0 / 별 1개
i = 2 / k = 0 , 1 / 별 2개
i = 3 / k = 0, 1, 2 / 별 3개
.
.
이렇게 문제의 요구사항대로 별이 찍히기 때문이다.
이렇게 가로줄에 맞게 별이 찍힌다면 다음 줄로 넘겨야 한다.
두 번째 for문이 끝나면 System.out.println();
메소드를 통해 다음 줄로 넘겨주면 된다!
좌측 상단이 직각인 이등변 삼각형 만들기
// 좌측 상단이 직각인 이등변 삼각형 만들기
public static void triangleLU(int n) {
for(int i = n; i > 0; i--) {
// System.out.println(i);
for(int k = i; k > 0; k--) {
System.out.print("*");
}
System.out.println();
}
}
두 번째 문제는 첫 번째 문제의 역순으로 출력해야 하는 문제다.
메소드의 매개변수 = 콘솔에 찍힐 가로줄 개수
처음 찍히는 가로줄의 번호 = 0
마지막에 찍히는 가로줄의 번호 = 메소드의 매개변수 - 1 > 한 개의 가로줄에 찍힐 별의 개수 = 마지막에 찍히는 가로줄의 번호 - 현재 가로줄의 번호
만약 메소드의 매개변수의 값을 5라고 가정했을 때,
첫 번째(0 번째 줄)에 찍혀야 하는 별의 개수는 5개(마지막 줄 번호 - 0 번째 줄)
두 번째(1 번째 줄)에 찍혀야 하는 별의 개수는 4개(마지막 줄 번호 - 1 번째 줄)
세 번째(2 번째 줄)에 찍혀야 하는 별의 개수는 3개(마지막 줄 번호 - 2 번째 줄)
.
.
.
순으로 진행된다. 첫 번째 문제를 이해했다면 위의 설명으로 이해가 될 거라고 믿는다!
우측 상단이 직각인 이등변 삼각형 만들기
// 우측 하단이 직각인 이등변 삼각형 만들기
public static void triangleRU(int n) {
for(int i = n; i > 0; i--) {
int m = n - i;
if(m > 0) {
for(int t = 0; t < m; t++) {
System.out.print(" ");
}
}
for(int k = i; k > 0; k--) {
System.out.print("*");
}
System.out.println();
}
}
세 번째 문제부터 어려웠다. 공백을 만들어줘야 하는데, 이 부분을 일일이 작성하게 되면 반복문의 의미도 없을뿐더러 이럴 거면 컴퓨터를 사용하는 게 아니라 손으로 그림을 그리는 게 낫기 때문이다.
그래서 나는 손으로 그렸다.
1 2 3 4 5
12 3 4 51 23 4 51 2 34 51 2 3 45
핑크색의 취소선이 그어진 숫자가 공백, 배경색이 검은색인 숫자는 별이 들어가야 할 부분이다.
왜 나는 동그라미나 별 같은 모양으로 그리지 않았냐면 공백 조차도 순서가 있기 때문이다.
이렇게 별이 아닌 숫자로 그림을 그리면 규칙을 알 수 있다.
(가로줄의 첫 번째 줄의 번호가 0이라고 가정했을 때)
첫 번째 줄(0 번째 줄)에는 공백 0개(0 번째 줄 번호와 같다.), 별 5개(매개변수의 값 - 0 번째 줄)
두 번째 줄(1 번째 줄)에는 공백 1개(1 번째 줄 번호와 같다.), 별 4개(매개변수의 값 - 1 번째 줄)
.
.
.
즉, 공백의 개수는 해당 줄의 번호와 같아 그만큼 찍은 후에 별을 찍는데
별의 개수는 매개변수의 값에서 해당 줄의 번호를 뺀 만큼 반복하여 찍으면 된다.
우측 하단이 직각인 이등변 삼각형 만들기
// 우측 상단이 직각인 이등변 삼각형 만들기
public static void triangleRB(int n) {
for(int i = 1; i <= n; i++) {
int m = n - i;
if(m > 0) {
for(int t = 0; t < m; t++) {
System.out.print(" ");
}
}
for(int k = 0; k < i; k++) {
System.out.print("*");
}
System.out.println();
}
}
네 번째 문제다. 사실 가장 어려웠다. 세 번째 문제의 역순인데 왜 그렇게 역순이라는 게 머리를 쥐어 뜯게 하는지..
(카트라이더 할 때도 역순으로 가는 맵이 제일 싫었다.)
해당 문제도 메소드의 매개변수의 값을 5라고 가정했을 때,
1 2 3 451 2 34 51 23 4 512 3 4 5
1 2 3 4 5
이런 그림이 나온다. 그렇다면
(가로줄의 첫 번째 줄의 번호가 1이라고 가정했을 때)
첫 번째 줄(1 번째 줄)에는 공백 4개(매개변수의 값 - 1 번째 줄), 별 1개(1 번째 줄)
두 번째 줄(2 번째 줄)에는 공백이 3개(매개변수의 값 - 2 번째 줄), 별 2개(2 번째 줄)
세 번째 줄(3 번째 줄)에는 공백이 2개(매개변수의 값 - 3 번째 줄), 별 3개(3 번째 줄)
.
.
순으로 반복된다. 해당 문제는 첫 번째 줄의 번호가 1번이라고 가정하고 풀었을 때 이해가 잘됐다.
규칙을 찾아 떠나는 여행
학원을 다니면서 강사님께서 항상 이런 문제에 마주하게 되면 먼저 규칙을 찾아보라고 말씀하셨는데
나는 청개구리 습성이 있어서 곧 죽어도 머리로만 상상하고 풀려고 했다.
근데 오늘 막상 해보니 왜 규칙을 찾고 코드로 풀어보라고 하셨는지 알겠다.
거기에 한술 더 떠서 내가 푼 문제를 이렇게 그림 + 글로 풀어서 설명하면 할수록 내 코드가 복잡한 코드일 수 있겠다는 생각이 든다.
남들에게는 정말 아무것도 아닌 문제지만 나에게는 적어도 북한산 같은 느낌의 문제였는데 여기까지 올 수 있게 되다니,
여러모로 나 자신을 칭찬하고 싶다. 앞으로 더 꾸준히 노력해야겠다고 다짐하며 글을 마친다!