BFS

프로그래머스 레벨2의 단어 변환 문제이다.

이 문제는 가장 짧은 변환 과정을 찾아야하고 bfs 는 최단거리를 보장해주는 알고리즘이므로 bfs 를 사용해야한다.

좀 더 공부해봐야 알겠지만 dfs 는 최단 거리가 보장이 안될 수도 있지 않을까?

bfs 문제를 많이 풀어보지는 않아서 정확히는 모르겠지만 전에 푼 문제처럼 Queue 를 이용한다.

 

풀이

  1. 너비 우선 탐색 알고리즘을 이용하여 탐색한다.
  2. 큐에서 idx, move 의 초기값(0, 0)을 꺼내서 visited 에 방문 여부 겸 이동 수를 기록
  3. 탐색 조건에 의해 변환할 수 없는 경우의 수는 걸러지고 남은 경우들은 각자의 최선의 선택으로 탐색
  4. 탐색 후  다음 좌표를 큐에 저장하고 다음 좌표의 방문 여부 겸 이동 수를  visited 에 기록
  5. 각자의 최선의 선택으로 탐색한 경우만 남았으므로 최단 변환 과정은 bfs의 값을 인덱스로 하는 visited 의 값
  6. 큐가 비어서 탐색을 진행할 수 없는 경우 bfs 메서드는 0을 반환
  7. 탐색 종료 후 bfs 의 결과 값을 인덱스로 하는 visited 의 값을 반환(0 이면 변환 불가라는 뜻이므로 0)

최종 코드

import java.util.*;
class Solution {
    // 너비 우선 탐색
    public int bfs(String[] new_words, int[] visited, String target) {
        Queue<int[]> que = new LinkedList<>();
        // 초기값 (idx, move) = (0, 0)
        que.add(new int[2]);
        
        // que 에서 idx 와 move 를 꺼내서 사용하며
        // que 가 비었다는건 words 를 모두 방문했다는 뜻이므로 변환 불가라는 뜻
        while(!que.isEmpty()) {
            int[] now = que.poll();
            int idx = now[0];
            int move = now[1];
            
            // 탐색 조건
            // 1. 방문하지 않은 words
            // 2. 바뀐 글자가 1개
            for (int i = 1; i < new_words.length; i++) {
                int diff = 0;
                // 바뀐 글자가 1개 뿐인지 체크
                for (int j = 0; j < new_words[i].length(); j++) {
                    if (new_words[idx].charAt(j) != new_words[i].charAt(j)){
                        diff += 1;
                    }
                }
                if (visited[i] == 0 && diff == 1) {
                	// 조건에 맞을 경우 이동수 +1
                    // visitied[i] 에 이동수 기록
                    move += 1;
                    visited[i] = visited[idx] +1;
                    // target 으로 변환 시 해당 visited의 인덱스 i 반환
                    if (new_words[i].equals(target)) {
                        return i;
                    }
                    que.add(new int[]{i, move});
                }
            }
        }
        return 0;
    }
    public int solution(String begin, String target, String[] words) {
        String[] new_words = new String[words.length +1];
        new_words[0] = begin;
        for (int i = 0; i < words.length; i++) {
            new_words[i +1] = words[i];
        }
        int[] visited = new int[new_words.length];
        int result = bfs(new_words, visited, target);
        
        // result = 도착점의 visited 인덱스
        // result 가 0 이면 변환 불가라는 의미
        // result 가 0 이 아니면 visited[result] 가 이동수
        return result == 0 ? 0 : visited[result] ;
    }
}

'알고리즘 > DFS 및 BFS' 카테고리의 다른 글

[알고리즘] BFS 입문(JAVA)  (0) 2023.10.22
[알고리즘] DFS 입문(JAVA)  (0) 2023.10.15

BFS

프로그래머스 게임 맵 최단거리 문제를 통해 처음 bfs 를 접해보았다. 

bfs 가 무엇인가 맛보고 이해하기에 좋은 문제인것 같다.

dfs 로 풀어보려고 안간 힘을 써봤지만 실패했다. 

최단거리 문제는 대표적인 bfs 문제라고 하며, Queue 를 이용한다.

 


풀이

  1. 너비 우선 탐색 알고리즘을 이용하여 탐색
  2. queue 에서 시작 좌표 값(0, 0)을 꺼내서 visited 에 방문 여부 겸 이동 수를 기록 후 사방탐색 시작
  3. 사방탐색 조건에 의해 사방이 막혔거나 방문한 길 밖에 없는 경우의 수는 걸러지고 남은 경우들은 각자의 최선의 선택으로 탐색
  4. 사방탐색 후 다음 좌표를 queue 에 저장하고 다음 좌표의 방문 여부 겸 이동 수를  visited 에 기록
  5. 각자의 최선의 선택으로 탐색한 경우만 남았으므로 가장 먼저 queue 가 비어서 탐색을 진행할 수 없는 경우가 최단거리
  6. 탐색 종료 후 도착점 좌표에 해당하는 visited 의 값을 반환(0 이면 방문한 적이 없다는 뜻이므로 -1)

최종 코드

import java.util.*;
class Solution {
    int n = 0;
    int m = 0;
    // 사방탐색용 dx, dy
    int[] dx = {1, 0, -1, 0};
    int[] dy = {0, 1, 0, -1};

	// 너비 우선 탐색
    public void bfs(int[][] maps, int[][] visited, int x, int y) {
    	// 방문 여부 겸 이동 수를 해당 시작 좌표에 기록
        visited[y][x] = 1;
        // queue 초기값 (0, 0)
        Queue<int[]> que = new LinkedList<>();
        que.add(new int[]{y, x});
        
        // queue 에서 현재 좌표를 꺼내서 사용
        // queue 가 비었다는건 더 이상 탐색할 수 없다는 뜻
        while (!que.isEmpty()) {
            int[] now = que.poll();
            y = now[0];
            x = now[1];
			
            // 사방탐색 조건
            // 1. y, x 가 최대값(n, m)을 넘지 않음
            // 2. 방문하지 않은 좌표(visited = 0 인 좌표)
            // 3. 해당하는 maps 의 값이 1인 좌표
            for (int i = 0; i < 4; i++) {
                if (x + dx[i] >= 0 &&
                   x + dx[i] < m &&
                   y + dy[i] >= 0 &&
                   y + dy[i] < n &&
                   visited[y + dy[i]][x + dx[i]] == 0 &&
                   maps[y + dy[i]][x + dx[i]] == 1) {
                    // 탐색 조건에 만족할 시 다음 좌표에 방문 여부 겸 이동 수를 기록
                    visited[y + dy[i]][x + dx[i]] = visited[y][x] + 1;
                    // 다음 좌표를 queue 에 추가
                    que.add(new int[]{y + dy[i], x + dx[i]});
                }
            }
        }
    }

    public int solution(int[][] maps) {
        n = maps.length;
        m = maps[0].length;
        int[][] visited = new int[n][m];
        // 너비 우선 탐색 시작
        // 초기값 (0, 0) 설정
        bfs(maps, visited, 0, 0);

        // 도착점(visited) 의 값을 확인
        // 0 이면 방문한 적이 없으므로 -1
        // 0 이 아니면 visited 의 해당 값이 이동 수를 의미
        return visited[n -1][m -1] == 0 ? -1 : visited[n -1][m -1];
    }
}

'알고리즘 > DFS 및 BFS' 카테고리의 다른 글

[알고리즘] 단어 변환(JAVA)  (0) 2023.11.14
[알고리즘] DFS 입문(JAVA)  (0) 2023.10.15

DFS

프로그래머스 타겟 넘버 문제를 통해 처음 dfs 를 접해보았다. 

dfs 가 무엇인가 맛보고 이해하기에 좋은 문제인것 같다.

 


풀이

  1. 깊이 우선 탐색 알고리즘을 이용하여 탐색을 시작한다.
  2. 처음 노드(depth = 0)부터 마지막 노드(depth = numbers.length)까지 탐색을 수행
  3. 마지막 노드까지 탐색했을 때 타겟 넘버와 결과값이 같으면 정답 카운트 1 증가

깊이 우선 탐색 알고리즘

public void dfs(int[] numbers, int depth, int target, int sum) {
    // numbers : 알고리즘을 수행할 대상 배열
    // depth : 노드의 깊이
    // target : 타겟 넘버
    // sum : 이전 노드까지의 결과값
}

 

최종 코드

public class TargetNumber {
    // 정답 카운트
    // 초기값 0부터 시작
    int answer = 0;

    // 깊이 우선 탐색
    public void dfs(int[] numbers, int depth, int target, int sum) {
        // 마지막 노드까지 탐색했을 때 sum == target 이면 정답 카운트 1 증가
        if (depth == numbers.length) {
            answer += sum == target ? 1 : 0;
        } else {
            // depth 가 0 부터 numbers.length 까지 numbers[depth] 값을 +, - 를 동시에 진행한다.
            dfs(numbers, depth +1, target, sum + numbers[depth]);
            dfs(numbers, depth +1, target, sum - numbers[depth]);
        }
    }

    public int solution(int[] numbers, int target) {
        // 깊이 우선 탐색 시작
        // depth 초기값은 0
        dfs(numbers, 0, target, 0);
        return answer;
    }
}

 


참고자료)

 

[프로그래머스] 타겟 넘버 - Java

https://programmers.co.kr/learn/courses/30/lessons/43165 코딩테스트 연습 - 타겟 넘버 n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로

hyojun.tistory.com

 

'알고리즘 > DFS 및 BFS' 카테고리의 다른 글

[알고리즘] 단어 변환(JAVA)  (0) 2023.11.14
[알고리즘] BFS 입문(JAVA)  (0) 2023.10.22

+ Recent posts