KB IT’s Your Life 4기 - Java 알고리즘 12일차


swea1233

package s1233;

import java.util.*;
import java.io.*;

public class Solution {
    
    static class Node{
        int value; // 노드 값
        char opr; // 노드 연산자
        int left,right; // 자식 노드 번호
        
        // 생성자 오버라이딩 2개 (연산자 있는 경우 없는 경우)
        public Node(int value, char opr, int left, int right) {
            super();
            // value와 opr은 서로 베타적이다. 공존하지 못함!
            this.value = value;
            this.opr = opr;
            this.left = left;
            this.right = right;
        }
        public Node(int value) {
            super();
            this.value = value;
        }

    }
    
    static int N; // 노드 개수
    static Node[] nodes;
    

    private static int calc(Node node) {
        // 연산자 추출
        char opr = node.opr;        
        if(opr == '-') {
            return calc(nodes[node.left]) - calc(nodes[node.right]);
        }
        else if(opr == '+') {
            return calc(nodes[node.left]) + calc(nodes[node.right]);
            }
        else if(opr == '/') {
            return calc(nodes[node.left]) / calc(nodes[node.right]);
        }
        else if(opr == '*') {
            return calc(nodes[node.left]) * calc(nodes[node.right]);
        }
        else {
            return node.value;
        }
    }
    
    
    public static void main(String[] args) throws IOException {
        
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        
        
        for(int i=1;i<=10;i++) {
            int ans=0;
            StringTokenizer st = new StringTokenizer(br.readLine());
            int N=Integer.parseInt(st.nextToken());
            nodes = new Node[N+1];
            for(int j=1;j<=N;j++) {
                // st에는 현재 [정점번호, 연산자, 왼쪽 자식 번호, 오른쪽 자식 번호] 혹은 [정점번호, 숫자]
                st = new StringTokenizer(br.readLine());
                // 입력 토큰 개수 판별
                // 연산자인 경우
                if(st.countTokens()==4) {
                    // 정점 번호는 제거하기
                    st.nextToken();
                    
                    char c = st.nextToken().charAt(0);
                    int left_v = Integer.parseInt(st.nextToken());
                    int right_v = Integer.parseInt(st.nextToken());
                    
                    nodes[j]= new Node(0,c,left_v,right_v);
                }
                // 값인 경우
                else {
                    // 정점 번호는 제거하기
                    st.nextToken();
                    String tk = st.nextToken();
                    if(Character.isDigit(tk.charAt(0))) {
                        nodes[j]= new Node(Integer.parseInt(tk));
                    }else {
                        nodes[j]= new Node(0,tk.charAt(0),0,0);
                    }
                }
            }
            //연산식체크
            ans = 1;
            for (int j = 1; j <= N; j++) {
                Node nd = nodes[j];
                if(nd.opr == '\u0000') {//숫자노드이면
                    if(nd.left != 0 || nd.right != 0) {
                        ans = 0;
                        break;
                    }
                }else {//연산자노드
                    if(nd.left == 0||nd.right == 0) {//
                        ans = 0;
                        break;
                    }
                }
            }
            System.out.println("#"+i+" "+ans);
        }
    }

}

그리디 알고리즘

  • 동전 개수의 최솟값 구하기
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class 동전개수 {
	static int N; // 동전 수
	static int total; // 목표 금액
	static int[] array; // 동전의 종류
	static int count; // 사용할 동전의 최솟값

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		total = Integer.parseInt(st.nextToken());

		array = new int[N];
		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			array[i] = Integer.parseInt(st.nextToken());

		}

		for (int i = N - 1; i >= 0; i--) {
			if (array[i] <= total) {
				count += total / array[i];
				total %= array[i];
			}
		}

		System.out.println(count);
	}
}

Anomymous Class

package 리뷰;

public class AnonymousExam {

	public static void main(String[] args) {
		// 일회용 임시 자식 클래스를 만드는 법
		A a = new A() {
			int j = 100;

			public void p() { // 이게 없으면, a.p()는 "A"가 출력된다.
				System.out.println("B" + j); // anonymous class의 경우, j는 간접적으로만 호출 가능
			}
		}; // 중괄호는 선언부의 역할이다. A를 상속한 이름 없는 클래스

		a.p();
//		a.j; //이렇게는 부를 수 없음. 간접적으로만 호출이 가능함. 

		System.out.println(a.getClass().getName()); // 리뷰.AnonymousExam$1 > 클래스 이름을 추출하는 함수

		MySwim mySwim = new MySwim() { 
			@Override
			public void swimming() {
				System.out.println("자유형 수영");
			}
		}; // MySwim은 인터페이스고 인터페이스는 new를 못한다. 인터페이스를 구현한 클래스를 선언하면, 오버라이딩이 꼭 필요.
		
		mySwim.swimming(); //자유형 수영
		System.out.println(mySwim.getClass().getName()); //리뷰.AnonymousExam$2 > anomy형태로 만들면 이름을 따로 만들 필요가 없어서 좋다. $1, $2 저절로 지어줌. 
	}
}

class A {
	public void p() {
		System.out.println("A");
	}
}

interface MySwim {
	void swimming();
}

class MySwimImpl implements MySwim {
	@Override
	public void swimming() {

	}
}

b1931

image

package b1931;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	static int N; // 회의의 수
	static int[][] array; // 회의의 시작시간과 끝나는 시간
	static int end; // 끝나는 시간
	static int count; // 배정 회의실 수

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());

		array = new int[N][2];
		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			array[i][0] = Integer.parseInt(st.nextToken()); // 회의 시작하는 시간
			array[i][1] = Integer.parseInt(st.nextToken()); // 회의 끝나는 시간
		}

		 Arrays.sort(array, (o1, o2) -> o1[1] == o2[1] ? o1[0] - o2[0] : o1[1] - o2[1]);// 정렬함.

		for (int i = 0; i < N; i++) {
			if (end <= array[i][0]) {
				end = array[i][1];
				count++;
			}
		}
		System.out.println(count);
	}

}

분할정복 알고리즘

  • 문제를 분할하여 작은 것부터 해결하여 결과적으로 전체적인 해결책을 얻는다.
  • 코드가 직관적이고 병렬적으로 문제를 해결할 수 있다.
  1. 병합 정렬
    하나의 리스트를 두 개의 균등한 크기로 분할하고 분할된 부분 리스트를 정렬한 다음, 두 개의 정렬된 부분 리스트를 합하여 전체가 정렬된 리스트가 되게 하는 방법이다.
  2. 퀵 정렬
    기준 값을 두고 배열을 분할하여 각 부분 배열에 퀵 정렬을 순환적으로 적용하는 방식이다.
  3. 이진 탐색
    정렬된 데이터를 탐색하는 것이다. (전제조건: 정렬)

백트래킹

  • 미로의 탐색처럼 하나의 갈래길을 선택해서 따라가다 막히면 다음 갈래 길을 선택해서 따라가고 다시 벽이 나오면 갈래길까지 되돌아와서 다른 갈래 길을 선택해서 출구를 찾는 방법

  • swea 2806