---
# System prepended metadata

title: '**Leetcode筆記(Word Ladder)**'
tags: [graph, hard, leetcode]

---

# **Leetcode筆記(Word Ladder)**


:::info
:information_source: 題目 : Word Ladder, 類型 : graph , 等級 : hard
日期 : 2023/05/18，2023/07/14，2024/04/04
:::


### 嘗試
2023/07/14
關鍵在於剛開始要統計長得很像的字們，把其中的空格加上"*" ，創造一個dict，並且把那些有加星號的組合當作key，那些擁有這種組合的字變成value
pop出一個字的時候，找那個字的各種星星組合，去和dict對應
```python
class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        record = defaultdict(list)
        wordList.append(beginWord)
        for w in wordList:
            for i in range(len(beginWord)):
                rest = w[ : i] + "*" + w[i + 1 :]
                record[rest].append(w)
        
        q = deque([beginWord])
        visited = set(beginWord)
        step = 1

        while q:
            length = len(q)
            for _ in range(length):
                w = q.popleft()

                if w == endWord: # 當遇到結尾字
                    return step

                for i in range(len(w)): # 找這個目標字的組成
                    rest = w[ : i] + "*" + w[i + 1 : ]
                    for other in record[rest]:
                        if other not in visited:
                            q.append(other)
                            visited.add(other)
            step += 1

        return 0
```
2024/04/04
在Python中，deque是一個雙端佇列的資料結構，它接受一個可迭代物件作為參數來初始化佇列。
```python
class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        record = collections.defaultdict(list)

        for word in wordList:
            for i in range(len(word)):
                w = word[0 : i] + "*" + word[i + 1:]
                record[w].append(word)
        
        step = 1
        q = deque([beginWord])
        visited = set([beginWord]) # 為了避免進入無限迴圈
        while q:
            l = len(q)
            for _ in range(l):
                w = q.popleft()
                if w == endWord:
                    return step
                for i in range(len(w)):
                    new_w = w[0:i] + "*" + w[i + 1:]
                    for next_w in record[new_w]:
                        if next_w not in visited:
                            q.append(next_w)
                            visited.add(next_w)
            step += 1
        
        return 0
```

---
### **優化**

在給定的程式碼中，`ladderLength` 方法的時間和空間複雜度如下：

1. 建立相似詞字典 (`similar`)：
   - 迭代 `wordList` 列表所需時間為 O(|wordList|)，其中 |wordList| 代表單詞列表的長度。
   - 對於每個單詞，透過迭代單詞的每個字元來建立模式 (`pattern`)，所需時間為 O(L)，其中 L 代表單詞的平均長度。
   - 因此，建立相似詞字典的時間複雜度為 O(|wordList| * L)。

2. BFS 遍歷：
   - 在每一層的 BFS 中，需要處理佇列中的每個單詞，所需時間為 O(|q|)，其中 |q| 代表佇列中的單詞數量。
   - 對於每個單詞，透過迭代其每個字元來建立模式，所需時間為 O(L)。
   - 在相似詞字典中查找相同模式的相似單詞，所需時間為 O(|similar[pattern]|)，其中 |similar[pattern]| 代表具有相同模式的相似單詞的數量。
   - 將未訪問過的相似單詞添加到佇列和訪問集合中，所需時間為 O(1)。
   - 在最壞的情況下，每個單詞都會被處理一次，因此 BFS 的時間複雜度為 O(|q| * |wordList| * L)。


綜上所述，`ladderLength` 方法的總時間複雜度為 O(|wordList| * L)，其中 |wordList| 代表單詞列表的長度，L 代表單詞的平均長度。

空間複雜度方面：
- 相似詞字典 (`similar`) 的空間複雜度為 O(|wordList| * L)。
- 佇列 (`q`) 和訪問集合 (visited) 的空間複雜度為 O(|wordList|)。


```python
class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        similar = collections.defaultdict(list)
        wordList.append(beginWord) # beginWord也要在pattern內

        # similar[重複的pattern] = 有哪些word
        for word in wordList:
            for i in range(len(word)):
                # "*ot" / "h*t" / "ho*"
                pattern = word[:i] + "*" + word[i + 1:]
                similar[pattern].append(word)
        
        # 初始化
        q = deque([beginWord])
        visited = set([beginWord])
        res = 1 # 統計bfs次數

        # bfs
        while q:
            for k in range(len(q)): # 這行是為了統計bfs
                word = q.popleft()

                # 符合條件
                if word == endWord:
                    return res

                for i in range(len(word)):
                    pattern = word[:i] + "*" + word[i + 1:]
                    # 去找pattern相同(只差一個字的)
                    for simi_word in similar[pattern]:
                        # 防止重複
                        if simi_word not in visited: 
                            q.append(simi_word)
                            visited.add(simi_word)
            res += 1
        
        return 0
```
---


**:warning: 錯誤語法** 
:::warning

:::


**:thumbsup:學習** 
:::success

:::

**思路**
![](https://hackmd.io/_uploads/Skf7TN7r2.png)

![](https://hackmd.io/_uploads/Hkv-pEmr3.png)


**講解連結**
https://www.youtube.com/watch?v=h9iTnkgv05E&ab_channel=NeetCode
Provided by. NeetCode

###### tags: `graph` `hard` `leetcode`