for(int i=0; i<board.length; i++){
    sum1=sum2=0;
    for(int j=0; j<board.length; j++){
        sum1 += board[i][j]; // 행의 합
        sum2 += board[j][i]; // 열의 합
    }
    answer = Math.max(answer, sum1);
    answer = Math.max(answer, sum2);
}

sum1=sum2=0;

// 대각선의 합 
for(int i=0; i<board.length; i++){
    sum1 += board[i][i];
    sum2 += board[i][board.length-i-1];
}

정수를 한자리씩 쪼개는 방법

- 10으로 나눠서 나머지를 구한다.

- answer에 10을 곱해줘서 자리를 앞으로 옮겨주고 구한 나머지를 더해준다. (첫번째 값의 경우 0 X 10 + 나머지) 

- 10으로 나눠서 몫을 구한다.

- 남은 몫이 0이 될때까지 앞의 과정을 반복한다. 

 

1230%10 = 0 -> 1230/10 = 123
123%10 = 3 -> 123/10 = 12
12%10 = 2 -> 12/10 = 1
1%10 = 1 -> 1/10 = 0

 

예시 코드

for(int i=0; i<arr.length; i++) {
    int temp = arr[i];
    int answer = 0;
    while (temp > 0) {
        int element = temp % 10;
        answer = answer * 10 + element;
        temp = temp / 10;
    }
}

에라토스테네스의 체

- 특정 범위 내의 소수를 찾을 때 사용하는 방법이다.

 

 

1. 1부터 N까지의 배열을 만든다. -> ex. int[] arr = {0,0,0,0,0,0,.....};

2. 소수가 아닌 1은 제거한다.

3. N까지 반복문을 돌려주면서 int[i] = 0인 값들에서 count++ 해준다.

- 2에서 count++; 

- 2의 배수는 모두 값을 1로 바꿔준다.

 

- 3에서 count++;

- 3의 배수는 모두 값을 1로 바꿔준다.

 

- 4의 배수는 2의 배수를 1로 바꿔주는 과정에서 바뀌었기 때문에 넘어간다.

....

- 마지막에 count를 출력해주면 그 값이 1부터 N까지의 소수 개수

 

 

에라토스테네스 체 사용

public static int solution(int n){
    int count = 0;
    int[] check = new int[n+1];

    for(int i=2; i<=n; i++){
        if(check[i]==0){
            count++;
            // i의 (j+i)배수들을 체크해준다.
            for(int j=i; j<=n; j=j+i){
                check[j] = 1;
            }
        }
    }

    return count;
}

 

 

소수 판별 코드

public static boolean isPrime(int num){
    if(num==1) return false; // 1은 소수가 아니다.
    for(int i=2; i<num; i++){
        if(num%i==0){ // i는 num의 약수가 된다.
            return false;
        }
    }
    return true;
}

이론 정리

연산자

  • 연산에 사용되는 표시나 기호
  • 피연산자 : 연산되는 데이터
  • 단항, 이항, 삼항 연산자 순서의 우선순위
  • 산술, 비교, 논리, 대입 연산자 순서의 우선순위
  • ++a 속도가 a=a+1 속도보다 빠르다.

String 타입

  • 참조형 타입

비트 연산자

  • 데이터를 bit 단위로 연산
  • 정수 타입만 가능
  • 비트 논리 연산자, 비트 이동 연산자

삼항 연산자

  • 세개의 피연산자를 필요로 하는 연산자
// 조건식 ? 값 또는 연산식(true) : 값 또는 연산식(false)
char grade = (score > 90) ? 'A' : ((score > 80) ? 'B' : 'C');

연습문제

[3-1] 다음 연산의 결과를 적으시오.

class Exercise3_1 {
    public static void main(String[] args){
        int x = 2;
        int y = 5;
        char c = 'A'; // 'A'의 문자 코드는 65
        
        System.out.println(1 + x << 33);
        System.out.println(y >= 5 || x < 0 && x > 2);
        System.out.println(y += 10 - x++);
        System.out.println(x+=2);
        System.out.println(!('A' <= c && c <= 'Z'));
        System.out.println('C'-c);
        System.out.println('5'-'0');
        System.out.println(c+1);
        System.out.println(++c);
        System.out.println(c++);
        System.out.println(c);
    }
}
  • 풀이
  • 1. 1+2 (3를 33만큼 왼쪽으로 이동 -> (32+1bit)1번만 이동 0011 -> 0110 = 6 2. true || false && false = false 논리연산자 &&가 ||보다 우선순위가 더 높다 true || true = true 3. 15-2++ = 13 4. (2++) + 2 = 5 5. !(true && true) = false 6. 67-65 = 2 7. 5 8. 66 9. B 10. B 11. C

[3-2] 아래의 코드는 사과를 담는데 필요한 바구니(버켓)의 수를 구하는 코드이다. 만일 사과의 수가 123개이고 하나의 바구니에는 10개의 사과를 담을 수 있다면, 13개의 바구니가 필요할 것이다. (1)에 알맞은 코드를 넣으시오.

class Exercise3_2 {
    public static void main(String[] args){
        int numOfApples = 123; // 사과의 개수
        int sizeOfBucket = 10; 
// 바구니의 크기(바구니에 담을 수 있는 사과의 개수)
        int numOfBucket = ( /*(1)*/ ); 
// 모든 사과를 담는데 필요한 바구니의 수
        
        System.out.println("필요한 바구니의 수 :"+numOfBucket);
    }
}
[실행결과]
13
  • 풀이
  • // numOfApples/sizeOfBucket+1; 반례 : 나머지가 0 인경우 ((numOfApples/sizeOfBucket)==0) ? numOfApples/sizeOfBucket : numOfApples/sizeOfBucket+1

[3-3] 아래는 변수 num의 값에 따라 ‘양수’, ‘음수’, ‘0’을 출력하는 코드이다. 삼항 연산자를 이용해서 (1)에 알맞은 코드를 넣으시오. (삼항 연산자 2번 사용)

class Exercise3_3 {
    public static void main(String[] args){
        int num = 10;
        System.out.println( /* (1) */ );
    }
}
[실행결과]
양수
  • 풀이
  • (num>0) ? "양수" : ((num<0) ? "음수" : '0')

[3-4] 아래는 변수 num의 값 중에서 백의 자리 이하를 버리는 코드이다. 만일 변수 num의 값이 ‘456’이라면 ‘400’이 되고, ‘111’이라면 ‘100’이 된다. (1)에 알맞은 코드를 넣으시오.

class Exercise3_4 {
    public static void main(String[] args){
        int num = 456;
        System.out.println( /* (1) */ );
    }
}
[실행결과]
400
  • 풀이
  • (num/100)*100

[3-5] 아래는 변수 num의 값 중에서 일의 자리 1로 바꾸는 코드이다. 만일 변수 num의 값이 ‘333’이라면 ‘331’이 되고, ‘777’이라면 ‘771’이 된다. (1)에 알맞은 코드를 넣으시오.

class Exercise3_5 {
    public static void main(String[] args){
        int num = 333;
        System.out.println( /* (1) */ );
    }
}
[실행결과]
331
  • 풀이
  • ((num/10)*10)+1

[3-6] 아래는 변수 num의 값보다 크면서도 가장 가까운 10의 배수에서 변수 num의 값을 뺀 나머지를 구하는 코드이다. 예를 들어, 24의 크면서도 가장 가까운 10의 배수는 30이다. 19의 경우 20이고, 81의 경우 90이 된다. 30에서 24를 뺀 나머지는 6이기 때문에 변수 num의 값이 24라면 6을 결과로 얻어야 한다. (1)에 알맞은 코드를 넣으시오.

class Exercise3_6 {
    public static void main(String[] args){
        int num = 24;
        System.out.println( /* (1) */ );
    }
}
[실행결과]
6
  • 풀이
  • (((num/10)+1)*10) - num

[3-7] 아래는 화씨(Fahrenheit)를 섭씨(Celsius)로 변환하는 코드이다. 변환공식이 ‘C’ = 5/9 x (F - 32)’ 라고 할 때, (1)에 알맞은 코드를 넣으시오. 단, 변환 결과값은 소수점 셋째자리에서 반올림해야한다. (Math.round()를 사용하지 않고 처리할 것)

class Exercise3_7 {
    public static void main(String[] args){
        int fahrenheit = 100;
        float celcius = ( /* (1) */ );

        System.out.println("Fahrenheit:"+fahrenheit);
        System.out.println("Celcius:"+celcius);
    }
}
[실행결과]
Fahrenheit:100
Celcius:37.78
  • 풀이
  • (int)((5/9f * (fahrenheit - 32))*100 + 0.5) / 100f; // 1. 37.77778 * 100 // 2. (1)+0.5 // 3. (int)(2) // 4. (3)/100f

[3-8] 아래 코드의 문제점을 수정해서 실행결과와 같은 결과를 얻도록 하시오.

class Exercise3_8 {
    public static void main(String[] args){
        byte a = 10;
        byte b = 20;
        byte c = a + b;

        char ch = 'A';
        ch = ch + 2;

        float f = 3/2;
        long l = 3000 * 3000 * 3000;

        float f2 = 0.1f;
        double d = 0.1;

        boolean result = d==f2;

        System.out.println("c="+c);
        System.out.println("ch="+ch);
        System.out.println("f="+f);
        System.out.println("l="+l);
        System.out.println("result="+result);
    }
}
[실행결과]
c=30
ch=C
f=1.5
l=27000000000
result=true
  • 풀이
  • byte c = (byte)(a + b); ch = (char)(ch + 2); float f = 3/2f; long l = 3000 * 3000 * 3000L; boolean result = (float)d==f2;

[3-9] 다음은 문자형 변수 ch가 영문자(대문자 또는 소문자)이거나 숫자일 때만 변수 b의 값이 true가 되도록 하는 코드이다. (1)에 알맞은 코드를 넣으시오.

class Exercise3_9 {
    public static void main(String[] args){
        char ch = 'z';
        boolean b = ( /* (1) */ );
        System.out.println(b);
    }
}
[실행결과]
true
  • 풀이
  • (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')

[3-10] 다음은 대문자를 소문자로 변경하는 코드인데, 문자 ch에 저장된 문자가 대문자인 경우에만 소문자로 변경한다. 문자코드는 소문자가 대문자보다 32만큼 더 크다. 예를들어 ‘A’의 코드는 65이고, ‘a’의 코드는 97이다. (1)~(2)에 알맞은 코드를 넣으시오.

class Exercise3_10 {
    public static void main(String[] args){
        char ch = 'A';
        char lowerCase = ( /* (1) */ ) ? ( /* (2) */ ) : ch;

        System.out.println("ch:"+ch);
        System.out.println("ch to lowerCase:"+lowerCase);
    }
}
[실행결과]
ch:A
ch to lowerCase:a
  • 풀이
  • (ch >= 65 && ch < 97) ? (char)(ch+32)

이론 정리

변수(variable)

  • 값을 저장할 수 있는 메모리의 공간
  • 첫 번째 글자는 문자 or ‘&’, ‘_’ → 숫자, 예약어 불가능

리터럴(literal)

  • 소스 코드 내에서 직접 입력된 값
  • 정수, 실수, 문자, 논리 리터럴

데이터 타입

  • 기본 타입(primitive) : 정수, 실수, 문자, 논리 리터럴을 직접 저장하는 타입
    • 정수 타입(byte, char, short, int, long)
    • 실수 타입(float, double)
    • 논리 타입(boolean)

타입 변환

  • 자동(묵시적) 타입 변환
    • byte → char(음수X) : 불가능
  • 강제(명시적) 타입 변환 = 캐스팅(casting)
    • int → char : 불가능
    • 실수 → 정수 : 소수점이 버려진다.

연습문제

[2-1] 다음 표의 빈 칸에 8개의 기본형(primitive type)을 알맞은 자리에 넣으시오.

  • 풀이1byte2byte4byte8byte
    논리형 boolean      
    문자형   char    
    정수형 byte short int long
    실수형     float double

[2-2] 주민등록번호를 숫자로 저장하고자 한다. 이 값을 저장하기 위해서는 어떤 자료형(data type)을 선택해야 할까? regNo라는 이름의 변수를 선언하고 자신의 주민등록번호로 초기화 하는 한 줄의 코드를 적으시오.

  • 풀이
    long regNo = 1234561234567L; 
    // long타입 컴파일러에게 4byte가 아닌 8byte를 알려주기 위해 L를 뒤에 붙여준다.
    
  • 예시) 123456-1234567 = 13자리

[2-3] 다음의 문장에서 리터럴, 변수, 상수, 키워드를 적으시오.

int i = 100;
long l = 100L;
final float PI = 3.14f;
  • 리터럴 :
  • 변수 :
  • 키워드 :
  • 상수 :
  • 풀이
    • 리터럴 : 100, 100L, 3.14f
    • 변수 : i, l
    • 키워드 : int, long, final, float
    • 상수 : PI

[2-4] 다음 중 기본형(primitive type)이 아닌 것은?

  1. int
  2. Byte
  3. double
  4. boolean
  • 풀이
    • 기본형X : b(Byte) → byte
    • 기본형 : a(int), c(double), d(boolean)

[2-5] 다음 문장들의 출력결과를 적으세요. 오류가 있는 문장의 경우, 괄호 안에 ‘오류’ 라고 적으시오.

System.out.println("1" + "2") -> ( 12 )
System.out.println(true + "") -> ( true )
System.out.println('A' + 'B') -> ( 131 )
System.out.println('1' + 2) -> ( 51 )
System.out.println('1' + '2') -> ( 99 )
System.out.println('J' + "ava") -> ( Java )
System.out.println(true + null) -> ( 오류 )
  • 풀이
  • “1” + “2” = 12
  • ‘A’ + ‘B’ = 65 + 66 = 131
  • ‘1’ + ‘2’ = 49 + 50 = 99
  • true + null = 오류
    • 문자와 숫자가 같이 쓰일 때, 자동으로 아스키코드로 변환되서 사용된다.
  • ‘J’ + “ava” = Java
  • ‘1’ + 2 = 49 + 2 = 51
  • true + “” = true
  •  

[2-6] 다음 중 키워드가 아닌 것은?(모두 고르시오)

  1. if
  2. True
  3. NULL
  4. Class
  5. System
  • 풀이
    • True → true
    • NULL → null
    • Class → class

[2-7] 다음 중 변수의 이름으로 사용할 수 있는 것은? (모두 고르시오)

  1. $ystem
  2. channel#5
  3. 7eleven
  4. If
  5. 자바
  6. new
  7. $MAX_NUM
  8. hello@com
  • 풀이
    1. $ystem → 특수문자 $ 사용 가능
    2. channel#5 → 특수문자 # 불가능
    3. 7eleven → 앞에 숫자 불가능
    4. If → 가능
    5. 자바 → 한글 불가능
      • 이클립스에서는 한글 사용 가능!!!
    6. new → 예약어 불가능
    7. $MAX_NUM → 특수문자 $ 사용 가능
    8. hello@com → 특수문자 @ 불가능

[2-8] 참조형 변수(reference type)와 같은 크기의 기본형(primitive type)은? (모두 고르시오)

  1. int
  2. long
  3. short
  4. float
  5. double
  • 풀이
    • 참조형 변수는 64bit JVM을 사용하면 8byte : double
    • 32bit JVM을 사용하면 4byte : int, float

[2-9] 다음 중 형 변환을 생략할 수 있는 것은? (모두 고르시오)

byte b = 10;
char ch = 'A;
int i = 100;
long l = 1000L;

a. b = (byte)i;
b. ch = (char)b;
c. shrot s = (short)ch;
d. float f = (flaot)l;
e. i = (int)ch;
  • 풀이
    1. int(4) → byte(1) 크기가 작기 때문에 불가능
    2. byte(1) → char(2) 음수는 변환 불가능
    3. char(2) → short(2) 크기는 같지만, 음수 변환 불가능
    4. long(8) → float(4) 크기가 작아서 실수 생략 가능하므로 가능
    5. char(2) - int(4) 가능

[2-10] char 타입의 변수에 저장될 수 있는 정수 값의 범위는? (10진수로 적으시오)

  • 풀이
    • 0~65536 = 2^16-1

[2-11] 다음 중 변수를 잘못 초기화 한 것은? (모두 고르시오)

a. byte b = 256;
b. char c = '';
c. char answer = 'no';
d. float f = 3.14
e. double d = 1.4e3f;
  • 풀이
    1. byte : -128~127 불가능
    2. char : 한개의 문자가 아니라 불가능
    3. char : 두개의 문자 불가능
    4. float : 리터럴 뒤에 f가 오지 않아서 불가능

[2-12] 다음 중 main 메서드의 선언부로 알맞은 것은? (모두 고르시오)

a. public static void main(String[] args)
b. public static void main(String args[])
c. public static void main(String[] arv)
d. public void static main(String[] args)
e. static public void main(String[] args)
  • 풀이
    • a, b, c, e

[2-13] 다음 중 타입과 기본값이 잘못 연결된 것은? (모두 고르시오)

a. boolean - false
b. char - '\\u0000' // 16진수 저장
c. float - 0.0
d. int - 0
e. long - 0
f. String - ""
  • 풀이e. 리터럴 뒤에 L 생략되어 있어서 불가능
  • f. String의 기본 값은 null
  • c. 리터럴 뒤에 f 생략되어 있어서 불가능

'프로그래밍 > JAVA' 카테고리의 다른 글

[JAVA] 스택 프레임(Stack Frame)  (0) 2022.06.28
[자바의 정석] 연습문제 2. 연산자  (0) 2022.06.23
[JAVA] 자바 메모리 구조 - Heap, Stack, JVM, GC  (0) 2022.06.23
Ch06. 클래스  (0) 2022.01.02
Ch05. 참조 타입  (0) 2022.01.01

Arrays.sort()

- 배열을 정렬할 때 사용한다.

- DualPivotQuicksort 사용

- 평균 O(nlogn)

- 최악 O(n^2)

 

Collections.sort()

- 리스트를 정렬할 때 사용한다.

- Timesort 사용 : 삽입 정렬 + 합병 정렬

- 평균 O(nlogn)

- 최악 O(nlogn)


1차원 배열 정렬

 

문자열 배열

- 오름차순 정렬

Arrays.sort(arr);
Collections.sort(list);

 

- 내림차순 정렬 : 정렬 후에 반대로 뒤집어 준다.

Arrays.sort(arr, Comparator.reverseOrder());
Collections.sort(list, Collections.reverseOrder());

정수형 배열

Object이 아닌 primitive타입 자료형 이기 때문에 Comparator를 사용해 정렬 불가능
- 오름차순 정렬 -> 뒤집기

 

// 오름차순 정렬
Arrays.sort(arr); 

// 내림차순 정렬
Arrays.sort(arr); // 오름차순 정렬 후
for(int i=0; i<arr.length/2; i++){ // 순서를 뒤집어준다.
    int temp = arr[i];
    arr[i] = arr[arr.length-i-1];
    arr[arr.length-i-1] = temp;
}

 

- 리스트 : Collections.sort() 사용

Collections.sort(list);
Collections.sort(list, Collections.reverseOrder());

 


2차원 배열

// 첫번째 원소 오름차순
Arrays.sort(arr, (o1, o2)->{
    return o1[0]-o2[0];
});

// 첫번째 원소 내림차순
Arrays.sort(arr, (o2, o1)->{
    return o1[0]-o2[0];
});

// 두번째 원소 오름차순
Arrays.sort(arr, (o1, o2)->{
    return o1[1]-o2[1];
});

// 두번째 원소 내림차순
Arrays.sort(arr, (o2, o1)->{
    return o1[1]-o2[1];
});

CompareTo - 정렬에 조건 넣기

class Point implements Comparable<Point>{
    public int x, y;
    Point(int x, int y){
        this.x=x;
        this.y=y;
    }
    @Override
    public int compareTo(Point o){
        if(this.x==o.x){ // x 값이 같을 경우
            return this.y-o.y;
        } else {
            return this.x - o.x;
        }
    }
}

 

CompareTo - 씨름선수

키와 몸무게 모두 높은 지원자가 존재하면 해당 지원자는 탈락

키를 먼저 내림차순으로 정렬해주고 몸무게를 비교한다.

class Body implements Comparable<Body>{
    public int h, w;
    Body(int h, int w){
        this.h = h;
        this.w = w;
    }
    @Override
    public int compareTo(Body o){ // h 내림차순
        return o.h-this.h;
    }
}
public class Solution {
    public static int solution(ArrayList<Body> arr, int n){
        int answer = 0;

        Collections.sort(arr); // 내림차순
        int max = Integer.MIN_VALUE;
        for(Body ob : arr){
            if(ob.w>max){
                max = ob.w;
                answer++;
            }
        }

        return answer;
    }
    public static void main(String[] args) {
        Solution T = new Solution();
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        ArrayList<Body> arr = new ArrayList<>();
        for(int i=0; i<n; i++){
            int height = sc.nextInt();
            int weight = sc.nextInt();
            arr.add(new Body(height, weight));
        }
        System.out.println(T.solution(arr, n));
    }
}

 

- 1개의 회의실에서 n개의 회의를 할 때

- 시간이 겹치지 않게 최대 수의 회의 찾기

- 시작 시간과 끝나는 시간이 주어진다.

- 끝나는 시간을 오름차순 해준다.

- 끝나는 시간이 같으면 시간순으로 오름차순한다.

class Time implements Comparable<Time> {
    public int s, e; // 시작시간, 끝나는시간
    Time(int s, int e){
        this.s = s;
        this.e = e;
    }
    @Override
    public int compareTo(Time o){
        if(this.e==o.e){ // 끝나는시간이 같으면 시간순으로 오름차순
            return this.s-o.s; // 오름차순
        } else {
            return this.e-o.e;
        }
    }
}
public class Solution {
    public int solution(ArrayList<Time> arr, int n){
        int count=0;

        Collections.sort(arr);
        int et = 0;
        for(Time ob : arr){
            if(ob.s>=et){
                count++;
                et = ob.e;
            }
        }
        return count;
    }

    public static void main(String[] args) {
        Solution T = new Solution();
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        ArrayList<Time> arr = new ArrayList<>();
        for(int i=0; i<n; i++){
            int meet = sc.nextInt();
            int room = sc.nextInt();
            arr.add(new Time(meet, room));
        }
        System.out.println(T.solution(arr, n));
    }
}

- next(), nextLine()은 둘 다 Scanner 클래스의 method

 

공통점

- 둘 다 문자열로 반환 시켜준다.

 

 

차이점

- next() : 공백(space) 전까지 입력받은 문자열을 반환한다.

- nextLine() : Enter를 치기 전까지의 모든 문자열을 반환한다.

자바 실행 과정

- 프로그램 실행

- 자바 컴파일러 javac 에서 소스코드 .java 를 읽어서 바이트 코드 .class 로 변환한다.

- class loader로 class파일을 JVM으로 로딩

- class 파일들을 Execution engine으로 해석

- 해석된 바이트 코드를 Runtime Data areas에 배치되어 수행

 

JVM 

- java application을 class loader를 통해 읽어서 자바 API와 함께 실행한다.

- JAVA와 OS사이의 중개자 역할

- 자바 byte code를 실행할 수 있는 주체

- JAVA가 다른 언어에 비해 OS에 영향을 받지 않고 사용 가능하도록 해주는 장점이 있다.

- 다른 언어는 malloc 같은 메모리 할당을 하고 해제를 해줘야 하지만 자바는 GC를 이용해서 메모리 관리를 대신 해준다.

- 스택 기반의 가상머신(정적)

 

GC

- 동적으로 할당된 메모리 영역에서 사용하지 않는 영역을 GC가 할당 해제한다.

 

Stack

- 정적 메모리 할당 영역

- Primitive 타입 

- 메모리가 thread당 하나씩 할당

- 다른 thread끼리 stack 영역 접근 불가능 

 

Heap

- 동적 메모리 할당 영역

- Object 타입

- heap 영역의 Object를 가리키는 참조 변수가 Stack에 할당

- stack과 다르게 thread가 여러개 있어도, heap은 1개의 영역만 존재

 

STACK HEAP
빠른 접근 속도 느린 접근 속도
정적 메모리 할당 동적 메모리 할당
메모리 크기 제한 (OS에 영향) 메모리 크기 제한 X
Primitive type Object type
문제점 memory shortage 문제점 memory fragmentation
  ralloc(), new
선형적 계층적 구조

 

'프로그래밍 > JAVA' 카테고리의 다른 글

[자바의 정석] 연습문제 2. 연산자  (0) 2022.06.23
[자바의 정석] 연습문제 1.변수와 타입  (0) 2022.06.23
Ch06. 클래스  (0) 2022.01.02
Ch05. 참조 타입  (0) 2022.01.01
Ch04. 조건문과 반복문  (0) 2022.01.01

+ Recent posts