728x90
반응형

단어변환

문제설명

두 개의 단어 begin, target과 단어의 집합 words가 있습니다. 아래와 같은 규칙을 이용하여 begin에서 target으로 변환하는 가장 짧은 변환 과정을 찾으려고 합니다.

  1. 한 번에 한 개의 알파벳만 바꿀 수 있습니다.
  2. words에 있는 단어로만 변환할 수 있습니다.

예를 들어 begin이 "hit", target가 "cog", words가 ["hot","dot","dog","lot","log","cog"]라면 "hit" -> "hot" -> "dot" -> "dog" -> "cog"와 같이 4단계를 거쳐 변환할 수 있습니다.

두 개의 단어 begin, target과 단어의 집합 words가 매개변수로 주어질 때, 최소 몇 단계의 과정을 거쳐 begin을 target으로 변환할 수 있는지 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 각 단어는 알파벳 소문자로만 이루어져 있습니다.
  • 각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
  • words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
  • begin과 target은 같지 않습니다.
  • 변환할 수 없는 경우에는 0를 return 합니다.

입출력 예

  • 각 단어는 알파벳 소문자로만 이루어져 있습니다.
  • 각 단어의 길이는 3 이상 10 이하이며 모든 단어의 길이는 같습니다.
  • words에는 3개 이상 50개 이하의 단어가 있으며 중복되는 단어는 없습니다.
  • begin과 target은 같지 않습니다.
  • 변환할 수 없는 경우에는 0를 return 합니다.

입출력 예 설명

예제 #1
문제에 나온 예와 같습니다.

예제 #2
target인 "cog"는 words 안에 없기 때문에 변환할 수 없습니다.

 

풀이

해당문제는 전형적인 BFS문제입니다. BFS 문제의 경우 "최단","최소"를 찾는 경우가 많습니다. 문제에서도 단어가 변환되는 최소의 단계를 구하는 것이기 때문에 BFS 알고리즘을 사용하여 풀면 되겠습니다.

BFS 알고리즘의 설명은 아래를 참고하여 주십시오.

https://tylee82.tistory.com/329?category=940295 
 

[JAVA] 너비 우선 탐색 BFS(Breadth-first search)

동작방식 하나로 시작 정점을 방문한 후 시작 정점에 인접한 모든 정점들을 우선 방문하는 방법입니다. 더 이상 방문하지 않은 정점이 없을 때까지 방문하지 않은 모든 정점들에 대해서도 너비

tylee82.tistory.com

 

이외에도 isCanChange 함수에서 문자1(str1)과 문자2(str2)를 비교해 한개의 알파벳만 변환을 했는지 검사를 하는 함수가 있습니다. 저는 str1과 str2의 문자 하나하나를 char로 변환하여 빼기를 하여 절대값을 해주었습니다. 이렇게하면 문자의 차이가 나오는데 같은 문자라면 '0'이 나타날 것 입니다. '0'이 아닌 위치는 알파벳이 변환이 되었으니 이후에 나오는 알파벳은 모두 '0'이 나와야 한다는 가정으로 새우고 함수를 만들었습니다.

import java.util.*;

class Solution {
    
    class Word{
        String str;
        int count;
        
        Word(String str, int count){
            this.str = str;
            this.count = count;
        }
    }
    
    
    public boolean isCanChange(String str1, String str2){
    	//한 번에 한 개의 알파벳만 바꿀 수 있습니다.
        boolean ret = false;
        
        int len = str1.length();
        
        boolean isOneChange = false;
        int diffWord = 0;
        for(int i=0; i<len; i++){
            diffWord = Math.abs(str1.charAt(i) - str2.charAt(i));
            
            if(!isOneChange && diffWord != 0) {
            	isOneChange = true;
            	ret = true;
            }else if(isOneChange && diffWord != 0){
            	ret = false;
            	break;
            }
        }
        
        return ret;
    }

    
    public int solution(String begin, String target, String[] words) {
        int answer = 0;
        
        int[] used = new int[words.length]; // 사용한것은 1, 안한것은 0
        Queue<Word> q = new LinkedList<Word>();
        q.add(new Word(begin, 0)); //시작점
        
        while(!q.isEmpty()){
            
            Word cur = q.poll();
            
            if(cur.str.equals(target)){
                // terget과 문자가 동일하면 cur.count 반환하고 멈춤
                answer = cur.count;
                break;
            }
            
            for(int i=0; i<words.length; i++){
                if(isCanChange(cur.str, words[i] ) && used[i] == 0) //변환이 가능하고 사용하지 않았으면 q에 넣어준다.
                {
                    used[i] = 1; // 방문 표시
                    q.add(new Word(words[i] , cur.count+1));
                }
            }
            
        }
        
        
        return answer;
    }
}

결과

 

728x90
반응형
728x90
반응형

네트워크 문제

문제설명

네트워크란 컴퓨터 상호 간에 정보를 교환할 수 있도록 연결된 형태를 의미합니다. 예를 들어, 컴퓨터 A와 컴퓨터 B가 직접적으로 연결되어있고, 컴퓨터 B와 컴퓨터 C가 직접적으로 연결되어 있을 때 컴퓨터 A와 컴퓨터 C도 간접적으로 연결되어 정보를 교환할 수 있습니다. 따라서 컴퓨터 A, B, C는 모두 같은 네트워크 상에 있다고 할 수 있습니다.

컴퓨터의 개수 n, 연결에 대한 정보가 담긴 2차원 배열 computers가 매개변수로 주어질 때, 네트워크의 개수를 return 하도록 solution 함수를 작성하시오.

 

제한사항

  • 컴퓨터의 개수 n은 1 이상 200 이하인 자연수입니다.
  • 각 컴퓨터는 0부터 n-1인 정수로 표현합니다.
  • i번 컴퓨터와 j번 컴퓨터가 연결되어 있으면 computers[i][j]를 1로 표현합니다.
  • computer[i][i]는 항상 1입니다.

입출력 예

입출력 예 설명

예제 #1

아래와 같이 2개의 네트워크가 있습니다.

예제 #2

아래와 같이 1개의 네트워크가 있습니다.

 

풀이방법

프로그래머스에서 제공하는 코딩테스트 연습문제 Level 3 의 문제입니다. 일단 네트워크 문제는 분류가 깊이/너비 우선 탐색(DFS/BFS)로 분류가 되어있습니다. 하지만 저는 이 문제를 Union-Find로 풀어보려 합니다. 왜냐하면 연결된 그룹을 찾는 문제이고 주어진 입력값으로 각 컴퓨터를 연결하여 집합으로 묶어주면 그 집합의 개수만 카운트 해주면 될 것 같아서 저는 Union-Find 로 풀어보았습니다.

https://tylee82.tistory.com/291
 

[Java] Union-Find (유니온-파인드) 알고리즘

Union-Find는 자료 구조입니다. 그래프 알고리즘에서 사용하는 대표 알고리즘입니다. 여러개의 노드가 존재할 때 두 개의 노드를 선택해서, 현재 이 두 노드가 서로 같은 그래프에 속하는지 판별하

tylee82.tistory.com

import java.util.*;

class Solution {
    
    static int[] uArr;
    
    public int solution(int n, int[][] computers) {
        int answer = 0;
        uArr = new int[n+4];
        
        for(int i=0; i<n ; i++){
            for(int j=0; j<n ; j++){
                if(i==j) continue; // computer[i][i]는 항상 1 이기때문에 필요없음
                if(computers[i][j]==1){ // 연결된 컴퓨터끼리 Union 해줌
                    setUnion(i, j); 
                }
            }
        }
        
        // System.out.println("0:"+getFind(0));
        // System.out.println("1:"+getFind(1));
        // System.out.println("2:"+getFind(2));
        
        // 집합의 개수를 카운트하기위한 변수
        ArrayList<Integer> alist = new ArrayList<Integer>();
        for(int i=0; i<n ; i++){
            if( alist.contains(getFind(i)) ){
                // getFind로 찾은 집합의 우두머리가 이미 alist 변수에 있으면 pass
                continue;  
            } 
            else {
                // alist 에 없으면 추가
                alist.add(getFind(i));
            }
        }
        
        // 집합은 alist 의 size 이다.
        answer = alist.size();
        
        return answer;
    }
    
    public void setUnion(int i, int j){
        int a = getFind(i);
        int b = getFind(j);
        if(a == b) return;
        uArr[a] = b;
    }
    
    public int getFind(int tar){
        if(uArr[tar] == 0) return tar;
        int ret = getFind(uArr[tar]);
        uArr[tar] = ret;
        return ret;
    }
}

 

결과

728x90
반응형
728x90
반응형

 

동작방식

하나로 시작 정점을 방문한 후 시작 정점에 인접한 모든 정점들을 우선 방문하는 방법입니다. 더 이상 방문하지 않은 정점이 없을 때까지 방문하지 않은 모든 정점들에 대해서도 너비 우선 검색을 적용합니다.

 

장점

  • 출발노드에서 목표노드까지의 최단 길이 경로를 보장한다.

단점

  • 경로가 매우 길 경우에는 탐색 가지가 급격히 증가함에 따라 보다 많은 기억 공간을 필요로 하게 된다.
  • 해가 존재하지 않는다면 유한 그래프(finite graph)의 경우에는 모든 그래프를 탐색한 후에 실패로 끝난다.
  • 무한 그래프(infinite graph)의 경우에는 결코 해를 찾지도 못하고, 끝내지도 못한다.

 

시간복잡도

DFS 시간복잡도와 동일함

- 인접리스트 : O(|V| + |E|) (정점의 개수:V, 간선의 개수:E)

- 인접행렬 : O(V^2) (정점의 개수:V)

참고사이트

https://ko.wikipedia.org/wiki/%EB%84%88%EB%B9%84_%EC%9A%B0%EC%84%A0_%ED%83%90%EC%83%89
 

너비 우선 탐색 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

기본코드

입력값

7
8
1 2
1 3
2 4
2 5
3 7
4 6
5 6
6 7  

코드

package study.graph;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class BFS {

	static int[] used;
	static int[][] map;
	static int N, M;
	public static void main(String[] args) throws IOException{
		
		System.setIn(new FileInputStream("input\\bfs.txt"));
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		N = Integer.parseInt(br.readLine());
		M = Integer.parseInt(br.readLine());
		
		used = new int[N+1];
		map = new int[N+1][N+1]; // 인접행렬을 이용하기 위한 2차원 배열 생성
		
		StringTokenizer st = null;
		for(int m=0; m<M; m++) {
			st = new  StringTokenizer(br.readLine());
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			
			map[a][b] = 1;
			map[b][a] = 1; //양방향이기 때문에..
		}
		
		System.out.print("그래프 BFS 방문 순서 : " );
		bfs(1);
		
		bw.close();
		br.close();
	}
	
	static void bfs(int st) {
		Queue<Integer> q = new LinkedList<Integer>();
		q.add(st);
		used[st] = 1; //방문표시
		
		while(!q.isEmpty()) {
			int x = q.poll();
			System.out.print( x + " ");
			
			for(int i=1; i<=N; i++) {
				if(map[x][i] == 1 && used[i] == 0) {
					// 다음 노드와 연결되어 있고 아직 방문하지 않았으면 q에 넣음
					q.add(i);
					used[i] = 1;//방문 표시
				}
			}
		}
	}
}
728x90
반응형

+ Recent posts