【搜索】C043_openj_單詞序列(暴力匹配 + bfs)

一、Problem

給出兩個單詞(開始單詞和結束單詞)以及一個詞典。找出從開始單詞轉換到結束單詞,所需要的最短轉換序列。轉換的規則如下:

  1. 每次只能改變一個字母
  2. 轉換過程中出現的單詞(除開始單詞和結束單詞)必須存在於詞典中

例如:

  • 開始單詞爲:hit
    結束單詞爲:cog
    詞典爲:[hot,dot,dog,lot,log,mot]

那麼一種可能的最短變換是: hit -> hot -> dot -> dog -> cog,所以返回的結果是序列的長度5;

注意:

  1. 如果不能找到這種變換,則輸出0;
  2. 詞典中所有單詞長度一樣;
  3. 所有的單詞都由小寫字母構成;
  4. 開始單詞和結束單詞可以不在詞典中。

輸入

共兩行,第一行爲開始單詞和結束單詞(兩個單詞不同),以空格分開。第二行爲若干的單詞(各不相同),以空格分隔開來,表示詞典。單詞長度不超過5,單詞個數不超過30。

輸出

輸出轉換序列的長度。

樣例輸入 
hit cog 
hot dot dog lot log 
樣例輸出 
5

二、Solution

方法一:bfs

  • 這本質是一道圖論問題,想象一下,每個單詞是一個結點,單詞之間的邊的邊權爲 1。
  • 問題轉化爲求從結點 w1 到達 w2 的最短路徑。
  • 如果判斷兩兩單詞的變換是否合法?
    • 暴力匹配即可。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static String w1, w2;
	static Info[] all;
	static int cnt;
	static boolean valid(String s1, String s2) {
		int diff = 0;
		for (int i = 0; i < s1.length(); i++) {
			if (s1.charAt(i) != s2.charAt(i)) 
				diff++;
			if (diff > 1)
				return false;
		}
		return diff == 1;
	}
	static int bfs() {
		Queue<Info> q = new LinkedList<>();
		Info i = new Info();
		i.s = w1; i.d = 1; i.vis = true;
		q.add(i);
		
		while (!q.isEmpty()) {
			Info t = q.poll();
			if (valid(t.s, w2)) {
				return t.d + 1;
			}
			for (int k = 0; k < cnt; k++) {
				if (all[k].vis || !valid(t.s, all[k].s))
					continue;
				Info info = new Info();
				info.s = all[k].s;
				info.vis = true;
				info.d = t.d + 1;
				q.add(info);
			}
		}
		return 0;
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
		w1 = sc.next();
		w2 = sc.next();
		all = new Info[30 + 5];
		for (int i = 0; i < all.length; i++)
			all[i] = new Info();
        while (sc.hasNext()) {
            all[cnt].s = sc.next();
            cnt++;
        }
		int res = bfs();
        System.out.println(res);		
    }
	static class Info {
		String s;
		boolean vis;
		int d;
	} 
}

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(n)O(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章