본문 바로가기

자바 자료구조 & 알고리즘/Do it! 자료구조와 함께 배우는 알고리즘 입문 (자바편)

Do it! 자료구조와 함께 배우는 알고리즘 입문 : 1장 기본 알고리즘

 알고리즘이란? 

세 값의 최댓값

실습 1-1 

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Max3 {
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    
    System.out.println("세 정수의 최댓값 구합니다.");
    System.out.print("a의 값 : "); int a = stdIn.nextInt();
    System.out.print("b의 값 : "); int b = stdIn.nextInt();
    System.out.print("c의 값 : "); int c = stdIn.nextInt();
    
    int max = a;
    if (b > max) max = b;
    if (c > max) max = c;
    
    System.out.println("최댓값은 " + max + "입니다.");
  }
}

문장(Process)의 구조

  • 순차적 구조(Concatenation) : 여러 문장이 순차적으로 실행되는 구조
  • 선택 구조(Selection) : () 안에 있는 식의 평가 결과에 따라 프로그램의 실행 흐름을 변경하는 if문 

 

순서도(flowchart)

 

순서도 (flowchart)

검은 선을 따라 위에서 아래로 향하고, 그 과정에서 사각형 안에 작성한 처리 과정이 실행된다.

마름모를 지날 때는 그 안에 작성된 조건을 평가한 결과에 따라 Yes, No 중 하나를 따라간다.

이처럼 두 갈래 중 어느 한쪽을 지나게 되는 시점. 즉 if문에 의한 프로그램 흐름의 분기를 쌍기 선택이라고 한다.

사각형안에 → 가 있는 경우가 있는데 이를 이것은 대입을 뜻한다. 즉, 왼쪽 변수에 들어있는 값을 오른쪽 변수에 대입하겠다는 의미이다.

 

알고리즘의 정의

문제를 해결하기 위한 것으로, 명확하게 정의되고 순서가 있는 유한 개의 규칙으로 이루어진 집합

 

변수의 값에 따라 결과가 맞기도 하고, 틀리기도 한다면 올바른 알고리즘이 아니다. 모든 경우의 수에 대하여 일관적인 결과를 도출해내야한다. 따라서 해당 알고리즘이 올바른지 확인하기 위해 모든 경우의 수에 대하여 메서드를 평가할 수 있는 테스트가 필요하다.

 

보통 알고리즘을 하나의 메서드로 만들고 이를 테스트 하기 위해 main 메서드에서 해당 메서드를 실행하는 코드를 작성한다.


연습 문제

Q1. 네 값의 최댓값을 구하는 max4 메서드를 작성하세요..

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q1 {
  
  static int max4(int a, int b, int c, int d) {
    int max = a;
    
    if (max < b) {
      max = b;
    }
    
    if (max < c) {
      max = c;
    }
    
    if (max < d) {
      max = d;
    }
    
    return max;
  }
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int a = sc.nextInt();
    int b = sc.nextInt();
    int c = sc.nextInt();
    int d = sc.nextInt();
    
    System.out.println(max4(a, b, c, d));
  }
}

Q2. 세 값의 최솟값을 구하는 min3 메서드를 작성하세요.

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q2 {
  
  static int min3(int a, int b, int c) {
    int max = a;
    
    if (max > b) {
      max = b;
    }
    
    if (max > c) {
      max = c;
    }
       
    return max;
  }
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int a = sc.nextInt();
    int b = sc.nextInt();
    int c = sc.nextInt();
    
    System.out.println(min3(a, b, c));
  }
}

Q3. 네 값의 최솟값을 구하는 min4 메서드를 작성하세요.

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q3 {
  
  static int min4(int a, int b, int c, int d) {
    int max = a;
    
    if (max > b) {
      max = b;
    }
    
    if (max > c) {
      max = c;
    }
    
    if (max > d) {
      max = d;
    }
       
    return max;
  }
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int a = sc.nextInt();
    int b = sc.nextInt();
    int c = sc.nextInt();
    int d = sc.nextInt();
    
    System.out.println(min4(a, b, c, d));
  }
}

결정 트리(Decision Tree)

실습 1-1 에서 세 값의 대소 관계의 조합은 총 13가지 종류가 있다. 그림 1C - 4는 조합을 나열한 것인데 이와 같은 그림을 조합을 나열한 모양이 나무 형태라고 하여 결정 트리(Decision Tree)라고 부른다.


세 값의 중앙값

실습 1C-1 

다음은 세 값이 주어졌을 때 그 중앙값을 구하는 프로그램이다.

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Median {
  static int med3(int a, int b, int c) {
    if (a >= b)
      if (b >= c)
        return b;
      else if (a <= c)
        return a;
      else
        return c;
    else if (a > c)
      return a;
    else if (b > c)
      return c;
    else
      return b;
  }
  
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    
    System.out.print("a의 값 : "); int a = stdIn.nextInt();
    System.out.print("b의 값 : "); int b = stdIn.nextInt();
    System.out.print("c의 값 : "); int c = stdIn.nextInt();
    
    System.out.println("중앙값은 " + med3(a, b, c) + "입니다.");
  }
}

* 세 값의 중앙값을 구하는 과정은 퀵 정렬에서도 사용된다.


연습 문제

Q4. 세 값의 대소 관계 13종류의 모든 조합에 대해 중앙값을 구하여 출력하는 프로그램을 작성하세요.

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q4 {
  static int med3(int a, int b, int c) {
    if (a >= b)
      if (b >= c)
        return b;
      else if (a >= c)
        return c;
      else
        return a;
    else if (a >= c)
      return a;
    else if (b <= c)
      return b;
    else
      return c;
  }
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    
    int a = sc.nextInt();
    int b = sc.nextInt();
    int c = sc.nextInt();
    
    System.out.println(med3(a, b, c));
  }
}

Q5. 중앙값을 구하는 메서드는 다음과 같이 작성할 수도 있습니다. 그러나 실습 1C-1의 med3 메서드에 비해 효율이 떨어지는데, 그 이유를 설명하시오.

 

내 답변

1C-1의 med3 메서드는 아무리 많아도 세번의 대소 비교를 거친다. 그러나 다음 메서드는 최대 8번의 대소 비교를 하는 경우가 있기 때문에 다음 메서드가 더 효율이 떨어진다.

 

정답

가장 처음의 if문의 판단 if ((b >= a && c<= a) || (b <= a && c >= a))에 주목합니다.

여기서 b >= a 및 b <= a의 판단을 뒤집은 판단(실질적으로 같은 판단)을

이어지는 else 이후의  else if ((a > b && c < b) || (b <= a && c > b)) 으로 수행합니다.

결국 가장 처음의 if가 성립한 경우 2 번째의 if에서도 (실질적으로)같은 판단을 수행하므로 효율이 나빠집니다.


조건 판단과 분기

실습 1-3

package com.heejin.doit.ex01;

import java.util.Scanner;

public class JudgeSign {
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    
    System.out.print("정수를 입력하세요. : ");
    int n = stdIn.nextInt();
    
    if (n > 0)
      System.out.println("이 수는 양수입니다.");  // -> 1
    else if (n < 0)
      System.out.println("이 수는 음수입니다.");  // -> 2
    else
      System.out.println("이 수는 0입니다.");  // -> 3
  }
}

위의 프로그램은 입력 받은 숫자의 절댓값을 구한다. 변수 n의 값이 양수면 1, 음수면 2, 0이면 3이 실행된다. 그 어떤 경우에도 두 가지가 동시에 실행되거나 한번도 실행되지 않는 일은 없다. 프로그램이 세가지로 분기하기 때문이다. 

 

위의 코드에서 if문 - else if문 - else문을 다음과 같이 바꾸면 결과는 세가지 분기가 아니라 네가지 분기로 바뀐다. 즉, 이 코드는 마지막에 else 가 붙는 것이랑 같은 결과를 도출한다.

if (n ==1)
      System.out.println("이 수는 1입니다.");
    else if (n == 2)
      System.out.println("이 수는 2입니다.");
    else if (n == 3)
      System.out.println("이 수는 3입니다.");
 // else;

순서도의 기호

 

데이터

데이터의 입력과 출력을 나타낸다.

 

 

 

처리

여러 종류의 처리 기능, 즉 연산이나 연산집합의 실행 또는 연속적인 몇가지 흐름 가운데 하나의 방향을 결정하는 연산집합이나 연산군의 실행을 의미한다.

 

 

 

미리 정의한 처리

서브루틴 및 모듈 등 다른 곳에서 이미 정의한 하나 이상의 연산 또는 명령어들로 이뤄진 처리를 의미한다.

 

 

판단

하나의 입구와 하나 이상을 선택할 수 있는 출구가 있고, 기호에서 정의한 조건을 평가하여 하나의 출구를 선택하는 판단 기능을 의미한다.

 

 

루프 범위

루프의 시작과 종료를 나타낸다. 

기호의 두 부분에는 같은 이름을 사용한다.

루프의 시작 기호 또는 종료 기호 안에 초깃값, 증갓값, 종룟값을 표기한다.

 

 

 

 

 

단말

외부 환경을 나가거나 외부 환경에서 들어오는 것을 나타낸다. 

가령 프로그램 흐름과 시작과 종료를 나타낸다.

 

 

 

- 선은 제어의 흐름을 나타내고 주로 흐름의 방향을 분명히 할 때는 화살표를 붙인다.


 반복 

1부터 n까지의 정수 합 구하기

실습 1-4

public class SumWhile {
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    
    System.out.println("1부터 n까지의 합을 구합니다.");
    System.out.print("n의 값 : ");
    int n = stdIn.nextInt();
    
    int sum = 0;
    int i = 1;
    
    while (i <= n) {
      sum += i;
      i++;
    }
    System.out.println("1부터 " + n + "까지의 합은 " + sum + "입니다.");
  }
}

위의 프로그램은 1부터 n까지의 정수합을 구하는 알고리즘이다. 

 

while 문의 반복

어떤 조건이 성립하는 동안 처리를 반복하여 실행하는 것을 반복 구조(repetition)라고 하며 일반적으로 루프(loop)라고 부른다. 이 때 while문은 실행 전에 반복을 계속 할지 판단하는데, 이런 구조를 사전 판단 반복 구조라고 부른다. 제어식의 평갓값이 false, 즉 0이 아니면 명령문이 계속 반복된다. 

 

위의 코드에서 제어식은 i <= n 이며, 제어식은 순서도에서 마름모 도형 안에 나타난다. 

 

위의 반복문을 돌리면 제어식을 만나는 순간의 i와 sum의 값은 다음 표와 같다.

sum
1 0
2 1
3 3
4 6
5 10
6 15

sum의 값은 루프 본문을 수행하는 동안의 합이며, i의 값은 다음에 더할 값이다.

따라서 i가 5면 sum은 1부터 4까지 더한 값이 된다.

또한 i가 n을 초과할 때 while문이 종료되기 때문에 최종 i 값은 n이 아니라, n + 1이다.


연습 문제

Q6. 실습 1-4에서 while문이 종료될 때 변수 i 값이 n + 1이 됨을 확인하세요. (변수 i 값을 출력하도록 프로그램을 수정하세요.)

public class SumWhile {
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    
    System.out.println("1부터 n까지의 합을 구합니다.");
    System.out.print("n의 값 : ");
    int n = stdIn.nextInt();
    
    int sum = 0;
    int i = 1;
    
    while (i <= n) {
      sum += i;
      i++;
    }
    System.out.println("i의 값은 " + i);
    System.out.println("1부터 " + n + "까지의 합은 " + sum + "입니다.");
  }
}

for 문 반복

실습 1-5

하나의 변수를 사용하는 반복문은 while문보다 for문을 사용하는 것이 좋다. 실습 1-4 에 있던 while문을 다음과 같이 바꿀 수 있다.

package com.heejin.doit.ex01;

import java.util.Scanner;

public class SumFor {
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    
    System.out.println("1부터 n까지의 합을 구합니다.");
    System.out.print("n의 값 : ");
    int n = stdIn.nextInt();
    
    int sum = 0;
    
    for (int i = 1; i <= n; i++) {
      sum += i;
    }
    System.out.println("1부터 " + n + "까지의 합은 " + sum + "입니다.");
  }
}


연습 문제

Q7. 실습 1-5 프로그램을 참고하여 n이 7이면 '1 + 2 + 3 + 4 + 5 + 6 + 7 = 28'로 출력하는 프로그램을 작성하세요.

public class Q7 {
  static int plus(int max) {
    int sum = 0;
    for (int i = 1; i <= max; i++) {
      sum += i;
    }
    return sum;
  }
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.println(plus(sc.nextInt()));
  }
}

Q8. 1부터 10까지의 합은 (1 + 10) * 5와 같은 방법으로 구할 수 있습니다. 가우스의 덧셈이라는 방법을 이용하여 1부터 n까지의 정수 합을 구하는 프로그램을 작성하세요.

public class Q8 {
  static int plus(int max) {
    return (int) ((1 + max) * max / 2.0f);
  }
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.println(plus(sc.nextInt()));
  }
}

Q9. 정수 a, b를 포함하여 그 사이의 모든 정수의 합을 구하여 반환하는 아래 메서드를 작성하세요.(단, a와 b의 대소 관계에 상관없이 합을 구하세요.)

public class Q8 {
  static int plus(int a, int b) {
      return (int) ((a + b) * (b - a + 1) / 2.0f);
  }
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    System.out.println(plus(sc.nextInt(), sc.nextInt()));
  }
}

 


양수만 입력하기

실습 1-6

실습 1-5의 프로그램에 음수를 넣으면 유효한 결과를 도출하지 않는다. 따라서 양수만 입력하도록 입력을 제한시키기 위해서 do/while문을 사용한다.

public class SumForPos {
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    int n;
    
    do {
      System.out.println("n의 값 : ");
      n = stdIn.nextInt();
    } while (n <= 0);
    
    int sum = 0;
    
    for (int i = 0; i <= n; i++)
      sum += i;
    
    System.out.println("1부터 " + n + "까지의 합은 " + sum + "입니다."); 
  }
}

 

사후 판단

do/while문과 같이 일단 루프 본문을 한번 실행한 다음에 계속 반복할 것인지 판단하는 방식을 사후 판단이라고 한다.

사전 판단은 제어식을 평가한 결과가 0이면 루프 본문은 한 번도 실행되지 않지만, 사후 판단 반복은 루프 본문이 반드시 한 번은 실행되는 것이 차이점이다.


연습문제

Q10. 오른쪽과 같이 두 변수 a,b에 정수를 입력하고 b - a를 출력하는 프로그램을 작성하세요.(단, 변수 b에 입력한 값이 a 이하면 변수 b의 값을 다시 입력하세요.)

public class Q10 {
  public static void main(String[] args) {
    minus();
  }
  
  static void minus() {
    Scanner sc = new Scanner(System.in);
    System.out.print("a의 값 : ");
    int a = sc.nextInt();
    int b;
    do {
      System.out.print("b의 값 : ");
      b = sc.nextInt();
      if (b <=a) {
        System.out.println("a보다 큰 값을 입력하세요!");
      }
    } while (b <= a);
    System.out.println("b - a는 " + (b - a) + "입니다.");
  }
}

Q11. 양의 정수를 입력하고 자릿수를 출력하는 프로그램을 작성하세요. 예를 들어 135를 입력하면 '그 수는 3자리입니다.'라고 출력하고 1314를 입력하면 '그 수는 4자리입니다.'라고 출력하면 됩니다.

public class Q11 {
  static Scanner sc = new Scanner(System.in);
  
  public static void main(String[] args) {
    getJari2();
  }
  static void getJari() {
    String str = sc.next();
    System.out.println("그 수는 " + str.length() + "자리입니다.");
    
  }
  
  static void getJari2() {
    int ten = 1;
    int count = 0;
    int n = sc.nextInt();
    while (n >= ten) {
      count++;
      ten *= 10;
    }
    System.out.println("그 수는 " + count + "자리입니다.");
  }
}

구조적 프로그래밍

하나의 입구와 하나의 출구를 가진 구성 요소만을 계층적으로 배치하여 프로그램을 구성하는 방법을 구조적 프로그래밍이라고 한다. 구조적 프로그래밍은 순차, 선택, 반복이라는 3종류의 제어 흐름을 사용한다.


논리 연산과 드모르간 법칙

실습 1C-2

public class Digits {
  public static void main(String [] args) {
    Scanner stdIn = new Scanner(System.in);
    int no;
    
    System.out.println("2자리의 정수를 입력하세요.");
    
    do {
      System.out.print("입력 : ");
      no = stdIn.nextInt();
    } while (no < 10 || no > 99);
    
    System.out.println("변수 no의 값은 " + no + "가(이) 되었습니다.");
  }
}

위의 프로그램은 입력한 값을 2자리의 양수로 제한하는 프로그램이다. 여기서 사용하는 ||는 논리합을 구하는 논리합 연산자이다. 논리 연산을 하는 또다른 연산자로 논리곱을 구하는 논리곱 연산자 &&가 있다. 

 

드모르간 법칙

!(a || b) = !a && !b
!(a && b) = !a && !b

a || b = !(!a && !b)
a && b = !(!a && !b)

어떤 조건의 부정은 그것을 구성하는 각 조건을 부정하고 논리곱을 논리합으로, 논리합을 논리곱으로 바꾼 조건과 같다.

 

이 법칙에 따라 1C-2의 while조건의 제어식을 수정하면 !(no >= 10 && n <= 99)가 될 수 있다. 


다중 루프

루프 안에서 또 다른 루프가 있을 수 있는데 이를 다중 루프라고 하며, 루프가 중첩되는 수준에 따라 '이중 루프, 삼중 루프'라고 한다.

 

곱셈표

실습 1-7

다음은 이중 루프를 사용하는 알고리즘의 예로 곱셈표를 출력하는 프로그램이다.

public class Multi99Table {
  public static void main(String[] args) {
    
    System.out.println("------곱셈표------");
    
    for (int i = 1; i <= 9; i++) {
      for (int j = 1; j <= 9; j++) {
        System.out.printf("%-3d", i * j);
      }
      System.out.println();
    }
  }
}

이 이중 루프는 다음과 같이 처리된다.

i가 1일 때 : j를 1 => 9로 증가시키면서 1 * j를 출력한다. 그리고 줄을 바꾼다.

i가 2일 때 : j를 1 => 9로 증가시키면서 2 * j를 출력한다. 그리고 줄을 바꾼다.

i가 3일 때 : j를 1 => 9로 증가시키면서 3 * j를 출력한다. 그리고 줄을 바꾼다.

i가 4일 때 : j를 1 => 9로 증가시키면서 4 * j를 출력한다. 그리고 줄을 바꾼다.

.

.

.

 

순서도는 다음과 같다.


연습 문제

Q12. 오른쪽과 같이 위쪽과 왼쪽에 곱하는 수가 있는 곱셈표를 출력하는 프로그램을 작성하세요. (구분선은 수직선 기호 (|), 마이너스 기호 (-), 플러스 기호 (+)를 사용하세요.)

public class Q12 {
  public static void main(String[] args) {
    multipleLineTable();
  }
  
  static void multipleLineTable() {
    System.out.print("  |");
    for (int i = 1; i <= 9; i++)
      System.out.printf("%3d", i);
    System.out.println("\n--+---------------------------");
    for (int i = 1; i <= 9; i++) {
      System.out.printf("%d |", i);
      for (int j = 1; j <= 9; j++) {
        System.out.printf("%3d", i * j);
      }
      System.out.println();
    }
  }
}

Q13. 곱셈이 아니라 덧셈을 출력하는 프로그램을 작성하세요. (Q12와 같이 위쪽과 왼쪽에 더하는 수를 출력하세요.)

package com.heejin.doit.ex01;

public class Q13 {
  public static void main(String[] args) {
    multipleLineTable();
  }
  
  static void multipleLineTable() {
    System.out.print("  |");
    for (int i = 1; i <= 9; i++)
      System.out.printf("%3d", i);
    System.out.println("\n--+---------------------------");
    for (int i = 1; i <= 9; i++) {
      System.out.printf("%d |", i);
      for (int j = 1; j <= 9; j++) {
        System.out.printf("%3d", i + j);
      }
      System.out.println();
    }
  }
}

Q14. 오른쪽과 같이 입력한 수를 한 변으로 하는 정사각형을 * 기호로 출력하는 프로그램을 작성하세요.

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q14 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    square(n);
  }
  
  static void square(int n) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++)
        System.out.print("* ");
      System.out.println();
    }
  }
}

 


직각 이등변 삼각형 출력

실습 1-8

이중 루프를 응용하면 기호를 늘어놓아 삼각형이나 사각형 모양으로 출력할 수 있다. 다음은 왼쪽 아래가 직각인 이등변 삼각형을 출력하는 프로그램이다.

public class TriangleLB {
  public static void main(String[] args) {
    Scanner stdIn = new Scanner(System.in);
    int n;
    
    System.out.println("왼쪽 아래가 직각인 이등변 삼각형을 출력합니다.");
    
    do {
      System.out.printf("몇 단 삼각형입니까? : ");
      n = stdIn.nextInt();
    } while (n <= 0);
    
    for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= i; j++)
        System.out.print("* ");
      System.out.println();
    }
  }
}

이 프로그램에서 이중 루프는 다음과 같이 처리된다.

i가 1 일 때 : j를 1 => 1로 증가시키면서 *를 출력한다. 그리고 줄을 바꾼다.

i가 2 일 때 : j를 1 => 2로 증가시키면서 *를 출력한다. 그리고 줄을 바꾼다. 

i가 3 일 때 : j를 1 => 3로 증가시키면서 *를 출력한다. 그리고 줄을 바꾼다. 

i가 4 일 때 : j를 1 => 4로 증가시키면서 *를 출력한다. 그리고 줄을 바꾼다. 

.

.

.

이 프로그램의 순서도는 다음과 같다. 

 


연습문제

Q15. 직각 이등변 삼각형을 출력하는 부분을 아래와 같은 형식의 메서드로 작성하세요.(왼쪽 아래가 직각인 이등변 삼각형을 출력) 또 왼쪽 위, 오른쪽 위, 오른쪽 아래가 직각인 이등변 삼각형을 출력하는 메서드를 작성하세요.

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q15 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    triangleLB(n);
    System.out.println("--------------");
    triangleLU(n);
    System.out.println("--------------");
    triangleRU(n);
    System.out.println("--------------");
    triangleRB(n);
  }
  static void triangleLB(int n) {
    for (int i = 1; i <= n; i++) {
      for (int j = 0; j < i; j++)
        System.out.print("*");
      System.out.println();
    }
  }
  static void triangleLU(int n) {
    for (int i = n; i >= 1; i--) {
      for (int j = 0; j < i; j++)
        System.out.print("*");
      System.out.println();
    }
  }
  static void triangleRU(int n) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < i; j++)
        System.out.print(" ");
      for (int j = 0; j < n - i; j++)
        System.out.print("*");
      System.out.println();
    }
  }
  static void triangleRB(int n) {
    for (int i = 1; i <= n; i++) {
      for (int j = 0; j < n - i; j++)
        System.out.print(" ");
      for (int j = 0; j < i; j++)
        System.out.print("*");
      System.out.println();
    }
  }
}

Q16. n단의 피라미드를 출력하는 메서드를 작성하세요.(i행에는 (i - 1) * 2 + 1개의 기호 문자 *가 출력되게 하세요.)

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q16 {
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    spira(n);
  }
  
  static void spira(int n) {
    for (int i = 1; i <= n; i++) {
      for (int j = 0; j < n - i; j++)
        System.out.print(" ");
      for (int j = 0; j < (i - 1) * 2 + 1; j++)
        System.out.print("*");
      System.out.println();
    }
  }
}

Q17. 오른쪽과 같이 아래를 향한 n단의 숫자 피라미드를 출력하는 메서드를 작성하세요.(i행에 출력하는 숫자는 i % 10으로 구하세요.)

package com.heejin.doit.ex01;

import java.util.Scanner;

public class Q16 {
  
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    npira(n);
  }
  
  static void npira(int n) {
    for (int i = 1; i <= n; i++) {
      for (int j = 0; j < n - i; j++)
        System.out.print(" ");
      for (int j = 0; j < (i - 1) * 2 + 1; j++)
        System.out.print(i);
      System.out.println();
    }
  }
}