ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ DFS / BFS ] 개념 및 예제 정리
    Java/코딩테스트 2023. 4. 5. 18:54

    코딩테스트에서 자주 사용되는 완전 탐색 기법 DFS/BFS 정리

    자주 나오기도 하고... 중요하기도 해서 복습겸 정리하는 포스팅!


    DFS 

    🌷특징 및 언제 사용? 

    - 탐색 공간 자체는 크지만 깊이가 유한할 때(공간 복잡도가 작다)

    - 최단 경로가 아니어도 괜찮을 때

    - 재귀함수로 구현 -> 현재 검사하는 상태에서 전이할 수 있는 상태라면 해당 상태로 전이

    - 시작하는 부분에서 한쪽 분기 정하고 최대 깊이까지 탐색 후 다른 분기로 이동, 다시 최대 깊이까지 탐색 ... 

    - 단절점 찾기, 단절선 찾기, 위상정렬, 사이클 찾기 등.. 

     

    🌷기본 코드 구현 시 필요한 것 

    - 방문 여부를 저장할 방문 여부 배열

    - 재귀함수로 구현하거나 스택 활용! 

     

    🌷 로직  

    1. while (스택에 값이 있는 동안)

    2. 방문 여부 검사

    3. state 변수(현재 방문한 변수)에 대한 처리(문제마다 다름)

    4. 다음에 방문해야할 자료에 대해 범위, 방문 여부 등 문제에 따라 조건 검사

    5. 조건에 위배되지 않으면 스택에 push or 재귀 함수 호출

    boolean isVisited[] = new boolean[n];
    Stack<Integer> stack = new Stack<>();
    
    while (!stack.isEmpty()) {
        int state = stack.pop();
        if (isVisited[]) {
        	// continue 또는 리턴 
        }
        isVisted[state] = true;
        for (int next : getNext(state)) {
        	if (!isVisted[next]) {
            	stack.push(next);
            }
        }
    }
    
    // 재귀로 구현한다면 
    static void DFS(int node) {
    	if (visited[node]) {
    		return ;
        } // 이미 방문한 노드인 경우엔 수행 X
        visited[node] = true; // 한 번 지난 노드는 다시 안 지나가게끔
        for (int i : graph[node]) {
        	if (!visited[i]) {
            	DFS(i);
            }
        }
    }

     

     

    🌷프로그래머스 lv3 네트워크

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

     

    프로그래머스

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

    programmers.co.kr

    DFS긴 DFS인데 처음에 구하려는 답을 내가 잘못 생각했다. 문제이해를 잘못했었는데, 제대로 이해해도 못풀어서 해설을 보고 코드를 짰다ㅎ... 

     여기서의 visited는 각 컴퓨터별로 연결된거 모두 탐색해봤는지를 저장하는 배열이다. 이 visited를 계속 DFS함수 매개변수로 넣어주고, 한 컴퓨터당 탐색이 끝나면 answer++해준다. 

    어려운 문젠 아닌거같은데 아직 부족하군...허허 

     

    import java.util.*;
    class Solution {
        public int solution(int n, int[][] computers) {
            boolean[] visited = new boolean[n];
            int answer = 0;
            for (int i = 0; i < n; i++) {
                if (visited[i]) {
                    continue;
                }
                DFS(i, computers, visited);
                answer++;
            }
            return answer;
        }
        
        void DFS(int now, int[][] computers, boolean[] visited) {
            Stack<Integer> stack = new Stack<>(); 
            stack.push(now);
            
            while (!stack.isEmpty()) {
                int temp = stack.pop();
                if (visited[temp]) {
                    continue;
                }
                visited[temp] = true;
                for (int i = 0; i < computers[temp].length; i++) {
                    if (computers[temp][i] == 0) {
                        continue;
                    }
                    if (temp != i) {
                        stack.push(i);
                    }
                }
            }
        }
    }

     


    BFS 

    🌷특징 및 언제 사용? 

    - 초기 상태에서 가까운 상태부터 탐색

    - 최단 거리나 최단 시간 등 목표 상태에서 도달할 수 있는 가장 빠른 경로 탐색 

    - 탐색 공간의 깊이 제약이 없는 편이나 공간복잡도가 크다 

    - 큐를 사용, 큐가 탐색 공간을 나타내고 큐에 다음 탐색할 것들을 추가하는 방식으로 진행 .. 

     

    🌷DFS와 차이점? 

    - 스택 대신 큐를 사용 

    - 큐에 넣어줄 때 방문 처리를 한다는 점

    boolean[] isVisited = new boolean[n];
    Queue<Integer>() queue = new LinkedList<>();
    queue.add(0); //초기 상태 저장
    isVisited[0] = true;
    
    while (!queue.isEmpty()) {
    	int now = queue.poll();
        for (int next : getNextStates(now)) {
        	// 방문 여부 외에 추가할만한 검사 조건들 추가하기 
        	if (isVisted[next]) {
            	continue;
            }
        }
        isVisited[next] = true;
        queue.add(next);
    }
    
     static void BFS(int num) {
            Queue<Integer> queue = new LinkedList<Integer>();
            queue.add(num);
            isVisited[num] = true;
    
            while(!queue.isEmpty()) {
                int now = queue.poll();
                System.out.print(now + " ");
                for (int i : graph[now]) {
                    if (!isVisited[i]) {
                        isVisited[i] = true;
                        queue.add(i);
                    }
                }
            }
        }

     

     

    🌷프로그래머스 level3 단어변환

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

     

    프로그래머스

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

    programmers.co.kr

    🌷로직 

    - 하나의 문자만 다른지 검사(word1 -> word2 바꿀 수 있는지 여부 검사하는 함수)

         -> boolean canChange(String word1, String word2) 

    - 바꿀 수 있는 단어들을 다 큐에 넣어두고 탐색 수행 (BFS)

    - 큐에서 꺼낼 때마다 target과 같은 문자열인지 확인, 맞다면 답 리턴

    - 큐가 다 비었는데도 리턴되지 않았다 => 전환이 불가능하다는 뜻이므로 0 리턴 

    import java.util.*;
    class Solution {
        public int solution(String begin, String target, String[] words) {
            Queue<Word> queue = new LinkedList<>(); 
            boolean[] visited = new boolean[words.length];
            queue.add(new Word(begin, 0));
        
            while (!queue.isEmpty()) {
                Word w = queue.poll();
                if (w.st.equals(target)) {
                    return w.count; // 꺼냈는데 target과 같다면 답 리턴
                }
                for (int i = 0; i < words.length; i++) {
                    if (!visited[i]) {
                        if (canChange(w.st, words[i])) {
                            visited[i] = true;
                            queue.add(new Word(words[i], w.count+1));
                        }
                    }
                }
            }
            return 0; // 다 돌아도 답 안나오는 경우 
        }
        
        public boolean canChange(String word1, String word2) {
            int count = 0;
            char[] first = word1.toCharArray();
            char[] second = word2.toCharArray();
            for (int i = 0; i < word1.length(); i++) {
                if (first[i] != second[i]) {
                    count++;
                }
                if (count > 1) {
                    return false;
                }
            }
            return true;
        }
        
        class Word {
            String st;
            int count;
            public Word(String s, int c) {
                this.st = s;
                this.count = c;
            }
        }
    }

     

    'Java > 코딩테스트' 카테고리의 다른 글

    백준 15686  (0) 2023.04.06
    백준 14503  (0) 2023.04.06
    [DP] 백준 풀이 기록 JAVA (Feat. do it 알고리즘 코딩테스트)  (0) 2023.04.05
    백준 11003(Java)  (0) 2022.08.07
    백준 1940, 1253, 12891(JAVA)  (0) 2022.07.31
Designed by Tistory.