자료구조와 알고리듬 With Java/[프로그래머스] Algorithm

Part 09 Tree

계란💕 2022. 3. 28. 16:09

  - tree는 규칙이 없던 그래프와 다르게 규칙이 있다.

 

1. Bynary tree

  - Bynary tree: child는 두 개만

  - 왼쪽부터 빠짐없이 채우면 => Complete Binary Tree

  - 빈 칸 없이 다 채우면 => Perfect Binary Tree

 

 

2. Tree읽는 방법

  1) DFS

  - In Order Travel: left -> root -> right

  - Pre Order Travle: root -> left -> right

  - Post Order Travel: left -> right -> root

 

  2) BFS

  - Level Order Travel

 

 

3. Heap

  - root에는 항상 최솟값이 있어야한다. => "Min heap'

  - root에는 항상 최댓값이 있어야한다. => "Max heap' 

  - 자바에서 "PriorityQueue"의 형태로 제공

    -> 작은 값부터 poll()  => Min heap

    -> 큰 값부터 poll() => reverseOrder()

  - Binary SearchTree를 이용하는 것은 대소관계를 사용한다는 것을 의미

 

  

  Note) 

  - 값이 set에 존재하는 지 확인할 때 대소관계를 확인한다.

    -> comparable이 필요하다. 

    -> comparable이 있어야 TreeSet이 동작한다.

<hide/>
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;

public class BinarySearchTree {
	public static void main(String[] args){
	
		// sort: O(nlogn), binary : O(logn)
		Queue<Integer> queue = new PriorityQueue<>();		// 최댓값(최솟값) 유지
		// 괄호에 Comparator.reverseOrder()를 넣으면 내림차순
		Random r = new Random();
		
		for(int i = 0; i < 20; ++i) queue.offer(r.nextInt(50)); 
		System.out.println(queue);
		
		List<Integer> sorted = new LinkedList<>();
		while(!queue.isEmpty())  sorted.add(queue.poll());	//heap sort
		System.out.println(sorted);
	}
}

 

 

  Ex) 더 맵게

  - 스코빌 지수를 나타내는 배열과 정수k가 주어진다. 이 때 모든음식의 스코빌 지수를 K이상으로 만들기위해

  - 섞어야하는 최소횟수를 리턴한다.

  - list.remove(0): 0번째 값 꺼내기

  - answer : 섞은 횟수

  - sort를 매번 하지 않도록 min heap을 이용한다.

  - min heap이므로 sort할 필요없다.

<hide/>
import java.util.*;
class Solution {
    public int solution(int[] scoville, int K) {
        
        Queue<Integer> list = new PriorityQueue<>();        // Queue 구조로된 list를 만든다. (자동 오름차순 정렬)
        for(int s : scoville ){ list.add(s); }              // 스코빌의 모든 원소를 list에 복사한다.
        int answer = 0;         // 초기값 0 설정
        
        while(list.size() >= 2 && list.peek() < K){         // LIST의 사이즈가 2보다 크고  PEEK한 값이 K보다 작으면 반복실행
                
            int s1 = list.poll();
            int s2 = list.poll();
            int s3 = s1 + 2 * s2;
            
            list.offer(s3);    // s1, s2를 뽑아내고 새로운 s3을 추가한다. 
            ++answer; 
        }
        
        if( list.peek() < K)    return -1;    // WHILE문 반복한 후에도 PEEK한 값(가장작은값)이 K보다 작다면 -1 반환
        return answer;
    }
}

 

 

  Ex) 가장 먼 노드

  - n개의 노드가 있는 그래프가 있다. 1번 노드에서 가장 멀리 떨어진 노드의 개수를 구한다.

  - 1번 노드로부터 가장 멀리 떨어진 노드의 개수를 반환한다.

<hide/>
import java.util.*;
class Solution{
    
    class Node{
    
        int n;
        int dist;
        boolean visit = false;
        List<Node> links = new LinkedList<>();
        
        Node(int n) {
            this.n = n;
        }
    }
    
    public int solution(int n , int[][] edge){

        List<Node> list = new LinkedList<>();
        
        for(int i = 0 ; i < n; ++i) list.add(new Node(i + 1));
        
        for(int []e: edge){		// 엣지 정보로 각 노드를 서로 연결한다.
            
            Node n1 = list.get(e[0] - 1);	// 1을 빼면 인덱스
            Node n2 = list.get(e[1] - 1);
            
            n1.links.add(n2);        // list 아니고 links!
            n2.links.add(n1);		// 쌍방향으로 연결한다.
        }
        int maxDist = 0;		// 최대길이를 구하기 위해서
        
        // BFS로 푼다.
        Queue<Node> queue = new LinkedList<>();
        
        Node first = list.get(0);   // list의 첫번째 행?? first
        first.visit = true;			// 방문여부 표시
        queue.offer(first);         // Queue에 넣는다
        
        while(!queue.isEmpty()){
            
            Node now = queue.poll();    // Queue에서 pop한 값을 now에 저장
            
            for(Node node: now.links){	// 연결된 모든 노드를 큐에 넣는다.
                if(node.visit) continue;
                node.visit = true;
                node.dist = now.dist + 1;
                queue.offer(node);
                maxDist = Math.max(maxDist, node.dist);	// 최대 거리
            }
        }
        
        int answer = 0;
        for(Node node: list){
            if(node.dist == maxDist) ++answer;		
            // 맥스 디스턴스 거리에 있는 노드를 카운트
        }
        return answer;
    }
}

 

 

  Ex) 순위 - 정확히 순서를 매길 수 있는 선수의 수를 반환

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

 

프로그래머스

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

programmers.co.kr

  - n명의 권투 선수, 대회 참여, 

  ex)  n = 5,  [ [4, 3] ,[ 4, 2 ], [3, 2], [1, 2], [2, 5] ] return = 2;

    -> 4번 선수가 3, 2 번 선수를 이김, 3번이 2번을 이김, 2번이 5번을 이김, 1번이 2번을 이김

  - 경기횟수가 가장 많은 선수들의 순위를 알아낼 수 있다.

  - 노드를 만들고 시작

  - 선수 번호에 따라서 arrayList로 만든다.

<hide/>
import java.util.*;
class Solution {

    class Node{
        int n;
        int win = 0, lose = 0;
        boolean visit = false;
        List<Node> links = new LinkedList<>();
        Node(int n){this.n = n;}		// 선수 번호
    }
    
    public int solution(int n, int[][] results){
 
        List<Node> list = new LinkedList<>();
        for(int i = 0; i < n  ; ++i) list.add(new Node(i + 1)); // 선수 번호 1 ~ n번
    
        for(int [] result : results){
            
            Node winner =  list.get(result[0] - 1);   // 이긴 애들, 인덱스로 꺼내온다.
            Node loser =  list.get(result[1] - 1);  // 진 애들
            winner.links.add(loser);	// 일방향으로만 연결한다. (방향성 있기 때문에)
        }
        
       for( Node winner: list){
        
           for(Node node: list) node.visit = false; // 시작되기 전에 visit을 초기화시킨다.
           Queue<Node> queue = new LinkedList<>();
           
           winner.visit = true ;        // 위너 트루
           queue.offer(winner);	//위너부터 시작
           
           while(!queue.isEmpty()){
               
               Node now = queue.poll();
               for(Node loser : now.links){    
                   if(loser.visit) continue;
                   loser.visit = true;
                   queue.offer(loser);
                   winner.win += 1;		// 승자의 win 카운드 +
                   loser.lose += 1;		// 패자선수의 lose 카운트 + 
               }
           }
       }
        int answer = 0;
        for(Node node: list){
            if(node.win + node.lose == n - 1) ++answer;		// 최대경기횟수: n - 1
        }
        return answer;
    }
}

 

출처: https://programmers.co.kr/learn/courses/13577

'자료구조와 알고리듬 With Java > [프로그래머스] Algorithm' 카테고리의 다른 글

Part 08 Graph (그래프)  (0) 2022.03.24
Part 07 정렬 (Sort)  (0) 2022.03.24
Part 06 선형탐색 (Linear Search)  (0) 2022.03.23
Part 05 Stack과 Queue  (0) 2022.03.23
Part 04 집합 (Set)  (0) 2022.03.22